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