Skip to content

Commit cdf51cf

Browse files
committed
Add USGS National Map Tile Layer
1 parent b71ea2e commit cdf51cf

File tree

3 files changed

+288
-1
lines changed

3 files changed

+288
-1
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package geoscript.layer
2+
3+
/**
4+
* A USGS National Map ImageTileLayer that is read only.
5+
* @author Jared Erickson
6+
*/
7+
class USGSTileLayer extends ImageTileLayer {
8+
9+
/**
10+
* The base url
11+
*/
12+
private final String baseUrl
13+
14+
/**
15+
* The global web mercator Pyramid
16+
*/
17+
private Pyramid pyramid
18+
19+
/**
20+
* Create a new USGS ImageTileLayer
21+
* @param name The name
22+
* @param baseUrl The base URL
23+
*/
24+
USGSTileLayer(String name, String baseUrl) {
25+
this.name = name
26+
this.baseUrl = baseUrl
27+
this.pyramid = Pyramid.createGlobalMercatorPyramid()
28+
this.pyramid.origin = Pyramid.Origin.TOP_LEFT
29+
this.bounds = pyramid.bounds
30+
this.proj = pyramid.proj
31+
}
32+
33+
/**
34+
* Get the Pyramid
35+
* @return The Pyramid
36+
*/
37+
@Override
38+
Pyramid getPyramid() {
39+
this.pyramid
40+
}
41+
42+
/**
43+
* Get a Tile
44+
* @param z The zoom level
45+
* @param x The column
46+
* @param y The row
47+
* @return A Tile
48+
*/
49+
@Override
50+
ImageTile get(long z, long x, long y) {
51+
ImageTile tile = new ImageTile(z, x, y)
52+
URL url = new URL("${baseUrl}${baseUrl.endsWith("/") ? '' : '/'}${z}/${y}/${x}")
53+
URLConnection urlConnection = url.openConnection()
54+
urlConnection.setRequestProperty("User-Agent", "GeoScript Groovy")
55+
InputStream inputStream = urlConnection.inputStream
56+
try {
57+
tile.data = inputStream.bytes
58+
} finally {
59+
inputStream.close()
60+
}
61+
tile
62+
}
63+
64+
/**
65+
* Add a Tile
66+
* @param t The Tile
67+
*/
68+
@Override
69+
void put(ImageTile t) {
70+
throw new IllegalArgumentException("OSM is ready only!")
71+
}
72+
73+
/**
74+
* Delete a Tile
75+
* @param t The Tile
76+
*/
77+
@Override
78+
void delete(ImageTile t) {
79+
throw new IllegalArgumentException("OSM is ready only!")
80+
}
81+
82+
/**
83+
* Close the TileLayer
84+
*/
85+
@Override
86+
void close() throws IOException {
87+
// Do nothing
88+
}
89+
90+
static USGSTileLayer createTopo() {
91+
new USGSTileLayer("USGSTopo","https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile")
92+
}
93+
94+
static USGSTileLayer createShadedRelief() {
95+
new USGSTileLayer("USGSShadedRelief","https://basemap.nationalmap.gov/arcgis/rest/services/USGSShadedReliefOnly/MapServer/tile")
96+
}
97+
98+
static USGSTileLayer createImagery() {
99+
new USGSTileLayer("USGSImagery", "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile")
100+
}
101+
102+
static USGSTileLayer createImageryTopo() {
103+
new USGSTileLayer("USGSImageryTopo","https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile")
104+
}
105+
106+
static USGSTileLayer createHydro() {
107+
new USGSTileLayer("USGSHydro","https://basemap.nationalmap.gov/arcgis/rest/services/USGSHydroCached/MapServer/tile")
108+
}
109+
110+
/**
111+
* Get a USGS ImageTileLayer with a well known name.
112+
* @param name The well known name
113+
* @return A USGS ImageTileLayer or null
114+
*/
115+
static USGSTileLayer getWellKnown(String name) {
116+
if (!name) {
117+
null
118+
} else if (name.equalsIgnoreCase("usgs-topo")) {
119+
createTopo()
120+
} else if (name.equalsIgnoreCase("usgs-shadedrelief")) {
121+
createShadedRelief()
122+
} else if (name.equalsIgnoreCase("usgs-imagery")) {
123+
createImagery()
124+
} else if (name.equalsIgnoreCase("usgs-imagerytopo")) {
125+
createImageryTopo()
126+
} else if (name.equalsIgnoreCase("usgs-hydro")) {
127+
createHydro()
128+
}
129+
}
130+
131+
/**
132+
* The USGS TileLayerFactory
133+
*/
134+
static class Factory extends TileLayerFactory<USGSTileLayer> {
135+
136+
@Override
137+
USGSTileLayer create(String paramsStr) {
138+
Map params = [:]
139+
if (paramsStr in ['usgs-topo', 'usgs-shadedrelief', 'usgs-imagery', 'usgs-imagerytopo', 'usgs-hydro']) {
140+
params["type"] = "usgs"
141+
params["name"] = paramsStr
142+
create(params)
143+
} else {
144+
super.create(paramsStr)
145+
}
146+
}
147+
148+
@Override
149+
USGSTileLayer create(Map params) {
150+
String type = params.get("type","").toString()
151+
if (type.equalsIgnoreCase("usgs")) {
152+
String name = params.get("name", "USGS")
153+
if (params.get("url")) {
154+
String baseUrl = params.get("url")
155+
new USGSTileLayer(name, baseUrl)
156+
}
157+
else if (USGSTileLayer.getWellKnown(name)) {
158+
USGSTileLayer.getWellKnown(name)
159+
}
160+
} else {
161+
null
162+
}
163+
}
164+
165+
@Override
166+
TileRenderer getTileRenderer(Map options, TileLayer tileLayer, List<Layer> layers) {
167+
null
168+
}
169+
}
170+
171+
}

src/main/resources/META-INF/services/geoscript.layer.TileLayerFactory

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ geoscript.layer.OSM$Factory
44
geoscript.layer.TMS$Factory
55
geoscript.layer.UTFGrid$Factory
66
geoscript.layer.VectorTiles$Factory
7-
geoscript.layer.DBTiles$Factory
7+
geoscript.layer.DBTiles$Factory
8+
geoscript.layer.USGSTileLayer$Factory
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package geoscript.layer
2+
3+
import geoscript.ServerTestUtil
4+
import okhttp3.HttpUrl
5+
import okhttp3.mockwebserver.MockResponse
6+
import okhttp3.mockwebserver.MockWebServer
7+
import org.junit.jupiter.api.Test
8+
9+
import static org.junit.jupiter.api.Assertions.*
10+
11+
/**
12+
* The USGSTileLayer Unit Test
13+
* @author Jared Erickson
14+
*/
15+
class USGSTileLayerTest {
16+
17+
@Test
18+
void getName() {
19+
USGSTileLayer usgs = USGSTileLayer.createImagery()
20+
assertEquals "USGSImagery", usgs.name
21+
}
22+
23+
@Test
24+
void getWellKnown() {
25+
USGSTileLayer usgs = USGSTileLayer.getWellKnown("usgs-topo")
26+
assertEquals "USGSTopo", usgs.name
27+
usgs = USGSTileLayer.getWellKnown("usgs-shadedrelief")
28+
assertEquals "USGSShadedRelief", usgs.name
29+
usgs = USGSTileLayer.getWellKnown("usgs-imagery")
30+
assertEquals "USGSImagery", usgs.name
31+
usgs = USGSTileLayer.getWellKnown("usgs-imagerytopo")
32+
assertEquals "USGSImageryTopo", usgs.name
33+
usgs = USGSTileLayer.getWellKnown("usgs-hydro")
34+
assertEquals "USGSHydro", usgs.name
35+
assertNull USGSTileLayer.getWellKnown("N/A")
36+
assertNull USGSTileLayer.getWellKnown("")
37+
assertNull USGSTileLayer.getWellKnown(null)
38+
}
39+
40+
@Test
41+
void getTileLayerFromMap() {
42+
USGSTileLayer usgs = TileLayer.getTileLayer([type: 'usgs', name: 'usgs-topo'])
43+
assertEquals 'USGSTopo', usgs.name
44+
usgs = TileLayer.getTileLayer([type: 'usgs', name: 'usgs-shadedrelief'])
45+
assertEquals 'USGSShadedRelief', usgs.name
46+
usgs = TileLayer.getTileLayer([type: 'usgs', name: 'usgs-imagery'])
47+
assertEquals 'USGSImagery', usgs.name
48+
usgs = TileLayer.getTileLayer([type: 'usgs', name: 'usgs-imagerytopo'])
49+
assertEquals 'USGSImageryTopo', usgs.name
50+
usgs = TileLayer.getTileLayer([type: 'usgs', name: 'usgs-hydro'])
51+
assertEquals 'USGSHydro', usgs.name
52+
usgs = TileLayer.getTileLayer([type: 'usgs', url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile'])
53+
assertEquals "USGS", usgs.name
54+
}
55+
56+
@Test
57+
void getTileLayerFromString() {
58+
USGSTileLayer usgs = TileLayer.getTileLayer("type=usgs name=usgs-topo")
59+
assertEquals 'USGSTopo', usgs.name
60+
usgs = TileLayer.getTileLayer("type=usgs name=usgs-shadedrelief")
61+
assertEquals 'USGSShadedRelief', usgs.name
62+
usgs = TileLayer.getTileLayer("type=usgs name=usgs-imagery")
63+
assertEquals 'USGSImagery', usgs.name
64+
usgs = TileLayer.getTileLayer("type=usgs name=usgs-imagerytopo")
65+
assertEquals 'USGSImageryTopo', usgs.name
66+
usgs = TileLayer.getTileLayer("type=usgs name=usgs-hydro")
67+
assertEquals 'USGSHydro', usgs.name
68+
usgs = TileLayer.getTileLayer("type=usgs url=http://a.tile.stamen.com/toner-lite")
69+
assertEquals "USGS", usgs.name
70+
}
71+
72+
@Test
73+
void getTile() {
74+
ServerTestUtil.withServer { MockWebServer server ->
75+
server.enqueue(new MockResponse().setBody(ServerTestUtil.fileToBytes(ServerTestUtil.getResource("0.png"))))
76+
server.start()
77+
HttpUrl url = server.url("")
78+
79+
USGSTileLayer usgs = new USGSTileLayer("USGSTileLayer", url.url().toString())
80+
Tile tile = usgs.get(1, 2, 3)
81+
assertEquals 1, tile.z
82+
assertEquals 2, tile.x
83+
assertEquals 3, tile.y
84+
assertNotNull tile.data
85+
86+
assertEquals("/1/3/2", server.takeRequest().getPath())
87+
}
88+
}
89+
90+
@Test
91+
void getTiles() {
92+
ServerTestUtil.withServer { MockWebServer server ->
93+
server.enqueue(new MockResponse().setBody(ServerTestUtil.fileToBytes(ServerTestUtil.getResource("0.png"))))
94+
server.enqueue(new MockResponse().setBody(ServerTestUtil.fileToBytes(ServerTestUtil.getResource("0.png"))))
95+
server.enqueue(new MockResponse().setBody(ServerTestUtil.fileToBytes(ServerTestUtil.getResource("0.png"))))
96+
server.enqueue(new MockResponse().setBody(ServerTestUtil.fileToBytes(ServerTestUtil.getResource("0.png"))))
97+
server.start()
98+
HttpUrl url = server.url("")
99+
100+
USGSTileLayer usgs = new USGSTileLayer("USGSTileLayer", url.url().toString())
101+
TileCursor c = usgs.tiles(1)
102+
c.each { Tile t ->
103+
assertTrue t.z == 1
104+
assertTrue t.x in [0l, 1l]
105+
assertTrue t.y in [0l, 1l]
106+
assertNotNull t.data
107+
}
108+
assertEquals("/1/0/0", server.takeRequest().getPath())
109+
assertEquals("/1/0/1", server.takeRequest().getPath())
110+
assertEquals("/1/1/0", server.takeRequest().getPath())
111+
assertEquals("/1/1/1", server.takeRequest().getPath())
112+
}
113+
}
114+
115+
}

0 commit comments

Comments
 (0)