1 |
|
---|
2 | /*
|
---|
3 | * The JTS Topology Suite is a collection of Java classes that
|
---|
4 | * implement the fundamental operations required to validate a given
|
---|
5 | * geo-spatial data set to a known topological specification.
|
---|
6 | *
|
---|
7 | * Copyright (C) 2001 Vivid Solutions
|
---|
8 | *
|
---|
9 | * This library is free software; you can redistribute it and/or
|
---|
10 | * modify it under the terms of the GNU Lesser General Public
|
---|
11 | * License as published by the Free Software Foundation; either
|
---|
12 | * version 2.1 of the License, or (at your option) any later version.
|
---|
13 | *
|
---|
14 | * This library is distributed in the hope that it will be useful,
|
---|
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
17 | * Lesser General Public License for more details.
|
---|
18 | *
|
---|
19 | * You should have received a copy of the GNU Lesser General Public
|
---|
20 | * License along with this library; if not, write to the Free Software
|
---|
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
22 | *
|
---|
23 | * For more information, contact:
|
---|
24 | *
|
---|
25 | * Vivid Solutions
|
---|
26 | * Suite #1A
|
---|
27 | * 2328 Government Street
|
---|
28 | * Victoria BC V8T 5G5
|
---|
29 | * Canada
|
---|
30 | *
|
---|
31 | * (250)385-6040
|
---|
32 | * www.vividsolutions.com
|
---|
33 | */
|
---|
34 | package com.vividsolutions.jts.index.quadtree;
|
---|
35 |
|
---|
36 | import java.util.List;
|
---|
37 |
|
---|
38 | import com.vividsolutions.jts.geom.Envelope;
|
---|
39 | import com.vividsolutions.jts.index.ArrayListVisitor;
|
---|
40 | import com.vividsolutions.jts.index.ItemVisitor;
|
---|
41 | import com.vividsolutions.jts.index.SpatialIndex;
|
---|
42 | /**
|
---|
43 | * A Quadtree is a spatial index structure for efficient querying
|
---|
44 | * of 2D rectangles. If other kinds of spatial objects
|
---|
45 | * need to be indexed they can be represented by their
|
---|
46 | * envelopes
|
---|
47 | * <p>
|
---|
48 | * The quadtree structure is used to provide a primary filter
|
---|
49 | * for range rectangle queries. The query() method returns a list of
|
---|
50 | * all objects which <i>may</i> intersect the query rectangle. Note that
|
---|
51 | * it may return objects which do not in fact intersect.
|
---|
52 | * A secondary filter is required to test for exact intersection.
|
---|
53 | * Of course, this secondary filter may consist of other tests besides
|
---|
54 | * intersection, such as testing other kinds of spatial relationships.
|
---|
55 | *
|
---|
56 | * <p>
|
---|
57 | * This implementation does not require specifying the extent of the inserted
|
---|
58 | * items beforehand. It will automatically expand to accomodate any extent
|
---|
59 | * of dataset.
|
---|
60 | * <p>
|
---|
61 | * This data structure is also known as an <i>MX-CIF quadtree</i>
|
---|
62 | * following the usage of Samet and others.
|
---|
63 | *
|
---|
64 | * @version 1.7
|
---|
65 | */
|
---|
66 | public class Quadtree
|
---|
67 | implements SpatialIndex
|
---|
68 | {
|
---|
69 | /**
|
---|
70 | * Ensure that the envelope for the inserted item has non-zero extents.
|
---|
71 | * Use the current minExtent to pad the envelope, if necessary
|
---|
72 | */
|
---|
73 | public static Envelope ensureExtent(Envelope itemEnv, double minExtent)
|
---|
74 | {
|
---|
75 | //The names "ensureExtent" and "minExtent" are misleading -- sounds like
|
---|
76 | //this method ensures that the extents are greater than minExtent.
|
---|
77 | //Perhaps we should rename them to "ensurePositiveExtent" and "defaultExtent".
|
---|
78 | //[Jon Aquino]
|
---|
79 | double minx = itemEnv.getMinX();
|
---|
80 | double maxx = itemEnv.getMaxX();
|
---|
81 | double miny = itemEnv.getMinY();
|
---|
82 | double maxy = itemEnv.getMaxY();
|
---|
83 | // has a non-zero extent
|
---|
84 | if (minx != maxx && miny != maxy) return itemEnv;
|
---|
85 |
|
---|
86 | // pad one or both extents
|
---|
87 | if (minx == maxx) {
|
---|
88 | minx = minx - minExtent / 2.0;
|
---|
89 | maxx = minx + minExtent / 2.0;
|
---|
90 | }
|
---|
91 | if (miny == maxy) {
|
---|
92 | miny = miny - minExtent / 2.0;
|
---|
93 | maxy = miny + minExtent / 2.0;
|
---|
94 | }
|
---|
95 | return new Envelope(minx, maxx, miny, maxy);
|
---|
96 | }
|
---|
97 |
|
---|
98 | private Root root;
|
---|
99 | /**
|
---|
100 |
|
---|
101 | * minExtent is the minimum envelope extent of all items
|
---|
102 | * inserted into the tree so far. It is used as a heuristic value
|
---|
103 | * to construct non-zero envelopes for features with zero X and/or Y extent.
|
---|
104 | * Start with a non-zero extent, in case the first feature inserted has
|
---|
105 | * a zero extent in both directions. This value may be non-optimal, but
|
---|
106 | * only one feature will be inserted with this value.
|
---|
107 | **/
|
---|
108 | private double minExtent = 1.0;
|
---|
109 |
|
---|
110 | /**
|
---|
111 | * Constructs a Quadtree with zero items.
|
---|
112 | */
|
---|
113 | public Quadtree()
|
---|
114 | {
|
---|
115 | root = new Root();
|
---|
116 | }
|
---|
117 |
|
---|
118 |
|
---|
119 | public void insert(Envelope itemEnv, Object item)
|
---|
120 | {
|
---|
121 | collectStats(itemEnv);
|
---|
122 | Envelope insertEnv = ensureExtent(itemEnv, minExtent);
|
---|
123 | root.insert(insertEnv, item);
|
---|
124 | }
|
---|
125 |
|
---|
126 | /**
|
---|
127 | * Removes a single item from the tree.
|
---|
128 | *
|
---|
129 | * @param itemEnv the Envelope of the item to be removed
|
---|
130 | * @param item the item to remove
|
---|
131 | * @return <code>true</code> if the item was found (and thus removed)
|
---|
132 | */
|
---|
133 | public boolean remove(Envelope itemEnv, Object item)
|
---|
134 | {
|
---|
135 | Envelope posEnv = ensureExtent(itemEnv, minExtent);
|
---|
136 | return root.remove(posEnv, item);
|
---|
137 | }
|
---|
138 |
|
---|
139 | /*
|
---|
140 | public List OLDquery(Envelope searchEnv)
|
---|
141 | {
|
---|
142 | /**
|
---|
143 | * the items that are matched are the items in quads which
|
---|
144 | * overlap the search envelope
|
---|
145 | */
|
---|
146 | /*
|
---|
147 | List foundItems = new ArrayList();
|
---|
148 | root.addAllItemsFromOverlapping(searchEnv, foundItems);
|
---|
149 | return foundItems;
|
---|
150 | }
|
---|
151 | */
|
---|
152 |
|
---|
153 | /**
|
---|
154 | * Queries the tree and returns items which may lie in the given search envelope.
|
---|
155 | * Precisely, the items that are returned are all items in the tree
|
---|
156 | * whose envelope <b>may</b> intersect the search Envelope.
|
---|
157 | * Note that some items with non-intersecting envelopes may be returned as well;
|
---|
158 | * the client is responsible for filtering these out.
|
---|
159 | * In most situations there will be many items in the tree which do not
|
---|
160 | * intersect the search envelope and which are not returned - thus
|
---|
161 | * providing improved performance over a simple linear scan.
|
---|
162 | *
|
---|
163 | * @param searchEnv the envelope of the desired query area.
|
---|
164 | * @return a List of items which may intersect the search envelope
|
---|
165 | */
|
---|
166 | public List query(Envelope searchEnv)
|
---|
167 | {
|
---|
168 | /**
|
---|
169 | * the items that are matched are the items in quads which
|
---|
170 | * overlap the search envelope
|
---|
171 | */
|
---|
172 | ArrayListVisitor visitor = new ArrayListVisitor();
|
---|
173 | query(searchEnv, visitor);
|
---|
174 | return visitor.getItems();
|
---|
175 | }
|
---|
176 |
|
---|
177 | /**
|
---|
178 | * Queries the tree and visits items which may lie in the given search envelope.
|
---|
179 | * Precisely, the items that are visited are all items in the tree
|
---|
180 | * whose envelope <b>may</b> intersect the search Envelope.
|
---|
181 | * Note that some items with non-intersecting envelopes may be visited as well;
|
---|
182 | * the client is responsible for filtering these out.
|
---|
183 | * In most situations there will be many items in the tree which do not
|
---|
184 | * intersect the search envelope and which are not visited - thus
|
---|
185 | * providing improved performance over a simple linear scan.
|
---|
186 | *
|
---|
187 | * @param searchEnv the envelope of the desired query area.
|
---|
188 | * @param visitor a visitor object which is passed the visited items
|
---|
189 | */
|
---|
190 | public void query(Envelope searchEnv, ItemVisitor visitor)
|
---|
191 | {
|
---|
192 | /**
|
---|
193 | * the items that are matched are the items in quads which
|
---|
194 | * overlap the search envelope
|
---|
195 | */
|
---|
196 | root.visit(searchEnv, visitor);
|
---|
197 | }
|
---|
198 |
|
---|
199 |
|
---|
200 | private void collectStats(Envelope itemEnv)
|
---|
201 | {
|
---|
202 | double delX = itemEnv.getWidth();
|
---|
203 | if (delX < minExtent && delX > 0.0)
|
---|
204 | minExtent = delX;
|
---|
205 |
|
---|
206 | double delY = itemEnv.getHeight();
|
---|
207 | if (delY < minExtent && delY > 0.0)
|
---|
208 | minExtent = delY;
|
---|
209 | }
|
---|
210 |
|
---|
211 | }
|
---|