1 /* Supporting different types and containers.
2  * Copyright (C) 2017  Marko Semet
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 module structuresd.dimension.rtree;
18 
19 private
20 {
21 	import core.exception;
22 	import std.algorithm.sorting;
23 	import structuresd;
24 	import structuresd.dimension;
25 	import structuresd.utils;
26 }
27 
28 /**
29  * Do split of a two big container. Innto two lower.
30  * @param data Source data to split
31  * @param toCompare function to get geometry to compare
32  * @return two list for one of the old container and one for the new one
33  */
34 private pure nothrow T1[][2] _split(T1, size_t MIN, size_t MAX, T2 = T1)(T1[] data, T2 function(T1) nothrow pure toCompare)
35 in {
36 	static assert(MIN >= 1);
37 	assert(2 * MIN <= data.length);
38 	assert(2 * MAX >= data.length);
39 }
40 out(outData) {
41 	assert(outData[0].length >= MIN);
42 	assert(outData[0].length <= MAX);
43 	assert(outData[1].length >= MIN);
44 	assert(outData[1].length <= MAX);
45 }
46 body {
47 	// Most away
48 	T1 a = data[0];
49 	T1 b = data[1];
50 	while(true)
51 	{
52 		T1 tmp = b;
53 		T2.BASE_TYPE tmp2 = toCompare(b).maxGeometry(toCompare(a)).volume();
54 		foreach(ref T1 t; data)
55 		{
56 			if((t != a) && (t != b))
57 			{
58 				if(tmp2 < toCompare(a).maxGeometry(toCompare(t)).volume())
59 				{
60 					tmp = t;
61 					tmp2 = toCompare(a).maxGeometry(toCompare(t)).volume();
62 				}
63 			}
64 		}
65 
66 		if(tmp == b)
67 		{
68 			break;
69 		}
70 		else
71 		{
72 			b = a;
73 			a = tmp;
74 		}
75 	}
76 
77 	// Do sorting
78 	{
79 		struct SortElement
80 		{
81 			T1 t1;
82 			T2.BASE_TYPE t2;
83 
84 			this(T1 t)
85 			{
86 				t1 = t;
87 				t2 = min(getInseredVolume(toCompare(a), toCompare(t)), getInseredVolume(toCompare(b), toCompare(t)));
88 			}
89 
90 			int opCmp(const SortElement b)
91 			{
92 				return this.t2 < b.t2 ? -1 : this.t2 > b.t2 ? 1 : 0;
93 			}
94 			bool opEquals(const SortElement b)
95 			{
96 				return this.t2 == b.t2;
97 			}
98 		}
99 
100 		SortElement[] sorted = new SortElement[data.length];
101 		for(size_t i = 0; i < data.length; i++)
102 		{
103 			sorted[i] = SortElement(data[i]);
104 		}
105 		size_t tmp = 0;
106 		foreach(SortElement t; sorted.sort)
107 		{
108 			data[tmp] = t.t1;
109 			tmp++;
110 		}
111 	}
112 
113 	// Do split
114 	T1[] resA = new T1[MAX];
115 	T1[] resB = new T1[MAX];
116 	size_t sizeA = 1;
117 	size_t sizeB = 1;
118 	resA[0] = a;
119 	resB[0] = b;
120 	size_t missing = data.length - 2;
121 	bool addedA = false;
122 	bool addedB = false;
123 	foreach(ref T1 t; data)
124 	{
125 		if((a == t) && (!addedA))
126 		{
127 			addedA = true;
128 			continue;
129 		}
130 		if((b == t) && (!addedB))
131 		{
132 			addedB = true;
133 			continue;
134 		}
135 
136 		if(sizeA + missing == MIN)
137 		{
138 			resA[sizeA] = t;
139 			sizeA++;
140 		}
141 		else if(sizeB + missing == MIN)
142 		{
143 			resB[sizeB] = t;
144 			sizeB++;
145 		}
146 		else
147 		{
148 			if(getInseredVolume(toCompare(a), toCompare(t)) < getInseredVolume(toCompare(b), toCompare(t)))
149 			{
150 				resA[sizeA] = t;
151 				sizeA++;
152 			}
153 			else
154 			{
155 				resB[sizeB] = t;
156 				sizeB++;
157 			}
158 		}
159 		missing--;
160 	}
161 	return [resA[0..sizeA], resB[0..sizeB]];
162 }
163 
164 /**
165  * A RTree implementation.
166  * @tparam DATA_T The data type that will be insert. It have to be castable to TYPE.
167  * @tparam TYPE Is the geometry structure that will be used. It have to match the isGeometry in parent package.
168  * @tparam MAX Maximal node size before spilt. MAX have to be at least 3 and odd.
169  * @tparam MIN Minimal node isze before merge. MIN have to be greater then 0 and lower or equal to 2 * MAX + 1.
170  */
171 public final class RTree(DATA_T, TYPE, size_t MAX, size_t MIN, FEATURES features = FEATURES.NON)
172 {
173 	static assert(isGeometry!TYPE);
174 	static assert(MAX % 2 == 1);
175 	static assert(MAX >= 3);
176 	static assert(MIN * 2 <= MAX + 1);
177 	static assert(MIN > 0);
178 
179 	private struct _Node
180 	{
181 		public size_t elements = 0;
182 		public bool isLeave = false;
183 		public _Node* parent = null;
184 		public TYPE ownSize;
185 		union
186 		{
187 			public DATA_T[MAX] leaves;
188 			public _Node*[MAX] nodes;
189 		}
190 
191 		@nogc
192 		private nothrow pure _Node* getRoot()
193 		{
194 			_Node* current = &this;
195 			while(current.parent !is null)
196 			{
197 				current = current.parent;
198 			}
199 			return current;
200 		}
201 
202 		public pure nothrow _Node* insert(ref DATA_T toInsert)
203 		{
204 			if(this.isLeave)
205 			{
206 				if(this.elements < MAX)
207 				{
208 					// No split
209 					this.leaves[this.elements] = toInsert;
210 					this.elements++;
211 					this.updateSize!true();
212 					return this.getRoot();
213 				}
214 				else
215 				{
216 					// Prepare split
217 					DATA_T[][2] tmp = _split!(DATA_T, MIN, MAX, TYPE)(this.leaves ~ [toInsert], function TYPE(DATA_T t) => (cast(TYPE) t));
218 					this.leaves[0..tmp[0].length] = tmp[0];
219 					this.elements = tmp[0].length;
220 					this.updateSize!false();
221 
222 					_Node* newNode = new _Node;
223 					newNode.isLeave = true;
224 					newNode.leaves[0..tmp[1].length] = tmp[1];
225 					newNode.elements = tmp[1].length;
226 					newNode.updateSize!false();
227 
228 					// Do split
229 					if(this.parent is null)
230 					{
231 						// New root
232 						_Node* root = new _Node;
233 						root.isLeave = false;
234 						root.elements = 2;
235 						root.nodes[0..2] = [&this, newNode];
236 						root.updateSize!false();
237 
238 						this.parent = root;
239 						newNode.parent = root;
240 					}
241 					else
242 					{
243 						// Use root
244 						this.parent.insert(newNode);
245 					}
246 					return this.getRoot();
247 				}
248 			}
249 			else
250 			{
251 				// Select min node
252 				_Node* best = this.nodes[0];
253 				TYPE.BASE_TYPE bestInsert = getInseredVolume(this.nodes[0].ownSize, cast(TYPE) toInsert);
254 				foreach(_Node* node; this.nodes)
255 				{
256 					TYPE.BASE_TYPE tmp = getInseredVolume(this.nodes[0].ownSize, cast(TYPE) toInsert);
257 					if(bestInsert > tmp)
258 					{
259 						bestInsert = tmp;
260 						best = node;
261 					}
262 				}
263 
264 				// insert
265 				return best.insert(toInsert);
266 			}
267 		}
268 		private pure nothrow void insert(_Node* node)
269 		{
270 			if(this.elements < MAX)
271 			{
272 				// Normal insert
273 				this.nodes[this.elements] = node;
274 				this.elements++;
275 				node.parent = &this;
276 				this.updateSize!true();
277 			}
278 			else
279 			{
280 				// Prepare split
281 				node.parent = &this;
282 				_Node*[][2] tmp = _split!(_Node*, MIN, MAX, TYPE)(this.nodes ~ [node], function TYPE(_Node* t) => t.ownSize);
283 
284 				this.elements = tmp[0].length;
285 				this.nodes[0..tmp[0].length] = tmp[0];
286 				this.updateSize!false();
287 
288 				_Node* newNode = new _Node;
289 				newNode.isLeave = false;
290 				newNode.elements = tmp[1].length;
291 				newNode.nodes[0..tmp[1].length] = tmp[1];
292 				newNode.updateSize!false();
293 				foreach(_Node* i; tmp[1])
294 				{
295 					i.parent = newNode;
296 				}
297 
298 				// Split
299 				if(this.parent == null)
300 				{
301 					// New root
302 					_Node* root = new _Node;
303 					root.elements = 2;
304 					root.nodes[0..2] = [&this, newNode];
305 					root.isLeave = false;
306 					root.updateSize!false();
307 
308 					this.parent = root;
309 					newNode.parent = root;
310 				}
311 				else
312 				{
313 					// Call parent
314 					this.parent.insert(newNode);
315 				}
316 			}
317 		}
318 		@nogc
319 		private pure nothrow void updateSize(bool RECUSIVE)()
320 		{
321 			_Node* tmp = &this;
322 			while(tmp !is null)
323 			{
324 				TYPE res = tmp.isLeave ? cast(TYPE)(tmp.leaves[0]) : tmp.nodes[0].ownSize;
325 				for(size_t i = 1; i < tmp.elements; i++)
326 				{
327 					res = res.maxGeometry(tmp.isLeave ? cast(TYPE)(tmp.leaves[i]) : tmp.nodes[i].ownSize);
328 				}
329 				tmp.ownSize = res;
330 
331 				static if(RECUSIVE)
332 				{
333 					tmp = tmp.parent;
334 				}
335 				else
336 				{
337 					return;
338 				}
339 			}
340 		}
341 	}
342 
343 	/**
344 	 * Query iterator to parse queries.
345 	 */
346 	public final class QueryIterator
347 	{
348 		private _Node* current;
349 		private size_t index;
350 		private TYPE range;
351 		private bool useable;
352 
353 		pragma(inline, true)
354 		package pure nothrow this(_Node* root, TYPE range)
355 		{
356 			this.current = root;
357 			this.index = 0;
358 			this.range = range;
359 			this.useable = false;
360 		}
361 
362 		private void toNext()
363 		{
364 			while(this.current !is null)
365 			{
366 				if(this.index < this.current.elements)
367 				{
368 					// Scan if useable
369 					if(this.current.isLeave)
370 					{
371 						if((cast(TYPE) this.current.leaves[this.index]).contains(this.range))
372 						{
373 							this.useable = true;
374 							break;
375 						}
376 						else
377 						{
378 							this.index++;
379 						}
380 					}
381 					else
382 					{
383 						if(this.current.nodes[this.index].ownSize.contains(this.range))
384 						{
385 							this.current = this.current.nodes[this.index];
386 							this.index = 0;
387 						}
388 						else
389 						{
390 							this.index++;
391 						}
392 					}
393 				}
394 				else
395 				{
396 					// Move up one position
397 					_Node* old = this.current;
398 					this.current = old.parent;
399 					this.index = 0;
400 					if(this.current is null)
401 					{
402 						break;
403 					}
404 					while(true)
405 					{
406 						if(this.current.nodes[this.index] is old)
407 						{
408 							this.index++;
409 							break;
410 						}
411 						else
412 						{
413 							this.index++;
414 							if(this.index >= this.current.elements)
415 							{
416 								throw new RangeError("Data structure currupted.");
417 							}
418 						}
419 					}
420 				}
421 			}
422 		}
423 
424 		public void popFront()
425 		{
426 			if(!this.useable)
427 				this.toNext();
428 			this.useable = false;
429 			this.index++;
430 		}
431 		@property
432 		pure nothrow bool empty()
433 		{
434 			if(!useable)
435 			{
436 				this.toNext();
437 				return !this.useable;
438 			}
439 			return false;
440 		}
441 		DATA_T front()
442 		{
443 			if(!useable)
444 			{
445 				this.toNext();
446 			}
447 			if(useable)
448 			{
449 				return this.current.leaves[this.index];
450 			}
451 			else
452 			{
453 				throw new RangeError("Out of range");
454 			}
455 		}
456 
457 		int opApply(scope int delegate(DATA_T) func)
458 		{
459 			int counter = 0;
460 			while(!this.empty())
461 			{
462 				func(front());
463 				this.popFront();
464 				counter++;
465 			}
466 			return counter;
467 		}
468 	}
469 
470 	private _Node* _root;
471 
472 	/**
473 	 * Generates an RTree structure.
474 	 */
475 	public pure nothrow this()
476 	{
477 		this._root = new _Node;
478 		this._root.isLeave = true;
479 		this._root.elements = 0;
480 		this._root.parent = null;
481 	}
482 
483 	/**
484 	 *
485 	 */
486 	public nothrow pure QueryIterator query(TYPE range)
487 	{
488 		return new QueryIterator(this._root, range);
489 	}
490 
491 	/**
492 	 * Insert data to the tree.
493 	 * @param data Source data to insert.
494 	 * @return was insert successfully.
495 	 */
496 	public pure nothrow bool insert(DATA_T data)
497 	{
498 		this._root = this._root.insert(data);
499 		return true;
500 	}
501 }
502 
503 private unittest
504 {
505 	RTree!(Cuboid!2, Cuboid!2, 11, 5) rtree;
506 }