- Timestamp:
- 2023-11-22T15:38:23+01:00 (12 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/GeoPropertyIndex.java
r17465 r18903 2 2 package org.openstreetmap.josm.tools; 3 3 4 import java.util.Collection; 5 6 import org.openstreetmap.josm.data.coor.ILatLon; 4 7 import org.openstreetmap.josm.data.coor.LatLon; 5 8 import org.openstreetmap.josm.data.osm.BBox; … … 7 10 /** 8 11 * Fast index to look up properties of the earth surface. 9 * 12 * <p> 10 13 * It is expected that there is a relatively slow method to look up the property 11 14 * for a certain coordinate and that there are larger areas with a uniform 12 15 * property. 13 * 16 * <p> 14 17 * This index tries to find rectangles with uniform property and caches them. 15 18 * Rectangles are subdivided, if there are different properties within. … … 80 83 if (isInside(ll)) 81 84 return getBounded(ll); 82 if (DEBUG) System.err.print("up["+level+"]");85 if (DEBUG) Logging.trace("up[{0}]", level); 83 86 return parent != null ? parent.get(ll) : null; 84 87 } 85 88 86 89 private T getBounded(LatLon ll) { 87 if (DEBUG) System.err.print("GPLevel["+level+"]"+bbox+" ");90 if (DEBUG) Logging.trace("GPLevel[{0}]{1}", level, bbox); 88 91 if (!isInside(ll)) { 89 92 throw new AssertionError("Point "+ll+" should be inside "+bbox); 90 93 } 91 94 if (val != null) { 92 if (DEBUG) System.err.println(" hit! "+val);95 if (DEBUG) Logging.trace("GPLevel[{0}]{1} hit! {2}", level, bbox, val); 93 96 owner.lastLevelUsed = this; 94 97 return val; 95 98 } 96 99 if (level >= owner.maxLevel) { 97 if (DEBUG) System.err.println(" max level reached !");100 if (DEBUG) Logging.trace("GPLevel[{0}]{1} max level reached !", level, bbox); 98 101 return owner.geoProp.get(ll); 99 102 } 100 103 101 if (children == null) { 102 @SuppressWarnings("unchecked") 103 GPLevel<T>[] tmp = new GPLevel[4]; 104 this.children = tmp; 105 } 104 GPLevel<T>[] currentChildren = this.getChildren(); 106 105 107 106 LatLon center = bbox.getCenter(); 108 107 for (int idx = 0; idx < 4; idx++) { 109 108 BBox testBBox = null; 110 if (c hildren[idx] != null)111 testBBox = c hildren[idx].bbox;109 if (currentChildren[idx] != null) 110 testBBox = currentChildren[idx].bbox; 112 111 113 112 if (testBBox == null) { 114 double lon1, lat1; 115 switch (idx) { 116 case 0: 117 lon1 = bbox.getTopLeftLon(); 118 lat1 = bbox.getBottomRightLat(); 119 break; 120 case 1: 121 lon1 = bbox.getTopLeftLon(); 122 lat1 = bbox.getTopLeftLat(); 123 break; 124 case 2: 125 lon1 = bbox.getBottomRightLon(); 126 lat1 = bbox.getBottomRightLat(); 127 break; 128 case 3: 129 lon1 = bbox.getBottomRightLon(); 130 lat1 = bbox.getTopLeftLat(); 131 break; 132 default: 133 throw new AssertionError(); 134 } 135 testBBox = new BBox(lon1, lat1, center.lon(), center.lat()); 113 testBBox = generateTestBBox(idx, center.lon(), center.lat()); 136 114 } 137 115 if (isInside(testBBox, ll)) { 138 if (children[idx] == null) { 139 if (DEBUG) System.err.println(" - new with idx "+idx); 140 children[idx] = new GPLevel<>(level + 1, testBBox, this, owner); 141 } 142 return children[idx].getBounded(ll); 116 generateChild(currentChildren, testBBox, idx); 117 return currentChildren[idx].getBounded(ll); 143 118 } 144 119 } 145 120 throw new AssertionError("Point "+ll+" should be inside one of the children of "+bbox); 121 } 122 123 /** 124 * Generate the bbox for the specified index in the {@link #getChildren()} array 125 * @param idx The index in the {@link #getChildren()} array 126 * @param lon2 The longitude of the center of the previous level 127 * @param lat2 The latitude of the center of the previous level 128 * @return The test bbox for the specified index in the {@link #getChildren()} array 129 */ 130 private BBox generateTestBBox(int idx, double lon2, double lat2) { 131 double lon1; 132 double lat1; 133 switch (idx) { 134 case 0: 135 lon1 = bbox.getTopLeftLon(); 136 lat1 = bbox.getBottomRightLat(); 137 break; 138 case 1: 139 lon1 = bbox.getTopLeftLon(); 140 lat1 = bbox.getTopLeftLat(); 141 break; 142 case 2: 143 lon1 = bbox.getBottomRightLon(); 144 lat1 = bbox.getBottomRightLat(); 145 break; 146 case 3: 147 lon1 = bbox.getBottomRightLon(); 148 lat1 = bbox.getTopLeftLat(); 149 break; 150 default: 151 throw new AssertionError(); 152 } 153 return new BBox(lon1, lat1, lon2, lat2); 154 } 155 156 /** 157 * Safely generate the child in a multi-threaded environment 158 * @param currentChildren The children array to check 159 * @param testBBox The current bbox (will be used to create the new {@link GPLevel}) 160 * @param idx The index in the child array 161 */ 162 private synchronized void generateChild(GPLevel<T>[] currentChildren, BBox testBBox, int idx) { 163 if (currentChildren[idx] == null) { 164 if (DEBUG) Logging.trace("GPLevel[{0}]{1} - new with idx {2}", level, bbox, idx); 165 currentChildren[idx] = new GPLevel<>(level + 1, testBBox, this, owner); 166 } 167 } 168 169 /** 170 * Get the children array safely in a multi-threaded environment. 171 * If this ends up being a performance issue, look up the "immutable" double-checked locking idiom. 172 * Just be certain you have a good test when checking the performance differences. 173 * See #23309/#23036. The issue there is that {@link Territories#getRegionalTaginfoUrls(LatLon)} 174 * uses a {@link Collection#parallelStream}. 175 * @return The children array (sw, nw, se, ne) 176 */ 177 private synchronized GPLevel<T>[] getChildren() { 178 GPLevel<T>[] currentChildren = this.children; 179 if (currentChildren == null) { 180 @SuppressWarnings("unchecked") 181 GPLevel<T>[] tmp = new GPLevel[4]; 182 currentChildren = tmp; 183 this.children = currentChildren; 184 } 185 return currentChildren; 146 186 } 147 187 … … 153 193 * @return true, if it is inside of the box 154 194 */ 155 boolean isInside( LatLon ll) {195 boolean isInside(ILatLon ll) { 156 196 return isInside(bbox, ll); 157 197 } … … 165 205 * @return true, if it is inside of the box 166 206 */ 167 boolean isInside(BBox bbox, LatLon ll) {207 boolean isInside(BBox bbox, ILatLon ll) { 168 208 return bbox.getTopLeftLon() <= ll.lon() && 169 209 (ll.lon() < bbox.getBottomRightLon() || (ll.lon() == 180.0 && bbox.getBottomRightLon() == 180.0)) &&
Note:
See TracChangeset
for help on using the changeset viewer.