1 // Copyright 2013 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 // Original Author: ericv@google.com (Eric Veach)
17 // Converted to D:  madric@gmail.com (Vijay Nayar)
18 
19 module s2.shapeutil.range_iterator;
20 
21 import s2.s2cell_id;
22 import s2.s2shape_index;
23 
24 // RangeIterator is a wrapper over S2ShapeIndex::Iterator with extra methods
25 // that are useful for merging the contents of two or more S2ShapeIndexes.
26 class RangeIterator {
27 private:
28   // Updates internal state after the iterator has been repositioned.
29   void refresh() {
30     _rangeMin = id().rangeMin();
31     _rangeMax = id().rangeMax();
32   }
33 
34   S2ShapeIndex.Iterator _it;
35   S2CellId _rangeMin, _rangeMax;
36 
37 public:
38   // Construct a new RangeIterator positioned at the first cell of the index.
39   this(S2ShapeIndex index) {
40     _it = new S2ShapeIndex.Iterator(index, S2ShapeIndex.InitialPosition.BEGIN);
41     refresh();
42   }
43 
44   // The current S2CellId and cell contents.
45   S2CellId id() const {
46     return _it.id();
47   }
48 
49   const(S2ShapeIndexCell) cell() const {
50     return _it.cell();
51   }
52 
53   // The min and max leaf cell ids covered by the current cell.  If done() is
54   // true, these methods return a value larger than any valid cell id.
55   S2CellId rangeMin() const {
56     return _rangeMin;
57   }
58   S2CellId rangeMax() const {
59     return _rangeMax;
60   }
61 
62   void next() {
63     _it.next();
64     refresh();
65   }
66 
67   bool done() {
68     return _it.done();
69   }
70 
71   // Position the iterator at the first cell that overlaps or follows
72   // "target", i.e. such that range_max() >= target.range_min().
73   void seekTo(in RangeIterator target) {
74     _it.seek(target.rangeMin());
75     // If the current cell does not overlap "target", it is possible that the
76     // previous cell is the one we are looking for.  This can only happen when
77     // the previous cell contains "target" but has a smaller S2CellId.
78     if (_it.done() || _it.id().rangeMin() > target.rangeMax()) {
79       if (_it.prev() && _it.id().rangeMax() < target.id()) _it.next();
80     }
81     refresh();
82   }
83 
84   // Position the iterator at the first cell that follows "target", i.e. the
85   // first cell such that range_min() > target.range_max().
86   void seekBeyond(in RangeIterator target) {
87     _it.seek(target.rangeMax().next());
88     if (!_it.done() && _it.id().rangeMin() <= target.rangeMax()) {
89       _it.next();
90     }
91     refresh();
92   }
93 
94 }