Annotation of embedaddon/sqlite3/src/test_rtree.c, revision 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>