1
/*************************************************************************
3
* Copyright (c) 2010 Kohei Yoshida
5
* Permission is hereby granted, free of charge, to any person
6
* obtaining a copy of this software and associated documentation
7
* files (the "Software"), to deal in the Software without
8
* restriction, including without limitation the rights to use,
9
* copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the
11
* Software is furnished to do so, subject to the following
14
* The above copyright notice and this permission notice shall be
15
* included in all copies or substantial portions of the Software.
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
* OTHER DEALINGS IN THE SOFTWARE.
26
************************************************************************/
28
#ifndef __MDDS_RECTANGLE_SET_HPP__
29
#define __MDDS_RECTANGLE_SET_HPP__
31
#include "segment_tree.hpp"
35
#include <unordered_map>
36
#include <boost/ptr_container/ptr_map.hpp>
40
template<typename _Key, typename _Data>
44
typedef _Key key_type;
45
typedef _Data data_type;
59
rectangle(key_type _x1, key_type _y1, key_type _x2, key_type _y2) :
60
x1(_x1), y1(_y1), x2(_x2), y2(_y2) {}
62
rectangle(const rectangle& r) :
63
x1(r.x1), y1(r.y1), x2(r.x2), y2(r.y2) {}
65
rectangle& operator= (const rectangle& r)
74
bool operator== (const rectangle& r) const
76
return x1 == r.x1 && y1 == r.y1 && x2 == r.x2 && y2 == r.y2;
79
bool operator!= (const rectangle& r) const
81
return !operator==(r);
84
typedef ::std::unordered_map<data_type*, rectangle> dataset_type;
86
typedef segment_tree<key_type, data_type> inner_type;
87
typedef segment_tree<key_type, inner_type> outer_type;
89
typedef ::std::pair<key_type, key_type> interval_type;
90
typedef ::boost::ptr_map<interval_type, inner_type> inner_segment_map_type;
93
typedef typename inner_type::search_result_type search_result_type;
96
* Most of the implementation of search_result and its iterator is in
97
* segment_tree since the iteration logic is identical & depends on the
98
* segment_tree internals.
100
class search_result : public inner_type::search_result_base
103
typedef typename inner_type::search_result_base::res_chains_type res_chains_type;
104
typedef typename inner_type::search_result_base::res_chains_ptr res_chains_ptr;
105
typedef typename inner_type::data_chain_type data_chain_type;
109
class iterator : public inner_type::iterator_base
111
friend class rectangle_set<_Key,_Data>::search_result;
113
iterator(const res_chains_ptr& p) : inner_type::iterator_base(p) {}
115
iterator() : inner_type::iterator_base() {}
118
search_result() : inner_type::search_result_base() {}
119
search_result(const search_result& r) : inner_type::search_result_base(r) {}
121
typename search_result::iterator begin()
123
typename search_result::iterator itr(
124
inner_type::search_result_base::get_res_chains());
129
typename search_result::iterator end()
131
typename search_result::iterator itr(
132
inner_type::search_result_base::get_res_chains());
139
rectangle_set(const rectangle_set& r);
142
rectangle_set& operator= (const rectangle_set& r);
145
* Equality between two instances of rectangle_set is evaluated based on
146
* the stored rectangle instances; their pointer values and geometries.
148
bool operator== (const rectangle_set& r) const;
150
bool operator!= (const rectangle_set& r) const { return !operator==(r); }
153
* Insert a new rectangle (and data associated with it) into the set.
154
* Note that insertion of duplicate data instance is not allowed. A data
155
* is considered a duplicate if its pointer value is identical to one of
156
* the data instances already stored within. Also note that <i>the end
157
* point of a rectangle is non-inclusive; a rectangle of (x1,y1) - (x2,y2)
158
* means that the rectangle spans x1 <= x < x2 and y1 <= y < y2.</i>
160
* @param x1 lower x coordinate of the rectangle. Inclusive.
161
* @param y1 lower y coordinate of the rectangle. Inclusive.
162
* @param x2 upper x coordinate of the rectangle. Non-inclusive.
163
* @param y2 upper y coordinate of the rectangle. Non-inclusive.
164
* @param data pointer to data instance associated with this rectangle.
165
* <i>Note that the caller is responsible for managing the
166
* life cycle of the data instance</i>.
168
* @return true if a rectangle successfully inserted, false otherwise.
170
bool insert(key_type x1, key_type y1, key_type x2, key_type y2, data_type* data);
173
* Search and collect all rectangles that contains a given point.
175
* @param x x coordinate of a query point.
176
* @param y y coordinate of a query point.
177
* @param result array of pointers to rectangle instances.
179
* @return true if the search is successful, false otherwise.
181
bool search(key_type x, key_type y, search_result_type& result);
184
* Search and collect all rectangles containing a given point.
186
* @param x x coordinate of a query point.
187
* @param y y coordinate of a query point.
189
* @return object containing the result of the search, which can be
190
* accessed via iterator.
192
search_result search(key_type x, key_type y);
195
* Remove a rectangle instance pointed to by a given pointer.
197
* @param data pointer that points to the rectangle instance you wish to
198
* remove from the set.
200
void remove(data_type* data);
203
* Clear all rectangles stored in the set.
208
* Return the number of rectangles currently stored in the set.
210
* @return number of stored rectangles.
215
* Check whether or not the set is empty.
217
* @return true if the set is empty, false otherwise.
222
void build_outer_segment_tree();
226
void dump_rectangles() const;
227
bool verify_rectangles(const dataset_type& expected) const;
233
* This data member stores pointers to the inner segment tree instances
234
* associated with outer intervals. Used to speed up searches.
236
outer_type m_outer_segments;
239
* This data member owns the inner segment_tree instances.
241
inner_segment_map_type m_inner_map;
244
* Used to keep track of currently stored data instances, to prevent
245
* insertion of duplicates. Duplicates are defined as data objects having
246
* identical pointer value.
248
dataset_type m_dataset;
251
template<typename _Key, typename _Data>
252
rectangle_set<_Key,_Data>::rectangle_set()
256
template<typename _Key, typename _Data>
257
rectangle_set<_Key,_Data>::rectangle_set(const rectangle_set& r) :
258
m_inner_map(r.m_inner_map),
259
m_dataset(r.m_dataset)
261
build_outer_segment_tree();
264
template<typename _Key, typename _Data>
265
rectangle_set<_Key,_Data>::~rectangle_set()
269
template<typename _Key, typename _Data>
270
rectangle_set<_Key,_Data>& rectangle_set<_Key,_Data>::operator= (const rectangle_set& r)
272
clear(); // Don't forget to clear the internal state beforehands.
274
m_inner_map = r.m_inner_map;
275
m_dataset = r.m_dataset;
276
build_outer_segment_tree();
280
template<typename _Key, typename _Data>
281
bool rectangle_set<_Key,_Data>::operator== (const rectangle_set& r) const
283
if (m_dataset.size() != r.m_dataset.size())
286
typename dataset_type::const_iterator itr = m_dataset.begin(), itr_end = m_dataset.end();
287
for (; itr != itr_end; ++itr)
289
typename dataset_type::const_iterator itr_rhs = r.m_dataset.find(itr->first);
290
if (itr_rhs == r.m_dataset.end())
293
if (itr->second != itr_rhs->second)
300
template<typename _Key, typename _Data>
301
bool rectangle_set<_Key,_Data>::insert(key_type x1, key_type y1, key_type x2, key_type y2, data_type* data)
303
// Make sure this is not a duplicate.
304
if (m_dataset.find(data) != m_dataset.end())
307
// Check if interval x1 - x2 is already stored.
308
interval_type outer_interval = interval_type(x1, x2);
309
typename inner_segment_map_type::iterator itr = m_inner_map.find(outer_interval);
310
if (itr == m_inner_map.end())
312
// this interval has not yet been stored. Create a new inner segment
313
// tree instance for this interval.
314
::std::pair<typename inner_segment_map_type::iterator, bool> r =
315
m_inner_map.insert(outer_interval, new inner_type);
317
throw general_error("inner segment tree insertion failed.");
321
// Register the pointer to this inner segment tree instance with the
322
// outer segment tree.
323
if (!m_outer_segments.insert(x1, x2, itr->second))
324
// This should never fail if my logic is correct.
325
throw general_error("failed to insert an inner segment tree pointer into the outer segment tree.");
328
inner_type* inner_tree = itr->second;
329
inner_tree->insert(y1, y2, data);
330
m_dataset.insert(typename dataset_type::value_type(data, rectangle(x1, y1, x2, y2)));
335
template<typename _Key, typename _Data>
336
bool rectangle_set<_Key,_Data>::search(key_type x, key_type y, search_result_type& result)
338
typename outer_type::search_result_type inner_trees;
339
if (!m_outer_segments.is_tree_valid())
340
m_outer_segments.build_tree();
342
if (!m_outer_segments.search(x, inner_trees))
345
typename outer_type::search_result_type::iterator itr_tree = inner_trees.begin(), itr_tree_end = inner_trees.end();
346
for (; itr_tree != itr_tree_end; ++itr_tree)
348
inner_type* inner_tree = *itr_tree;
349
if (!inner_tree->is_tree_valid())
350
inner_tree->build_tree();
352
// Search all relevant inner trees and aggregate results.
353
if (!inner_tree->search(y, result))
359
template<typename _Key, typename _Data>
360
typename rectangle_set<_Key,_Data>::search_result
361
rectangle_set<_Key,_Data>::search(key_type x, key_type y)
363
search_result result;
364
typename outer_type::search_result_type inner_trees;
365
if (!m_outer_segments.is_tree_valid())
366
m_outer_segments.build_tree();
368
if (!m_outer_segments.search(x, inner_trees))
371
typename outer_type::search_result_type::iterator itr_tree = inner_trees.begin(), itr_tree_end = inner_trees.end();
372
for (; itr_tree != itr_tree_end; ++itr_tree)
374
inner_type* inner_tree = *itr_tree;
375
if (!inner_tree->is_tree_valid())
376
inner_tree->build_tree();
378
// Search all relevant inner trees and aggregate results.
379
inner_tree->search(y, result);
384
template<typename _Key, typename _Data>
385
void rectangle_set<_Key,_Data>::remove(data_type* data)
387
typename dataset_type::iterator itr_data = m_dataset.find(data);
388
if (itr_data == m_dataset.end())
389
// The data is not stored in this data structure.
392
const rectangle& rect = itr_data->second;
394
// Find the corresponding inner segment tree for this outer interval.
395
interval_type outer(rect.x1, rect.x2);
396
typename inner_segment_map_type::iterator itr_seg = m_inner_map.find(outer);
397
if (itr_seg == m_inner_map.end())
398
throw general_error("inconsistent internal state: failed to find an internal segment tree for an existing interval.");
400
// Remove data from the inner segment tree.
401
inner_type* inner_tree = itr_seg->second;
402
inner_tree->remove(data);
403
if (inner_tree->empty())
405
// This inner tree is now empty. Erase it.
406
m_outer_segments.remove(inner_tree);
407
m_inner_map.erase(itr_seg);
410
// Remove it from the data set as well.
411
m_dataset.erase(data);
414
template<typename _Key, typename _Data>
415
void rectangle_set<_Key,_Data>::clear()
417
m_outer_segments.clear();
422
template<typename _Key, typename _Data>
423
size_t rectangle_set<_Key,_Data>::size() const
425
return m_dataset.size();
428
template<typename _Key, typename _Data>
429
bool rectangle_set<_Key,_Data>::empty() const
431
return m_dataset.empty();
434
template<typename _Key, typename _Data>
435
void rectangle_set<_Key,_Data>::build_outer_segment_tree()
437
// Re-construct the outer segment tree from the authoritative inner tree
439
typename inner_segment_map_type::iterator itr = m_inner_map.begin(), itr_end = m_inner_map.end();
440
for (; itr != itr_end; ++itr)
442
const interval_type& interval = itr->first;
443
inner_type* tree = itr->second;
444
m_outer_segments.insert(interval.first, interval.second, tree);
449
template<typename _Key, typename _Data>
450
void rectangle_set<_Key,_Data>::dump_rectangles() const
453
cout << "dump rectangles ------------------------------------------------" << endl;
454
if (m_dataset.empty())
456
cout << "No rectangles in the data set." << endl;
460
typename dataset_type::const_iterator itr = m_dataset.begin(), itr_end = m_dataset.end();
461
for (; itr != itr_end; ++itr)
463
const rectangle& rect = itr->second;
464
cout << itr->first->name << ": (x1,y1,x2,y2) = "
465
<< "(" << rect.x1 << "," << rect.y1 << "," << rect.x2 << "," << rect.y2 << ")"
470
template<typename _Key, typename _Data>
471
bool rectangle_set<_Key,_Data>::verify_rectangles(const dataset_type& expected) const
473
if (m_dataset.size() != expected.size())
474
// Data sizes differ.
477
typename dataset_type::const_iterator itr_data = m_dataset.begin(), itr_data_end = m_dataset.end();
478
for (; itr_data != itr_data_end; ++itr_data)
480
const data_type* data = itr_data->first;
481
typename dataset_type::const_iterator itr_test = expected.find(data);
482
if (itr_test == expected.end())
483
// Pointer in one container but not in the other.
486
if (itr_data->second != itr_test->second)
487
// Rectangle positions and/or sizes differ.