File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / src / test_rtree.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:16 2012 UTC (12 years, 8 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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>