Empress Technical News – May
2009
      Database Spatial Search
Index – Fast Geographical Data Retrieval
 
Introduction
Empress
Ultra Embedded V10.20 offers many additional features to application
developers. One of those features is a Spatial Search Index capability for fast
geographical data retrieval.
Empress Spatial
Index
Empress
Ultra Embedded V10.20 Spatial Search Index capability empowers application
developers to implement an efficient search using spatial access methods for
geographic location data.
The
spatial index capability is developed as an additional set of C calls that are
used in conjunction with Empress C/C++ Kernel Level API (mr Routines) and a set
of SQL commands.
The
Empress spatial Index technology is based on an R* tree index. R*
tree is a variant of R tree for indexing spatial information.
are tree data structures similar to B-trees (already in use with Empress
indexes) but are used for spatial access methods, i.e. for indexing
multi-dimensional information for example, the (X, Y) coordinates of
geographical data. A common real-world usage for an R-tree might be: " Find
all points of interest within 5 kilometers of my current location" .
Empress Spatial Index C
API
The
Empress spatial search capability uses the following set of C API calls that
should be used in conjunction with Empress C/C++ Kernel Level mr Routines:
ms_rstree_open
ms_rstree_close
ms_rstree_point_search_in_rectangle
ms_rstree_point_search_in_circle ms_rstree_rect_search_in_circle
ms_rstree_rect_search_overlap_circle ms_rstree_rect_search_in_rectangle
ms_rstree_rect_search_overlap_rectangle
ms_rstree_list_free
Example Using Spatial
Search
In the
following source code example rstree_select.c searches for all
the restaurants in the specified rectangle given by its geographical
coordinates. Restaurants, stored as points of interest, have the
characteristics such as, for example:
ID:              4
Name: 
 
 
 
 
Frankie Tomatto’s
Address: 
 
7225 Woodbine Avenue 1A3&lrm
Phone: 
 
 
 
(905) 940-1900&lrm
Latitude: 
43 degrees 49 minutes 09.51 seconds North
Longitude: 79 degrees 20 minutes 53.41 seconds West
R*
tree index
expects geographical parameters, such as longitude and latitude, defined as
integers or float numbers. Hence, the values expressed in degrees, minutes and
seconds need to be converted. For example:
  The latitude 43 degrees 49 minutes 09.51
seconds North is converted to:
43 * 360000 + 49 * 6000 + 9.51*100 = 15774951
The
longitude 79 degrees 20 minutes 53.41 seconds West is converted to:
79 * 360000 + 20 * 6000 + 53.41*100 = 28565341
The
following tables give an idea of how distances in meters relates to degrees,
minutes and seconds. The figures are taken from the following source:
Robinson,
Arthur H. et al. of Cartography, 5th ed. New York: John Wiley & Sons, 1984. (pp
64-66, Appendix B)
Latitude:
1
degree of latitude
|
=     
|
1
degree               
|
or         
|
110,874.4
meters
|
1
minute of latitude
|
=
|
1/60
of a degree
|
or
|
1,847.91
meters
|
1
second of latitude
|
=
|
1/60
of a minute
|
or
|
30.7984
meters
|
1/10
of a second of latitude
|
=
|
.10
of one second
|
or
|
3.0798
meters
|
1/100
of a second of latitude
|
=
|
.01
of one second   
|
or
|
0.3080
meters
|
Longitude:
1
degree of longitude
|
=       
|
1
degree               
|
or         
|
95,506
meters
|
1
minute of longitude
|
=
|
1/60
of a degree
|
or
|
1,591.7667
meters
|
1
second of longitude
|
=
|
1/60
of a minute
|
or
|
26.5294
meters
|
1/10
of a second of longitude
|
=
|
.10
of one second
|
or
|
2.6529
meters
|
1/100
of a second of longitude       
|
= 
|
.01
of one  second   
|
or
|
0.2653
meters
|
Example Source Code
In the
example below, integers were used as the coordinates. Float values could have
been used as well. When dealing with the circular search in the example the
radius of 1500 represents approximately 450 meters.
The
source code example is as follows:
#include     
<
mscc.h>
#define 
 
 
 
DATABASE                          " testdb"
#define 
 
 
 
RTREE_RECT_XMIN           28562500
#define 
 
 
 
RTREE_RECT_YMIN           15772000
#define 
 
 
 
RTREE_RECT_XMAX           28567500
#define 
 
 
 
RTREE_RECT_YMAX           15774000
#define 
 
 
 
RTREE_CIRCLE_X              28565200
#define 
 
 
 
RTREE_CIRCLE_Y              15773100
#define 
 
 
 
RTREE_CIRCLE_RADIUS  
int main (int argc, argv[])
 
 
 
 
 
 
void* 
poi_tabdesc
 
 
 
 
 
 
void* 
name_attrdesc
void* 
id_attrdesc
void* 
x_attrdesc
void* 
y_attrdesc
 
 
 
 
 
 
void*  poi_recdesc
void* 
qual
 
 
 
 
 
 
void* 
retrieve_desc
void* 
rshandle
char* 
name_value
char* 
id_value
char* 
x_value
char* 
y_value
 
 
 
 
 
 
long* 
rec_list
 
 
 
 
 
 
long   
rect_buf[4]={RTREE_RECT_XMIN, RTREE_RECT_YMIN, RTREE_RECT_XMAX,                                             RTREE_RECT_YMAX}
 
 
 
 
 
 
long   
circle_buf[3]={RTREE_CIRCLE_X, RTREE_CIRCLE_Y, RTREE_CIRCLE_RADIUS}
 
 
 
 
 
 
msinit ()
 
 
 
 
 
 
  poi_tabdesc = mropen (DATABASE, " poi" , 'r')
 
 
 
 
 
 
 
poi_recdesc =
mrmkrec (poi_tabdesc)
 
 
 
 
 
 
 
name_attrdesc =
mrngeta (poi_tabdesc, name" )
 
 
 
 
 
 
 
id_attrdesc =
mrngeta (poi_tabdesc, id" )
 
 
 
 
 
 
 
x_attrdesc =
mrngeta (poi_tabdesc, x" )
 
 
 
 
 
 
 
y_attrdesc = mrngeta (poi_tabdesc, " y" )
 
 
 
 
 
 
 
name_value = mrspv (name_attrdesc)
 
 
 
 
 
 
 
id_value =
mrspv (id_attrdesc)
 
 
 
 
 
 
 
x_value = mrspv
(x_attrdesc)
 
 
 
 
 
 
 
y_value = mrspv (y_attrdesc)
 
 
 
 
 
 
 
rshandle = ms_rstree_open (poi_tabdesc, x_attrdesc,
y_attrdesc, 0)
 
 
 
 
 
 
 
if (rshandle == 0)
             
 
 
 
 
 
 
 
 
 
 
 
 
 
fprintf
(stderr, " cannot open rstree index
\n"
)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
return (1)
 
 
 
 
 
 
 
}
/*** search for points of interest in defined rectangle
***/
 
 
 
 
 
 
 
rec_list =
ms_rstree_point_search_in_rectangle (rshandle, ( rect_buf)
/*** alternatevely search for points of interest in
defined circle
 
 
 
 
 
 
 
rec_list
= ms_rstree_point_search_in_circle (rshandle, (long*) circle_buf)
***/
 
 
 
 
 
 
 
if (rec_list == 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
goto done1
 
 
 
 
 
 
 
printf (" Points of Interest inside defined
rectangle\n\n"
)
 
 
 
 
 
 
 
printf (" id   
name 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
X
coordinate 
 
Y coordinate\n"
 
 
 
 
 
 
  qual = mrqlst (poi_tabdesc, rec_list)
 
 
 
 
 
 
 
retrieve_desc = mrgetbegin (qual, poi_recdesc, ( 0)
 
 
 
 
 
 
 
while (mrget (retrieve_desc))
 
 
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
mrcopyv
(poi_recdesc, name_attrdesc, name_value)
 
 
 
 
 
 
 
 
 
 
 
 
mrcopyv
(poi_recdesc, id_attrdesc, id_value)
 
 
 
 
 
 
 
 
 
 
 
 
mrcopyv
(poi_recdesc, x_attrdesc, x_value)
 
 
 
 
 
 
 
 
 
 
 
 
mrcopyv (poi_recdesc, y_attrdesc, y_value)
 
 
 
 
 
 
 
 
 
 
 
 
printf (" %-5s%-20s%-15s%-15s\n" id_value, name_value, x_value, y_value)
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
mrgetend
(retrieve_desc)
 
 
 
 
 
 
 
ms_rstree_list_free
(rec_list)
 
 
 
 
 
 
 
mrfree
(name_value)
 
 
 
 
 
 
 
mrfree
(id_value)
 
 
 
 
 
 
 
mrfree
(x_value)
 
 
 
 
 
 
 
if (!mrfrrec (poi_recdesc))
 
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
fprintf
(stderr, " ERROR in freeing record
buffers\n"
)
 
 
 
 
 
 
 
 
 
 
 
 
 
fprintf (stderr, " mroperr='%d' : %s\n" , mroperr, mrerrmsg ())
 
 
 
 
 
 
}
              (!mrclose (poi_tabdesc))
 
 
 
 
 
 
{
                          fprintf
(stderr, " Unable to close the
table\n"
)
 
 
 
 
 
 
 
 
 
 
 
 
 
fprintf (stderr, " mroperr='%d' : %s\n" , mroperr, mrerrmsg ())
 
 
 
 
 
 
}
done1:
 
 
 
 
 
 
ms_rstree_close
(rshandle)
 
 
 
 
 
 
msend ()
 
 
 
 
 
 
return 0
Example – Preparing Data
Thefollowing sequence of steps will show how to prepare data in the database for
running the example. The latitude and longitude values were real values derived
from Google Earth.
To create
the database testdb it doesn’t exist) run:
empmkdb testdb
To create
the table poi that contains ‘points of interest’ locations and
insert records with some restaurants information, run:
empbatch testdb sql_commands
where sql_commands file looks as follows:
CREATE TABLE poi (
 
 
 
 
 
 
 
id                                        INTEGER        NOT NULL,
 
 
 
 
 
 
 
name                        VARCHAR(32),
 
 
 
 
 
 
 
address 
 
 
 
 
 
 
 
CLOB(64),
 
 
 
 
 
 
 
phone                        VARCHAR(15),
 
 
 
 
 
 
 
x                                            INTEGER,
 
 
 
 
 
 
 
y                                                  INTEGER
)
INSERT INTO poi VALUES ( 1, " Ten23" ,
"
3100
Steeles Avenue East, Markham, ON L3R 8T3" ,
"
(905) 479-6488" , 28565120, 15773195 )
INSERT INTO poi VALUES ( 2, " Buffet City" ,
"
3160
Steeles Avenue East, Markham, ON L3R 4G9" ,
"
(905) 474-9899" , 28563997, 15773487 )
INSERT INTO poi VALUES ( 3, " Golden Griddle" ,
"
7100 Woodbine Avenue, Markham,
ON L3R 5J2" ,
"
(905) 477-6980" ,
28565768, 15773777 )
INSERT INTO poi VALUES ( 4,
"
Frankie Tomatto’s" ,
"
7225 Woodbine Avenue, Markham, ON L3R 1A3" ,
"
(905) 940-1900" ,
28565341, 15774951 )
INSERT INTO poi VALUES ( 5,
"
Phoenix Restaurant" ,
"
7155 Woodbine Avenue, Markham,
ON L3R 1A3" ,
"
(905) 940-1113" ,
28565710, 15774350 )
INSERT INTO poi VALUES ( 6," Tandoori Queen" ,
"
708 Gordon Baker Road, North York,
ON M2H 3B4" ,
"
(416) 492-7993" ,
28564299, 15771282 )
INSERT INTO poi VALUES ( 7,
"
Owl & Firkin" ,
"
7181 Woodbine Avenue, Markham,
ON L3R 1A3" ,
"
(905) 513-6611" ,
28565684, 15774552 )
CREATE RSTARTREE INDEX poix ONpoi(x,y)
Example– Compiling the C Program
To
compile an example: go to the directory where the example is copied and run the
Empress compiler utility empcc command:
empcc -o
rstree_select rstree_select.c
The executable file be created in the same
directory.
Example
– Running the Program Using a Rectangle
When rstree_select gets executed it will display the following
result.
Points
of Interest inside defined rectangle
id                                coordinate    coordinate
1 
 
 
Ten23                              28565120                     
2 
 
 
Buffet City                  28563997            15773487           
3 
 
 
Golden Griddle            28565768            15773777 
Points ofinterest (i.e. restaurants) that satisfy the criteria for the above search are
shown in the Fig 1. The letter A in the red balloon on the map below is
the starting point. The numbers in the blue balloons on the map below
correspond to the “id” of the “Points of Interest”.  
Fig 1: Spatial search for all points of
interest inside the defined rectangle
Example
– Running the Program Using a Circle
Insteadof using rectangle spatial search:
ms_rstree_point_search_in_rectangle (rshandle, (    
a circle spatial search could be used:
ms_rstree_point_search_in_circle (rshandle, (long circle_buf)
With this change, when rstree_select gets executed it will
display the following result.
Pointsof Interest inside defined circle
id 
 
name                              X coordinate    Y coordinate
1      Ten23                                        15773195           
2 
 
 
Buffet City                  28563997            15773487           
3 
 
 
Golden Griddle            28565768            15773777           
5 
 
 
Phoenix Restaurant              15774350   
Points of
interest (i.e. restaurants) that satisfy the criteria for the above search are
shown in the Fig 2. 
The letter A
in the red balloon on the map below is the starting point. The numbers in the
blue balloons on the map below correspond to the “id” of the “Points of
Interest”.
                                Fig 2: Spatial search for all points of
interest inside the defined circle
The rectangle produced 3 points ofinterest while the circle produced 4 points of interest.
And Furthermore
Empress Spatial index search
functionality can be used with other regular Empress query search conditions.
In addition, it can be used with special Empress features such as Empress text
search and Empress Shiborikomi search.
Empress
Software Inc.
www.empress.com