/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2016, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.geopkg; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.net.URL; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Set; import java.util.TimeZone; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.geotools.TestData; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.data.DataUtilities; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; import org.geotools.data.memory.MemoryFeatureCollection; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.data.simple.SimpleFeatureReader; import org.geotools.data.simple.SimpleFeatureWriter; import org.geotools.factory.CommonFactoryFinder; import org.geotools.factory.Hints; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geometry.jts.Geometries; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.geopkg.mosaic.GeoPackageFormat; import org.geotools.geopkg.mosaic.GeoPackageReader; import org.geotools.image.test.ImageAssert; import org.geotools.parameter.Parameter; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.sql.SqlUtil; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.PropertyDescriptor; import org.opengis.filter.FilterFactory; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.PrecisionModel; import org.opengis.parameter.GeneralParameterValue; import org.opengis.referencing.FactoryException; import javax.imageio.ImageIO; import javax.media.jai.PlanarImage; public class GeoPackageTest { GeoPackage geopkg; @BeforeClass public static void setUpOnce() { Hints.putSystemDefault(Hints.COMPARISON_TOLERANCE, 1e-9); } @Before public void setUp() throws Exception { geopkg = new GeoPackage(File.createTempFile("geopkg", "db", new File("target"))); geopkg.init(); } @After public void tearDown() throws Exception { geopkg.close(); //for debugging, copy the current geopackage file to a well known file File f = new File("target", "geopkg.db"); if (f.exists()) { f.delete(); } FileUtils.copyFile(geopkg.getFile(), f); } @Test public void testInit() throws Exception { assertTableExists("gpkg_contents"); assertTableExists("gpkg_geometry_columns"); assertTableExists("gpkg_spatial_ref_sys"); assertDefaultSpatialReferencesExist(); assertApplicationId(); } void assertDefaultSpatialReferencesExist() throws Exception { Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement(); try { ResultSet rs = st.executeQuery("SELECT srs_id FROM gpkg_spatial_ref_sys WHERE srs_id = -1"); assertEquals(rs.getInt(1), -1); rs = st.executeQuery("SELECT srs_id FROM gpkg_spatial_ref_sys WHERE srs_id = 0"); assertEquals(rs.getInt(1), 0); rs = st.executeQuery("SELECT srs_id FROM gpkg_spatial_ref_sys WHERE srs_id = 4326"); assertEquals(rs.getInt(1), 4326); } catch(Exception e) { fail(e.getMessage()); } finally { st.close(); cx.close(); } } void assertApplicationId() throws Exception { Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement(); try { ResultSet rs = st.executeQuery("PRAGMA application_id;"); assertEquals(rs.getInt(1), 0x47503130); } catch(Exception e) { fail(e.getMessage()); } finally { st.close(); cx.close(); } } void assertTableExists(String table) throws Exception { Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement(); try { st.execute(String.format("SELECT count(*) FROM %s;", table)); } catch(Exception e) { fail(e.getMessage()); } finally { st.close(); cx.close(); } } void assertLastChangedDateString(Calendar startTime, Calendar endTime) throws Exception { final TimeZone tz = TimeZone.getTimeZone("GMT"); // get the date now for comparison final Calendar c = Calendar.getInstance(tz); // this is what should be used for the date string format in the DB final String dateFomratString = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; final SimpleDateFormat sdf = new SimpleDateFormat(dateFomratString); sdf.setTimeZone(tz); try (Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement(); ResultSet rs = st.executeQuery(String.format("SELECT last_change FROM %s;", GeoPackage.GEOPACKAGE_CONTENTS))){ if (rs.next()) { final String dateString = rs.getString(1); // parse the date with the expected format string Date parsedDate = sdf.parse(dateString); // assert the parsed time is between the start and end time c.setTime(parsedDate); assertTrue("Start time should be less than or equal to last_change time", startTime.compareTo(c) <= 0); assertTrue("End time should be greater than or equal to last_change time", endTime.compareTo(c) >= 0); } } } boolean doesEntryExists(String table, Entry entry) throws Exception { boolean exists = false; Connection cx = geopkg.getDataSource().getConnection(); try { String sql = String.format("SELECT * FROM %s WHERE table_name = ?", table); SqlUtil.PreparedStatementBuilder psb = SqlUtil.prepare(cx, sql).set(entry.getTableName()); PreparedStatement ps = psb.log(Level.FINE).statement(); try { ResultSet rs = ps.executeQuery(); try { while(rs.next()) { exists = true; } } finally { rs.close(); } } finally { ps.close(); } } catch(Exception e) { fail(e.getMessage()); } finally { cx.close(); } return exists; } @Test public void testSRS() throws Exception { Entry entry = new Entry(); entry.setTableName("points"); entry.setDataType(Entry.DataType.Feature); entry.setIdentifier("points"); entry.setBounds(new ReferencedEnvelope(-180,180,-90,90, CRS.decode("EPSG:2000", true))); entry.setSrid(2000); geopkg.addGeoPackageContentsEntry(entry); Connection cx = geopkg.getDataSource().getConnection(); try { String sql = String.format("SELECT srs_name FROM %s WHERE srs_id = ?", GeoPackage.SPATIAL_REF_SYS); SqlUtil.PreparedStatementBuilder psb = SqlUtil.prepare(cx, sql).set(2000); PreparedStatement ps = psb.log(Level.FINE).statement(); try { ResultSet rs = ps.executeQuery(); try { assertTrue(rs.next()); assertEquals("epsg:2000", rs.getString(1)); } finally { rs.close(); } } finally { ps.close(); } } catch(Exception e) { fail(e.getMessage()); } finally { cx.close(); } } @Test public void testDeleteGeoPackageContentsEntry() throws Exception { Entry entry = new Entry(); entry.setTableName("points"); entry.setDataType(Entry.DataType.Feature); entry.setIdentifier("points"); entry.setBounds(new ReferencedEnvelope(-180,180,-90,90, CRS.decode("EPSG:4326", true))); entry.setSrid(4326); geopkg.addGeoPackageContentsEntry(entry); assertTrue(doesEntryExists(GeoPackage.GEOPACKAGE_CONTENTS, entry)); geopkg.deleteGeoPackageContentsEntry(entry); assertFalse(doesEntryExists(GeoPackage.GEOPACKAGE_CONTENTS, entry)); } @Test public void testDeleteGeometryColumnsEntry() throws Exception { FeatureEntry entry = new FeatureEntry(); entry.setTableName("points"); entry.setDataType(Entry.DataType.Feature); entry.setIdentifier("points"); entry.setBounds(new ReferencedEnvelope(-180,180,-90,90, CRS.decode("EPSG:4326", true))); entry.setSrid(4326); entry.setGeometryColumn("geom"); entry.setGeometryType(Geometries.POINT); geopkg.addGeometryColumnsEntry(entry); assertTrue(doesEntryExists(GeoPackage.GEOMETRY_COLUMNS, entry)); geopkg.deleteGeometryColumnsEntry(entry); assertFalse(doesEntryExists(GeoPackage.GEOMETRY_COLUMNS, entry)); } @Test public void testCreateFeatureEntry() throws Exception { ShapefileDataStore shp = new ShapefileDataStore(setUpShapefile()); FeatureEntry entry = new FeatureEntry(); geopkg.add(entry, shp.getFeatureSource(), null); assertTableExists("bugsites"); //check metadata contents assertFeatureEntry(entry); SimpleFeatureReader re = Features.simple(shp.getFeatureReader()); SimpleFeatureReader ra = geopkg.reader(entry, null, null); while(re.hasNext()) { assertTrue(ra.hasNext()); assertSimilar(re.next(), ra.next()); } re.close(); ra.close(); } @Test public void test3DGeometry() throws Exception { //create feature with 3d geometry Point geom = new GeometryFactory(new PrecisionModel(), 4326).createPoint(new Coordinate(5,3,8)); SimpleFeatureTypeBuilder tBuilder = new SimpleFeatureTypeBuilder(); tBuilder.setName( "mytype" ); tBuilder.add( "name", String.class); tBuilder.add( "geom", Geometry.class, 4326); SimpleFeatureType type = tBuilder.buildFeatureType(); SimpleFeatureBuilder fBuilder = new SimpleFeatureBuilder(type); MemoryFeatureCollection featCollection = new MemoryFeatureCollection(type); fBuilder.add("testfeature"); fBuilder.add(geom); featCollection.add(fBuilder.buildFeature("fid-0001")); FeatureEntry entry = new FeatureEntry(); //important, store in database that there is a z entry.setZ(true); geopkg.add(entry, featCollection); assertTableExists("mytype"); //check metadata contents assertFeatureEntry(entry); //read feature and verify dimension SimpleFeatureReader ra = geopkg.reader(entry, null, null); assertTrue(ra.hasNext()); SimpleFeature f = ra.next(); Point readGeom = (Point) f.getAttribute("geom"); assertEquals(3, readGeom.getCoordinateSequence().getDimension()); assertEquals(geom.getCoordinate().z, readGeom.getCoordinate().z, 0.0001); ra.close(); } @Test public void testFunctions() throws Exception { ShapefileDataStore shp = new ShapefileDataStore(setUpShapefile()); SimpleFeatureReader re = Features.simple(shp.getFeatureReader()); FeatureEntry entry = new FeatureEntry(); geopkg.add(entry, shp.getFeatureSource(), null); Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement(); try { while(re.hasNext()) { SimpleFeature f = re.next(); ResultSet rs = st.executeQuery((String.format( "SELECT ST_MinX(the_geom), ST_MinY(the_geom), ST_MaxX(the_geom), ST_MaxY(the_geom), ST_IsEmpty(the_geom) FROM bugsites WHERE ID=" + f.getProperty("ID").getValue()))); assertEquals(rs.getDouble(1), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMinX(), 0.0001 ); assertEquals(rs.getDouble(2), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMinY(), 0.0001 ); assertEquals(rs.getDouble(3), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMaxX(), 0.0001 ); assertEquals(rs.getDouble(4), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMaxY(), 0.0001 ); assertEquals(rs.getDouble(5)==1, ((Geometry) f.getDefaultGeometry()).isEmpty() ); rs.close(); } } catch(Exception e) { fail(e.getMessage()); } finally { st.close(); cx.close(); re.close(); } } @Test public void testFunctionsNoEnvelope() throws Exception { ShapefileDataStore shp = new ShapefileDataStore(setUpShapefile()); SimpleFeatureReader re = Features.simple(shp.getFeatureReader()); FeatureEntry entry = new FeatureEntry(); geopkg.getWriterConfiguration().setWriteEnvelope(false); geopkg.add(entry, shp.getFeatureSource(), null); Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement(); try { while(re.hasNext()) { SimpleFeature f = re.next(); ResultSet rs = st.executeQuery((String.format( "SELECT ST_MinX(the_geom), ST_MinY(the_geom), ST_MaxX(the_geom), ST_MaxY(the_geom), ST_IsEmpty(the_geom) FROM bugsites WHERE ID=" + f.getProperty("ID").getValue()))); assertEquals(rs.getDouble(1), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMinX(), 0.0001 ); assertEquals(rs.getDouble(2), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMinY(), 0.0001 ); assertEquals(rs.getDouble(3), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMaxX(), 0.0001 ); assertEquals(rs.getDouble(4), ((Geometry) f.getDefaultGeometry()).getEnvelopeInternal().getMaxY(), 0.0001 ); assertEquals(rs.getDouble(5)==1, ((Geometry) f.getDefaultGeometry()).isEmpty() ); rs.close(); } } catch(Exception e) { fail(e.getMessage()); } finally { st.close(); cx.close(); re.close(); } } @Test public void testSpatialIndexWriting() throws Exception { ShapefileDataStore shp = new ShapefileDataStore(setUpShapefile()); SimpleFeatureCollection coll = shp.getFeatureSource().getFeatures(); FeatureEntry entry = new FeatureEntry(); entry.setBounds(coll.getBounds()); geopkg.create(entry, shp.getSchema()); //write some features before and some after try(SimpleFeatureIterator it = coll.features()) { //some features try(Transaction tx = new DefaultTransaction(); SimpleFeatureWriter w = geopkg.writer(entry, true, null, tx)) { for (int i = 0; i < 3; i++) { SimpleFeature f = it.next(); SimpleFeature g = w.next(); for (PropertyDescriptor pd : coll.getSchema().getDescriptors()) { String name = pd.getName().getLocalPart(); g.setAttribute(name, f.getAttribute(name)); } w.write(); } tx.commit(); } //create spatial index geopkg.createSpatialIndex(entry); //the rest of features try(Transaction tx = new DefaultTransaction(); SimpleFeatureWriter w = geopkg.writer(entry, true, null, tx)) { while(it.hasNext()) { SimpleFeature f = it.next(); SimpleFeature g = w.next(); for (PropertyDescriptor pd : coll.getSchema().getDescriptors()) { String name = pd.getName().getLocalPart(); g.setAttribute(name, f.getAttribute(name)); } w.write(); } tx.commit(); } } //test if the index was properly created try(Connection cx = geopkg.getDataSource().getConnection(); Statement st = cx.createStatement()) { ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM rtree_bugsites_the_geom"); rs.next(); assertEquals(rs.getInt(1), coll.size()); } } @Test public void testSpatialIndexReading() throws Exception { FilterFactory ff = CommonFactoryFinder.getFilterFactory(); ShapefileDataStore shp = new ShapefileDataStore(setUpShapefile()); FeatureEntry entry = new FeatureEntry(); geopkg.add(entry, shp.getFeatureSource(), null); assertFalse(geopkg.hasSpatialIndex(entry)); geopkg.createSpatialIndex(entry); assertTrue(geopkg.hasSpatialIndex(entry)); Set ids = geopkg.searchSpatialIndex(entry, 590230.0, 4915038.0, 590234.0, 4915040.0); try(SimpleFeatureReader sfr = geopkg.reader(entry, ff.id(ids), null)) { assertTrue(sfr.hasNext()); assertEquals("bugsites.1", sfr.next().getID().toString()); assertFalse(sfr.hasNext()); } } @Test public void testCreateTileEntry() throws Exception { TileEntry e = new TileEntry(); e.setTableName("foo"); e.setBounds(new ReferencedEnvelope(-180,180,-90,90,DefaultGeographicCRS.WGS84)); e.getTileMatricies().add(new TileMatrix(0, 1, 1, 256, 256, 0.1, 0.1)); e.getTileMatricies().add(new TileMatrix(1, 2, 2, 256, 256, 0.1, 0.1)); geopkg.create(e); assertTileEntry(e); List<Tile> tiles = new ArrayList(); tiles.add(new Tile(0,0,0,new byte[]{0})); tiles.add(new Tile(1,0,0,new byte[]{1})); tiles.add(new Tile(1,0,1,new byte[]{2})); tiles.add(new Tile(1,1,0,new byte[]{3})); tiles.add(new Tile(1,1,1,new byte[]{4})); for (Tile t : tiles) { geopkg.add(e, t); } try(TileReader r = geopkg.reader(e, null, null, null, null, null, null)) { assertTiles(tiles, r); } } @Test public void testIndependentTileMatrix() throws Exception { TileEntry e = new TileEntry(); e.setTableName("foo"); e.setBounds(new ReferencedEnvelope(-10, 10, -10, 10, DefaultGeographicCRS.WGS84)); e.setTileMatrixSetBounds(new Envelope(-180, 180, -90, 90)); e.getTileMatricies().add(new TileMatrix(0, 1, 1, 256, 256, 0.1, 0.1)); e.getTileMatricies().add(new TileMatrix(1, 2, 2, 256, 256, 0.1, 0.1)); geopkg.create(e); assertContentEntry(e); try (Connection cx = geopkg.getDataSource().getConnection(); PreparedStatement ps = cx.prepareStatement( "SELECT * from gpkg_tile_matrix_set WHERE table_name = ?")) { ps.setString(1, e.getTableName()); try(ResultSet rs = ps.executeQuery()) { rs.next(); assertEquals(4326, rs.getInt(2)); assertEquals(-180, rs.getDouble(3), 0.01); assertEquals(-90, rs.getDouble(4), 0.01); assertEquals(180, rs.getDouble(5), 0.01); assertEquals(90, rs.getDouble(6), 0.01); assertFalse(rs.next()); } } } @Test public void testListEntries() throws Exception { // grab the start and end time to ensure the last_change time range final TimeZone tz = TimeZone.getTimeZone("GMT"); final Calendar startTime = Calendar.getInstance(tz); testCreateFeatureEntry(); testCreateTileEntry(); final Calendar endTime = Calendar.getInstance(tz); List<FeatureEntry> lf = geopkg.features(); assertEquals(1, lf.size()); assertEquals("bugsites", lf.get(0).getTableName()); // make sure Date format String is fine assertLastChangedDateString(startTime, endTime); List<TileEntry> lt = geopkg.tiles(); assertEquals(1, lt.size()); TileEntry te = lt.get(0); assertEquals("foo", te.getTableName()); assertEquals(2, te.getTileMatricies().size()); } @Test /* * From the OGC GeoPackage Specification [1]: * * "The tile coordinate (0,0) always refers to the tile in the upper left corner of the tile matrix at any zoom * level, regardless of the actual availability of that tile" * * [1]: http://www.geopackage.org/spec/#tile_matrix */ public void testTopLeftTile() throws IOException, FactoryException { File sourceFile = GeoPackageFormat.getFileFromSource(getClass().getResource("Blue_Marble.gpkg")); GeoPackage geopkg = new GeoPackage(sourceFile); List<TileEntry> tiles = geopkg.tiles(); //Get 0,0,0 tile Tile topLeftTile = geopkg.reader(tiles.get(0), 0, 0, 0, 0, 0, 0).next(); BufferedImage tileImg = ImageIO.read(new ByteArrayInputStream(topLeftTile.getData())); ImageAssert.assertEquals(DataUtilities.urlToFile(getClass().getResource("bluemarble_0_0_0.jpeg")), tileImg, 250); //Render the GeoPackage at zoom level 0 GeoPackageReader reader = new GeoPackageReader(getClass().getResource("Blue_Marble.gpkg"), null); GeneralParameterValue[] parameters = new GeneralParameterValue[1]; GridGeometry2D gg = new GridGeometry2D(new GridEnvelope2D(new Rectangle(1536,768)), new ReferencedEnvelope(-180,180,-90,90, CRS.decode("EPSG:4326", true))); parameters[0] = new Parameter<GridGeometry2D>(AbstractGridFormat.READ_GRIDGEOMETRY2D, gg); GridCoverage2D gc = reader.read("bluemarble_tif_tiles", parameters); BufferedImage img = ((PlanarImage) gc.getRenderedImage()).getAsBufferedImage(); //ImageIO.write(img, "JPEG", new File("bluemarblerendered.jpeg")); //Get top left tile BufferedImage topLeftImg = new BufferedImage(256, 256, img.getType()); Graphics2D graphics = topLeftImg.createGraphics(); graphics.drawImage(img, 0, 0, 256, 256, //Destination coordinates 0, 0, 256, 256, //Source coordinates null); //ImageIO.write(topLeftImg, "JPEG", new File("bluemarbletopleft.jpeg")); ImageAssert.assertEquals(DataUtilities.urlToFile(getClass().getResource("bluemarble_0_0_0.jpeg")), topLeftImg, 250); } void assertTiles(List<Tile> tiles, TileReader r) throws IOException { for (Tile t : tiles) { assertTrue(r.hasNext()); Tile a = r.next(); assertEquals(t, a); } assertFalse(r.hasNext()); r.close(); } void assertContentEntry(Entry entry) throws Exception { Connection cx = geopkg.getDataSource().getConnection(); try { PreparedStatement ps = cx.prepareStatement("SELECT * FROM gpkg_contents WHERE table_name = ?"); ps.setString(1, entry.getTableName()); ResultSet rs = ps.executeQuery(); assertTrue(rs.next()); assertEquals(entry.getIdentifier(), rs.getString("identifier")); assertEquals(entry.getDescription(), rs.getString("description")); assertEquals(entry.getSrid().intValue(), rs.getInt("srs_id")); assertEquals(entry.getBounds().getMinX(), rs.getDouble("min_x"), 0.1); assertEquals(entry.getBounds().getMinY(), rs.getDouble("min_y"), 0.1); assertEquals(entry.getBounds().getMaxX(), rs.getDouble("max_x"), 0.1); assertEquals(entry.getBounds().getMaxY(), rs.getDouble("max_y"), 0.1); rs.close(); ps.close(); } finally { cx.close(); } } void assertFeatureEntry(FeatureEntry entry) throws Exception { assertContentEntry(entry); Connection cx = geopkg.getDataSource().getConnection(); try { PreparedStatement ps = cx.prepareStatement("SELECT * FROM gpkg_geometry_columns WHERE table_name = ?"); ps.setString(1, entry.getTableName()); ResultSet rs = ps.executeQuery(); assertTrue(rs.next()); assertEquals(entry.getGeometryColumn(), rs.getString("column_name")); assertEquals(entry.getGeometryType(), Geometries.getForName(rs.getString("geometry_type_name"))); assertEquals(entry.getSrid().intValue(), rs.getInt("srs_id")); assertEquals(entry.isZ(), rs.getBoolean("z")); assertEquals(entry.isM(), rs.getBoolean("m")); rs.close(); ps.close(); } finally { cx.close(); } } void assertTileEntry(TileEntry entry) throws Exception { assertContentEntry(entry); Connection cx = geopkg.getDataSource().getConnection(); try { PreparedStatement ps = cx.prepareStatement( "SELECT count(*) from gpkg_tile_matrix WHERE table_name = ?"); ps.setString(1, entry.getTableName()); ResultSet rs = ps.executeQuery(); rs.next(); assertEquals(rs.getInt(1), entry.getTileMatricies().size()); rs.close(); ps.close(); ps = cx.prepareStatement( "SELECT * from gpkg_tile_matrix_set WHERE table_name = ?"); ps.setString(1, entry.getTableName()); rs = ps.executeQuery(); rs.next(); assertEquals(rs.getInt(2), entry.getSrid().intValue()); assertEquals(rs.getDouble(3), entry.getBounds().getMinX(), 0.01); assertEquals(rs.getDouble(4), entry.getBounds().getMinY(), 0.01); assertEquals(rs.getDouble(5), entry.getBounds().getMaxX(), 0.01); assertEquals(rs.getDouble(6), entry.getBounds().getMaxY(), 0.01); assertFalse(rs.next()); rs.close(); ps.close(); //index ps = cx.prepareStatement( "SELECT * from sqlite_master WHERE type='index' and name = ?"); ps.setString(1, entry.getTableName() + "_zyx_idx"); rs = ps.executeQuery(); rs.close(); ps.close(); } finally { cx.close(); } } void assertSimilar(SimpleFeature expected, SimpleFeature actual) { assertNotNull(actual); assertTrue(((Geometry)expected.getDefaultGeometry()).equals( ((Geometry)actual.getDefaultGeometry()))); for (AttributeDescriptor d : expected.getType().getAttributeDescriptors()) { Object e = expected.getAttribute(d.getLocalName()); Object a = actual.getAttribute(d.getLocalName()); if (e instanceof Number) { assertEquals(((Number) e).intValue(), ((Number)a).intValue()); } else { assertEquals(e, a); } } } URL setUpShapefile() throws Exception { File d = File.createTempFile("bugsites", "shp", new File("target")); d.delete(); d.mkdirs(); String[] exts = new String[]{"shp", "shx", "dbf", "prj"}; for (String ext : exts) { if("prj".equals(ext)) { String wkt = CRS.decode("EPSG:26713", true).toWKT(); FileUtils.writeStringToFile(new File(d, "bugsites.prj"), wkt); } else { FileUtils.copyURLToFile(TestData.url("shapes/bugsites." + ext), new File(d, "bugsites." + ext)); } } return DataUtilities.fileToURL(new File(d, "bugsites.shp")); } URL setUpGeoTiff() throws IOException { File d = File.createTempFile("world", "tiff", new File("target")); d.delete(); d.mkdirs(); FileUtils.copyURLToFile(TestData.url("geotiff/world.tiff"), new File(d, "world.tiff")); return DataUtilities.fileToURL(new File(d, "world.tiff")); } URL setUpPNG() throws IOException { File d = File.createTempFile("Pk50095", "png", new File("target")); d.delete(); d.mkdirs(); FileUtils.copyURLToFile(TestData.url(this, "Pk50095.png"), new File(d, "Pk50095.png")); FileUtils.copyURLToFile(TestData.url(this, "Pk50095.pgw"), new File(d, "Pk50095.pgw")); return DataUtilities.fileToURL(new File(d, "Pk50095.png")); } }