Statistics
| Revision:

root / trunk / libraries / libTopology / src / org / gvsig / spatialindex / b2dtree / KDNode.java @ 21250

History | View | Annotate | Download (7.02 KB)

1
package org.gvsig.spatialindex.b2dtree;
2

    
3
import java.util.Vector;
4

    
5

    
6
// K-D Tree node class
7

    
8
class KDNode {
9

    
10
    // these are seen by KDTree
11
    protected HPoint k;
12
    Object v;
13
    protected KDNode left, right;
14
    protected boolean deleted;
15

    
16
    // Method ins translated from 352.ins.c of Gonnet & Baeza-Yates
17
    protected static KDNode ins(HPoint key, Object val, KDNode t, int lev, 
18
                                int K)         throws KeyDuplicateException {
19
        
20
        if (t == null) {
21
            t = new KDNode(key, val);
22
        }
23
        
24
        else if (key.equals(t.k)) {
25

    
26
            // "re-insert"
27
            if (t.deleted) {
28
                t.deleted = false;
29
                t.v = val;
30
            }
31

    
32
            else {
33
                throw new KeyDuplicateException();
34
            }
35
        }
36

    
37
        else if (key.coord[lev] > t.k.coord[lev]) {
38
            t.right = ins(key, val, t.right, (lev+1)%K, K);
39
        }
40
        else {
41
            t.left = ins(key, val, t.left, (lev+1)%K, K);
42
        }
43
        
44
        return t;
45
    }
46

    
47

    
48
    // Method srch translated from 352.srch.c of Gonnet & Baeza-Yates
49
    protected static KDNode srch(HPoint key, KDNode t, int K) {
50

    
51
        for (int lev=0; t!=null; lev=(lev+1)%K) {
52

    
53
            if (!t.deleted && key.equals(t.k)) {
54
                return t;
55
            }
56
            else if (key.coord[lev] > t.k.coord[lev]) {
57
                t = t.right;
58
            }
59
            else {
60
                t = t.left;
61
            }
62
        }
63

    
64
        return null;
65
    }
66

    
67
    // Method rsearch translated from 352.range.c of Gonnet & Baeza-Yates
68
    protected static void rsearch(HPoint lowk, HPoint uppk, KDNode t, int lev,
69
                                  int K, Vector v) {
70

    
71
        if (t == null) return;
72
        if (lowk.coord[lev] <= t.k.coord[lev]) {
73
            rsearch(lowk, uppk, t.left, (lev+1)%K, K, v);
74
        }
75
        int j;
76
        for (j=0; j<K && lowk.coord[j]<=t.k.coord[j] && 
77
                 uppk.coord[j]>=t.k.coord[j]; j++) 
78
            ;
79
        if (j==K) v.add(t);
80
        if (uppk.coord[lev] > t.k.coord[lev]) {
81
            rsearch(lowk, uppk, t.right, (lev+1)%K, K, v);
82
        }
83
    }
84

    
85
    // Method Nearest Neighbor from Andrew Moore's thesis. Numbered
86
    // comments are direct quotes from there. Step "SDL" is added to
87
    // make the algorithm work correctly.  NearestNeighborList solution
88
    // courtesy of Bjoern Heckel.
89
   protected static void nnbr(KDNode kd, HPoint target, HRect hr,
90
                              double max_dist_sqd, int lev, int K,
91
                              NearestNeighborList nnl) {
92

    
93
       // 1. if kd is empty then set dist-sqd to infinity and exit.
94
       if (kd == null) {
95
           return;
96
       }
97

    
98
       // 2. s := split field of kd
99
       int s = lev % K;
100

    
101
       // 3. pivot := dom-elt field of kd
102
       HPoint pivot = kd.k;
103
       double pivot_to_target = HPoint.sqrdist(pivot, target);
104

    
105
       // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
106
       //    The cut plane is through pivot and perpendicular to the s
107
       //    dimension.
108
       HRect left_hr = hr; // optimize by not cloning
109
       HRect right_hr = (HRect) hr.clone();
110
       left_hr.max.coord[s] = pivot.coord[s];
111
       right_hr.min.coord[s] = pivot.coord[s];
112

    
113
       // 5. target-in-left := target_s <= pivot_s
114
       boolean target_in_left = target.coord[s] < pivot.coord[s];
115

    
116
       KDNode nearer_kd;
117
       HRect nearer_hr;
118
       KDNode further_kd;
119
       HRect further_hr;
120

    
121
       // 6. if target-in-left then
122
       //    6.1. nearer-kd := left field of kd and nearer-hr := left-hr
123
       //    6.2. further-kd := right field of kd and further-hr := right-hr
124
       if (target_in_left) {
125
           nearer_kd = kd.left;
126
           nearer_hr = left_hr;
127
           further_kd = kd.right;
128
           further_hr = right_hr;
129
       }
130
       //
131
       // 7. if not target-in-left then
132
       //    7.1. nearer-kd := right field of kd and nearer-hr := right-hr
133
       //    7.2. further-kd := left field of kd and further-hr := left-hr
134
       else {
135
           nearer_kd = kd.right;
136
           nearer_hr = right_hr;
137
           further_kd = kd.left;
138
           further_hr = left_hr;
139
       }
140

    
141
       // 8. Recursively call Nearest Neighbor with paramters
142
       //    (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
143
       //    results in nearest and dist-sqd
144
       nnbr(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl);
145

    
146
       KDNode nearest = (KDNode) nnl.getHighest();
147
       double dist_sqd;
148

    
149
       if (!nnl.isCapacityReached()) {
150
           dist_sqd = Double.MAX_VALUE;
151
       }
152
       else {
153
           dist_sqd = nnl.getMaxPriority();
154
       }
155

    
156
       // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
157
       max_dist_sqd = Math.min(max_dist_sqd, dist_sqd);
158

    
159
       // 10. A nearer point could only lie in further-kd if there were some
160
       //     part of further-hr within distance sqrt(max-dist-sqd) of
161
       //     target.  If this is the case then
162
       HPoint closest = further_hr.closest(target);
163
       if (HPoint.eucdist(closest, target) < Math.sqrt(max_dist_sqd)) {
164

    
165
           // 10.1 if (pivot-target)^2 < dist-sqd then
166
           if (pivot_to_target < dist_sqd) {
167

    
168
               // 10.1.1 nearest := (pivot, range-elt field of kd)
169
               nearest = kd;
170

    
171
               // 10.1.2 dist-sqd = (pivot-target)^2
172
               dist_sqd = pivot_to_target;
173

    
174
               // add to nnl
175
               if (!kd.deleted) {
176
                   nnl.insert(kd, dist_sqd);
177
               }
178

    
179
               // 10.1.3 max-dist-sqd = dist-sqd
180
               // max_dist_sqd = dist_sqd;
181
               if (nnl.isCapacityReached()) {
182
                   max_dist_sqd = nnl.getMaxPriority();
183
               }
184
               else {
185
                   max_dist_sqd = Double.MAX_VALUE;
186
               }
187
           }
188

    
189
           // 10.2 Recursively call Nearest Neighbor with parameters
190
           //      (further-kd, target, further-hr, max-dist_sqd),
191
           //      storing results in temp-nearest and temp-dist-sqd
192
           nnbr(further_kd, target, further_hr, max_dist_sqd, lev + 1, K, nnl);
193
           KDNode temp_nearest = (KDNode) nnl.getHighest();
194
           double temp_dist_sqd = nnl.getMaxPriority();
195

    
196
           // 10.3 If tmp-dist-sqd < dist-sqd then
197
           if (temp_dist_sqd < dist_sqd) {
198

    
199
               // 10.3.1 nearest := temp_nearest and dist_sqd := temp_dist_sqd
200
               nearest = temp_nearest;
201
               dist_sqd = temp_dist_sqd;
202
           }
203
       }
204

    
205
       // SDL: otherwise, current point is nearest
206
       else if (pivot_to_target < max_dist_sqd) {
207
           nearest = kd;
208
           dist_sqd = pivot_to_target;
209
       }
210
   }
211

    
212

    
213
    // constructor is used only by class; other methods are static
214
    private KDNode(HPoint key, Object val) {
215
        
216
        k = key;
217
        v = val;
218
        left = null;
219
        right = null;
220
        deleted = false;
221
    }
222

    
223
    protected String toString(int depth) {
224
        String s = k + "  " + v + (deleted ? "*" : "");
225
        if (left != null) {
226
            s = s + "\n" + pad(depth) + "L " + left.toString(depth+1);
227
        }
228
        if (right != null) {
229
            s = s + "\n" + pad(depth) + "R " + right.toString(depth+1);
230
        }
231
        return s;
232
    }
233

    
234
    private static String pad(int n) {
235
        String s = "";
236
        for (int i=0; i<n; ++i) {
237
            s += " ";
238
        }
239
        return s;
240
    }
241

    
242
    private static void hrcopy(HRect hr_src, HRect hr_dst) {
243
        hpcopy(hr_src.min, hr_dst.min);
244
        hpcopy(hr_src.max, hr_dst.max);
245
    }
246

    
247
    private static void hpcopy(HPoint hp_src, HPoint hp_dst) {
248
        for (int i=0; i<hp_dst.coord.length; ++i) {
249
            hp_dst.coord[i] = hp_src.coord[i];
250
        }
251
    }
252
}