|
26 | 26 | import java.util.concurrent.ExecutionException; |
27 | 27 | import java.util.concurrent.TimeUnit; |
28 | 28 | import java.util.concurrent.TimeoutException; |
29 | | -import java.util.stream.IntStream; |
30 | | -import java.util.stream.Stream; |
31 | 29 |
|
32 | 30 | import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; |
33 | 31 | import org.openstreetmap.josm.data.Bounds; |
|
86 | 84 | * @author Taylor Smock |
87 | 85 | */ |
88 | 86 | public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader { |
89 | | - private record TileXYZ(int x, int y, int z) { |
90 | | - /** |
91 | | - * Checks to see if the given bounds are functionally equal to this tile |
92 | | - * |
93 | | - * @param left left |
94 | | - * @param bottom bottom |
95 | | - * @param right right |
96 | | - * @param top top |
97 | | - */ |
98 | | - boolean checkBounds(double left, double bottom, double right, double top) { |
99 | | - final var thisLeft = xToLongitude(this.x, this.z); |
100 | | - final var thisRight = xToLongitude(this.x + 1, this.z); |
101 | | - final var thisBottom = yToLatitude(this.y + 1, this.z); |
102 | | - final var thisTop = yToLatitude(this.y, this.z); |
103 | | - return equalsEpsilon(thisLeft, left, this.z) && equalsEpsilon(thisRight, right, this.z) |
104 | | - && equalsEpsilon(thisBottom, bottom, this.z) && equalsEpsilon(thisTop, top, this.z); |
105 | | - } |
106 | | - |
107 | | - private static boolean equalsEpsilon(double first, double second, int z) { |
108 | | - // 0.1% of tile size is considered to be "equal" |
109 | | - final var maxDiff = (360 / Math.pow(2, z)) / 1000; |
110 | | - final var diff = Math.abs(first - second); |
111 | | - return diff <= maxDiff; |
112 | | - } |
113 | | - |
114 | | - private static double xToLongitude(int x, int z) { |
115 | | - return (x / Math.pow(2, z)) * 360 - 180; |
116 | | - } |
117 | | - |
118 | | - private static double yToLatitude(int y, int z) { |
119 | | - var t = Math.PI - 2 * Math.PI * y / Math.pow(2, z); |
120 | | - return 180 / Math.PI * Math.atan((Math.exp(t) - Math.exp(-t)) / 2); |
121 | | - } |
122 | | - |
123 | | - /** |
124 | | - * Convert bounds to tiles |
125 | | - * |
126 | | - * @param zoom The zoom level to use |
127 | | - * @param bounds The bounds to convert to tiles |
128 | | - * @return A stream of tiles for the bounds at the given zoom level |
129 | | - */ |
130 | | - private static Stream<TileXYZ> tilesFromBBox(int zoom, Bounds bounds) { |
131 | | - final var left = bounds.getMinLon(); |
132 | | - final var bottom = bounds.getMinLat(); |
133 | | - final var right = bounds.getMaxLon(); |
134 | | - final var top = bounds.getMaxLat(); |
135 | | - final var tile1 = tileFromLatLonZoom(left, bottom, zoom); |
136 | | - final var tile2 = tileFromLatLonZoom(right, top, zoom); |
137 | | - return IntStream.rangeClosed(tile1.x, tile2.x) |
138 | | - .mapToObj(x -> IntStream.rangeClosed(tile2.y, tile1.y).mapToObj(y -> new TileXYZ(x, y, zoom))) |
139 | | - .flatMap(stream -> stream); |
140 | | - } |
141 | | - |
142 | | - /** |
143 | | - * Checks to see if the given bounds are functionally equal to this tile |
144 | | - * |
145 | | - * @param left left lon |
146 | | - * @param bottom bottom lat |
147 | | - * @param right right lon |
148 | | - * @param top top lat |
149 | | - */ |
150 | | - private static TileXYZ tileFromBBox(double left, double bottom, double right, double top) { |
151 | | - var zoom = 18; |
152 | | - while (zoom > 0) { |
153 | | - final var tile1 = tileFromLatLonZoom(left, bottom, zoom); |
154 | | - final var tile2 = tileFromLatLonZoom(right, top, zoom); |
155 | | - if (tile1.equals(tile2)) { |
156 | | - return tile1; |
157 | | - } else if (tile1.checkBounds(left, bottom, right, top)) { |
158 | | - return tile1; |
159 | | - } else if (tile2.checkBounds(left, bottom, right, top)) { |
160 | | - return tile2; |
161 | | - // Just in case the coordinates are _barely_ in other tiles and not the "common" |
162 | | - // tile |
163 | | - } else if (Math.abs(tile1.x() - tile2.x()) <= 2 && Math.abs(tile1.y() - tile2.y()) <= 2) { |
164 | | - final var tileT = new TileXYZ((tile1.x() + tile2.x()) / 2, (tile1.y() + tile2.y()) / 2, zoom); |
165 | | - if (tileT.checkBounds(left, bottom, right, top)) { |
166 | | - return tileT; |
167 | | - } |
168 | | - } |
169 | | - zoom--; |
170 | | - } |
171 | | - return new TileXYZ(0, 0, 0); |
172 | | - } |
173 | | - |
174 | | - private static TileXYZ tileFromLatLonZoom(double lon, double lat, int zoom) { |
175 | | - var xCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom) * (180 + lon) / 360))); |
176 | | - var yCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom) |
177 | | - * (1 - (Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI)) |
178 | | - / 2))); |
179 | | - return new TileXYZ(xCoordinate, yCoordinate, zoom); |
180 | | - } |
181 | | - |
182 | | - /** |
183 | | - * Extends a bounds object to contain this tile |
184 | | - * |
185 | | - * @param currentBounds The bounds to extend |
186 | | - */ |
187 | | - private void expandBounds(Bounds currentBounds) { |
188 | | - final var thisLeft = xToLongitude(this.x, this.z); |
189 | | - final var thisRight = xToLongitude(this.x + 1, this.z); |
190 | | - final var thisBottom = yToLatitude(this.y + 1, this.z); |
191 | | - final var thisTop = yToLatitude(this.y, this.z); |
192 | | - currentBounds.extend(thisBottom, thisLeft); |
193 | | - currentBounds.extend(thisTop, thisRight); |
194 | | - } |
195 | | - } |
196 | | - |
197 | 87 | private final String url; |
198 | 88 | private final boolean crop; |
199 | 89 | private final int start; |
|
0 commit comments