Annotation of embedaddon/sqlite3/src/test_rtree.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: ** 2010 August 28
                      3: **
                      4: ** The author disclaims copyright to this source code.  In place of
                      5: ** a legal notice, here is a blessing:
                      6: **
                      7: **    May you do good and not evil.
                      8: **    May you find forgiveness for yourself and forgive others.
                      9: **    May you share freely, never taking more than you give.
                     10: **
                     11: *************************************************************************
                     12: ** Code for testing all sorts of SQLite interfaces. This code
                     13: ** is not included in the SQLite library. 
                     14: */
                     15: 
                     16: #include <sqlite3.h>
                     17: 
                     18: /* Solely for the UNUSED_PARAMETER() macro. */
                     19: #include "sqliteInt.h"
                     20: 
                     21: #ifdef SQLITE_ENABLE_RTREE
                     22: /* 
                     23: ** Type used to cache parameter information for the "circle" r-tree geometry
                     24: ** callback.
                     25: */
                     26: typedef struct Circle Circle;
                     27: struct Circle {
                     28:   struct Box {
                     29:     double xmin;
                     30:     double xmax;
                     31:     double ymin;
                     32:     double ymax;
                     33:   } aBox[2];
                     34:   double centerx;
                     35:   double centery;
                     36:   double radius;
                     37: };
                     38: 
                     39: /*
                     40: ** Destructor function for Circle objects allocated by circle_geom().
                     41: */
                     42: static void circle_del(void *p){
                     43:   sqlite3_free(p);
                     44: }
                     45: 
                     46: /*
                     47: ** Implementation of "circle" r-tree geometry callback.
                     48: */
                     49: static int circle_geom(
                     50:   sqlite3_rtree_geometry *p,
                     51:   int nCoord, 
                     52:   double *aCoord, 
                     53:   int *pRes
                     54: ){
                     55:   int i;                          /* Iterator variable */
                     56:   Circle *pCircle;                /* Structure defining circular region */
                     57:   double xmin, xmax;              /* X dimensions of box being tested */
                     58:   double ymin, ymax;              /* X dimensions of box being tested */
                     59: 
                     60:   if( p->pUser==0 ){
                     61:     /* If pUser is still 0, then the parameter values have not been tested
                     62:     ** for correctness or stored into a Circle structure yet. Do this now. */
                     63: 
                     64:     /* This geometry callback is for use with a 2-dimensional r-tree table.
                     65:     ** Return an error if the table does not have exactly 2 dimensions. */
                     66:     if( nCoord!=4 ) return SQLITE_ERROR;
                     67: 
                     68:     /* Test that the correct number of parameters (3) have been supplied,
                     69:     ** and that the parameters are in range (that the radius of the circle 
                     70:     ** radius is greater than zero). */
                     71:     if( p->nParam!=3 || p->aParam[2]<0.0 ) return SQLITE_ERROR;
                     72: 
                     73:     /* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM
                     74:     ** if the allocation fails. */
                     75:     pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle)));
                     76:     if( !pCircle ) return SQLITE_NOMEM;
                     77:     p->xDelUser = circle_del;
                     78: 
                     79:     /* Record the center and radius of the circular region. One way that
                     80:     ** tested bounding boxes that intersect the circular region are detected
                     81:     ** is by testing if each corner of the bounding box lies within radius
                     82:     ** units of the center of the circle. */
                     83:     pCircle->centerx = p->aParam[0];
                     84:     pCircle->centery = p->aParam[1];
                     85:     pCircle->radius = p->aParam[2];
                     86: 
                     87:     /* Define two bounding box regions. The first, aBox[0], extends to
                     88:     ** infinity in the X dimension. It covers the same range of the Y dimension
                     89:     ** as the circular region. The second, aBox[1], extends to infinity in
                     90:     ** the Y dimension and is constrained to the range of the circle in the
                     91:     ** X dimension.
                     92:     **
                     93:     ** Then imagine each box is split in half along its short axis by a line
                     94:     ** that intersects the center of the circular region. A bounding box
                     95:     ** being tested can be said to intersect the circular region if it contains
                     96:     ** points from each half of either of the two infinite bounding boxes.
                     97:     */
                     98:     pCircle->aBox[0].xmin = pCircle->centerx;
                     99:     pCircle->aBox[0].xmax = pCircle->centerx;
                    100:     pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius;
                    101:     pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius;
                    102:     pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius;
                    103:     pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
                    104:     pCircle->aBox[1].ymin = pCircle->centery;
                    105:     pCircle->aBox[1].ymax = pCircle->centery;
                    106:   }
                    107: 
                    108:   pCircle = (Circle *)p->pUser;
                    109:   xmin = aCoord[0];
                    110:   xmax = aCoord[1];
                    111:   ymin = aCoord[2];
                    112:   ymax = aCoord[3];
                    113: 
                    114:   /* Check if any of the 4 corners of the bounding-box being tested lie 
                    115:   ** inside the circular region. If they do, then the bounding-box does
                    116:   ** intersect the region of interest. Set the output variable to true and
                    117:   ** return SQLITE_OK in this case. */
                    118:   for(i=0; i<4; i++){
                    119:     double x = (i&0x01) ? xmax : xmin;
                    120:     double y = (i&0x02) ? ymax : ymin;
                    121:     double d2;
                    122:     
                    123:     d2  = (x-pCircle->centerx)*(x-pCircle->centerx);
                    124:     d2 += (y-pCircle->centery)*(y-pCircle->centery);
                    125:     if( d2<(pCircle->radius*pCircle->radius) ){
                    126:       *pRes = 1;
                    127:       return SQLITE_OK;
                    128:     }
                    129:   }
                    130: 
                    131:   /* Check if the bounding box covers any other part of the circular region.
                    132:   ** See comments above for a description of how this test works. If it does
                    133:   ** cover part of the circular region, set the output variable to true
                    134:   ** and return SQLITE_OK. */
                    135:   for(i=0; i<2; i++){
                    136:     if( xmin<=pCircle->aBox[i].xmin 
                    137:      && xmax>=pCircle->aBox[i].xmax 
                    138:      && ymin<=pCircle->aBox[i].ymin 
                    139:      && ymax>=pCircle->aBox[i].ymax 
                    140:     ){
                    141:       *pRes = 1;
                    142:       return SQLITE_OK;
                    143:     }
                    144:   }
                    145: 
                    146:   /* The specified bounding box does not intersect the circular region. Set
                    147:   ** the output variable to zero and return SQLITE_OK. */
                    148:   *pRes = 0;
                    149:   return SQLITE_OK;
                    150: }
                    151: 
                    152: /* END of implementation of "circle" geometry callback.
                    153: **************************************************************************
                    154: *************************************************************************/
                    155: 
                    156: #include <assert.h>
                    157: #include "tcl.h"
                    158: 
                    159: typedef struct Cube Cube;
                    160: struct Cube {
                    161:   double x;
                    162:   double y;
                    163:   double z;
                    164:   double width;
                    165:   double height;
                    166:   double depth;
                    167: };
                    168: 
                    169: static void cube_context_free(void *p){
                    170:   sqlite3_free(p);
                    171: }
                    172: 
                    173: /*
                    174: ** The context pointer registered along with the 'cube' callback is
                    175: ** always ((void *)&gHere). This is just to facilitate testing, it is not
                    176: ** actually used for anything.
                    177: */
                    178: static int gHere = 42;
                    179: 
                    180: /*
                    181: ** Implementation of a simple r-tree geom callback to test for intersection
                    182: ** of r-tree rows with a "cube" shape. Cubes are defined by six scalar
                    183: ** coordinates as follows:
                    184: **
                    185: **   cube(x, y, z, width, height, depth)
                    186: **
                    187: ** The width, height and depth parameters must all be greater than zero.
                    188: */
                    189: static int cube_geom(
                    190:   sqlite3_rtree_geometry *p,
                    191:   int nCoord, 
                    192:   double *aCoord, 
                    193:   int *piRes
                    194: ){
                    195:   Cube *pCube = (Cube *)p->pUser;
                    196: 
                    197:   assert( p->pContext==(void *)&gHere );
                    198: 
                    199:   if( pCube==0 ){
                    200:     if( p->nParam!=6 || nCoord!=6
                    201:      || p->aParam[3]<=0.0 || p->aParam[4]<=0.0 || p->aParam[5]<=0.0
                    202:     ){
                    203:       return SQLITE_ERROR;
                    204:     }
                    205:     pCube = (Cube *)sqlite3_malloc(sizeof(Cube));
                    206:     if( !pCube ){
                    207:       return SQLITE_NOMEM;
                    208:     }
                    209:     pCube->x = p->aParam[0];
                    210:     pCube->y = p->aParam[1];
                    211:     pCube->z = p->aParam[2];
                    212:     pCube->width = p->aParam[3];
                    213:     pCube->height = p->aParam[4];
                    214:     pCube->depth = p->aParam[5];
                    215: 
                    216:     p->pUser = (void *)pCube;
                    217:     p->xDelUser = cube_context_free;
                    218:   }
                    219: 
                    220:   assert( nCoord==6 );
                    221:   *piRes = 0;
                    222:   if( aCoord[0]<=(pCube->x+pCube->width)
                    223:    && aCoord[1]>=pCube->x
                    224:    && aCoord[2]<=(pCube->y+pCube->height)
                    225:    && aCoord[3]>=pCube->y
                    226:    && aCoord[4]<=(pCube->z+pCube->depth)
                    227:    && aCoord[5]>=pCube->z
                    228:   ){
                    229:     *piRes = 1;
                    230:   }
                    231: 
                    232:   return SQLITE_OK;
                    233: }
                    234: #endif /* SQLITE_ENABLE_RTREE */
                    235: 
                    236: static int register_cube_geom(
                    237:   void * clientData,
                    238:   Tcl_Interp *interp,
                    239:   int objc,
                    240:   Tcl_Obj *CONST objv[]
                    241: ){
                    242: #ifndef SQLITE_ENABLE_RTREE
                    243:   UNUSED_PARAMETER(clientData);
                    244:   UNUSED_PARAMETER(interp);
                    245:   UNUSED_PARAMETER(objc);
                    246:   UNUSED_PARAMETER(objv);
                    247: #else
                    248:   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
                    249:   extern const char *sqlite3TestErrorName(int);
                    250:   sqlite3 *db;
                    251:   int rc;
                    252: 
                    253:   if( objc!=2 ){
                    254:     Tcl_WrongNumArgs(interp, 1, objv, "DB");
                    255:     return TCL_ERROR;
                    256:   }
                    257:   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
                    258:   rc = sqlite3_rtree_geometry_callback(db, "cube", cube_geom, (void *)&gHere);
                    259:   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
                    260: #endif
                    261:   return TCL_OK;
                    262: }
                    263: 
                    264: static int register_circle_geom(
                    265:   void * clientData,
                    266:   Tcl_Interp *interp,
                    267:   int objc,
                    268:   Tcl_Obj *CONST objv[]
                    269: ){
                    270: #ifndef SQLITE_ENABLE_RTREE
                    271:   UNUSED_PARAMETER(clientData);
                    272:   UNUSED_PARAMETER(interp);
                    273:   UNUSED_PARAMETER(objc);
                    274:   UNUSED_PARAMETER(objv);
                    275: #else
                    276:   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
                    277:   extern const char *sqlite3TestErrorName(int);
                    278:   sqlite3 *db;
                    279:   int rc;
                    280: 
                    281:   if( objc!=2 ){
                    282:     Tcl_WrongNumArgs(interp, 1, objv, "DB");
                    283:     return TCL_ERROR;
                    284:   }
                    285:   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
                    286:   rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0);
                    287:   Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
                    288: #endif
                    289:   return TCL_OK;
                    290: }
                    291: 
                    292: int Sqlitetestrtree_Init(Tcl_Interp *interp){
                    293:   Tcl_CreateObjCommand(interp, "register_cube_geom", register_cube_geom, 0, 0);
                    294:   Tcl_CreateObjCommand(interp, "register_circle_geom",register_circle_geom,0,0);
                    295:   return TCL_OK;
                    296: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>