1 /******************************************************************************
2 * Project: libspatialindex - A C++ library for spatial indexing
3 * Author: Marios Hadjieleftheriou, mhadji@gmail.com
4 ******************************************************************************
5 * Copyright (c) 2003, Marios Hadjieleftheriou
6 *
7 * All rights reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 ******************************************************************************/
27
28 // NOTE: Please read README.txt before browsing this code.
29
30 #include <cstring>
31
32 // include library header file.
33 #include <spatialindex/SpatialIndex.h>
34
35 using namespace SpatialIndex;
36 using namespace std;
37
38 #define DELETE 0
39 #define INSERT 1
40 #define QUERY 2
41
42 // example of a Visitor pattern.
43 // findes the index and leaf IO for answering the query and prints
44 // the resulting data IDs to stdout.
45 class MyVisitor : public IVisitor
46 {
47 public:
48 size_t m_indexIO;
49 size_t m_leafIO;
50
51 public:
MyVisitor()52 MyVisitor() : m_indexIO(0), m_leafIO(0) {}
53
visitNode(const INode & n)54 void visitNode(const INode& n)
55 {
56 if (n.isLeaf()) m_leafIO++;
57 else m_indexIO++;
58 }
59
visitData(const IData & d)60 void visitData(const IData& d)
61 {
62 //IShape* pS;
63 //d.getShape(&pS);
64 // do something.
65 //delete pS;
66
67 // data should be an array of characters representing a Region as a string.
68 //byte* pData = 0;
69 //size_t cLen = 0;
70 //d.getData(cLen, &pData);
71 // do something.
72 //string s = reinterpret_cast<char*>(pData);
73 //cout << s << endl;
74 //delete[] pData;
75
76 cout << d.getIdentifier() << endl;
77 // the ID of this data entry is an answer to the query. I will just print it to stdout.
78 }
79
visitData(std::vector<const IData * > & v)80 void visitData(std::vector<const IData*>& v) {}
81 };
82
83 // example of a Strategy pattern.
84 // traverses the tree by level.
85 class MyQueryStrategy : public SpatialIndex::IQueryStrategy
86 {
87 private:
88 queue<id_type> ids;
89
90 public:
getNextEntry(const IEntry & entry,id_type & nextEntry,bool & hasNext)91 void getNextEntry(const IEntry& entry, id_type& nextEntry, bool& hasNext)
92 {
93 IShape* ps;
94 entry.getShape(&ps);
95 Region* pr = dynamic_cast<Region*>(ps);
96
97 cout << pr->m_pLow[0] << " " << pr->m_pLow[1] << endl;
98 cout << pr->m_pHigh[0] << " " << pr->m_pLow[1] << endl;
99 cout << pr->m_pHigh[0] << " " << pr->m_pHigh[1] << endl;
100 cout << pr->m_pLow[0] << " " << pr->m_pHigh[1] << endl;
101 cout << pr->m_pLow[0] << " " << pr->m_pLow[1] << endl << endl << endl;
102 // print node MBRs gnuplot style!
103
104 delete ps;
105
106 const INode* n = dynamic_cast<const INode*>(&entry);
107
108 // traverse only index nodes at levels 2 and higher.
109 if (n != 0 && n->getLevel() > 1)
110 {
111 for (size_t cChild = 0; cChild < n->getChildrenCount(); cChild++)
112 {
113 ids.push(n->getChildIdentifier(cChild));
114 }
115 }
116
117 if (! ids.empty())
118 {
119 nextEntry = ids.front(); ids.pop();
120 hasNext = true;
121 }
122 else
123 {
124 hasNext = false;
125 }
126 }
127 };
128
129 // example of a Strategy pattern.
130 // find the total indexed space managed by the index (the MBR of the root).
131 class MyQueryStrategy2 : public IQueryStrategy
132 {
133 public:
134 Region m_indexedSpace;
135
136 public:
getNextEntry(const IEntry & entry,id_type & nextEntry,bool & hasNext)137 void getNextEntry(const IEntry& entry, id_type& nextEntry, bool& hasNext)
138 {
139 // the first time we are called, entry points to the root.
140
141 // stop after the root.
142 hasNext = false;
143
144 IShape* ps;
145 entry.getShape(&ps);
146 ps->getMBR(m_indexedSpace);
147 delete ps;
148 }
149 };
150
main(int argc,char ** argv)151 int main(int argc, char** argv)
152 {
153 try
154 {
155 if (argc != 4)
156 {
157 cerr << "Usage: " << argv[0] << " query_file tree_file query_type [intersection | 10NN]." << endl;
158 return -1;
159 }
160
161 uint32_t queryType = 0;
162
163 if (strcmp(argv[3], "intersection") == 0) queryType = 0;
164 else if (strcmp(argv[3], "10NN") == 0) queryType = 1;
165 else
166 {
167 cerr << "Unknown query type." << endl;
168 return -1;
169 }
170
171 ifstream fin(argv[1]);
172 if (! fin)
173 {
174 cerr << "Cannot open query file " << argv[1] << "." << endl;
175 return -1;
176 }
177
178 string baseName = argv[2];
179 IStorageManager* diskfile = StorageManager::loadDiskStorageManager(baseName);
180 // this will try to locate and open an already existing storage manager.
181
182 StorageManager::IBuffer* file = StorageManager::createNewRandomEvictionsBuffer(*diskfile, 10, false);
183 // applies a main memory random buffer on top of the persistent storage manager
184 // (LRU buffer, etc can be created the same way).
185
186 // If we need to open an existing tree stored in the storage manager, we only
187 // have to specify the index identifier as follows
188 ISpatialIndex* tree = MVRTree::loadMVRTree(*file, 1);
189
190 size_t count = 0;
191 size_t indexIO = 0;
192 size_t leafIO = 0;
193 id_type id;
194 uint32_t op;
195 double x1, x2, y1, y2, t;
196 double plow[2], phigh[2];
197
198 while (fin)
199 {
200 fin >> t >> op >> id >> x1 >> y1 >> x2 >> y2;
201 if (! fin.good()) continue; // skip newlines, etc.
202
203 if (op == QUERY)
204 {
205 size_t qt1, qt2;
206 fin >> qt1 >> qt2;
207 if (! fin.good()) continue;
208
209 plow[0] = x1; plow[1] = y1;
210 phigh[0] = x2; phigh[1] = y2;
211
212 MyVisitor vis;
213
214 if (queryType == 0)
215 {
216 TimeRegion r = TimeRegion(plow, phigh, qt1, qt2, 2);
217 tree->intersectsWithQuery(r, vis);
218 // this will find all data that intersect with the query range.
219 }
220 else
221 {
222 //Point p = Point(plow, 2);
223 //tree->nearestNeighborQuery(10, p, vis);
224 // this will find the 10 nearest neighbors.
225 }
226
227 indexIO += vis.m_indexIO;
228 leafIO += vis.m_leafIO;
229 // example of the Visitor pattern usage, for calculating how many nodes
230 // were visited.
231 }
232 else
233 {
234 cerr << "This is not a query operation." << endl;
235 }
236
237 if ((count % 1000) == 0)
238 cerr << count << endl;
239
240 count++;
241 }
242
243 MyQueryStrategy2 qs;
244 tree->queryStrategy(qs);
245
246 cerr << "Indexed space: " << qs.m_indexedSpace << endl;
247 cerr << "Operations: " << count << endl;
248 cerr << *tree;
249 cerr << "Index I/O: " << indexIO << endl;
250 cerr << "Leaf I/O: " << leafIO << endl;
251 cerr << "Buffer hits: " << file->getHits() << endl;
252
253 delete tree;
254 delete file;
255 delete diskfile;
256 // delete the buffer first, then the storage manager
257 // (otherwise the the buffer will fail writting the dirty entries).
258 }
259 catch (Tools::Exception& e)
260 {
261 cerr << "******ERROR******" << endl;
262 std::string s = e.what();
263 cerr << s << endl;
264 return -1;
265 }
266 catch (...)
267 {
268 cerr << "******ERROR******" << endl;
269 cerr << "other exception" << endl;
270 return -1;
271 }
272
273 return 0;
274 }
275