/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2010 HydroloGIS (www.hydrologis.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.geopaparazzi.spatialite.database.spatial.core.databasehandlers; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.Paint.Cap; import android.graphics.Paint.Join; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import eu.geopaparazzi.library.database.GPLog; import eu.geopaparazzi.library.style.ColorUtilities; import eu.geopaparazzi.library.util.LibraryConstants; import eu.geopaparazzi.library.util.types.ESpatialDataSources; import eu.geopaparazzi.spatialite.database.spatial.core.enums.TableTypes; import eu.geopaparazzi.spatialite.database.spatial.core.tables.AbstractSpatialTable; import eu.geopaparazzi.spatialite.database.spatial.core.tables.SpatialRasterTable; import eu.geopaparazzi.spatialite.database.spatial.core.tables.SpatialVectorTable; import eu.geopaparazzi.spatialite.database.spatial.core.geometry.GeometryIterator; import eu.geopaparazzi.spatialite.database.spatial.core.enums.GeometryType; import eu.geopaparazzi.spatialite.database.spatial.core.daos.DaoSpatialite; import eu.geopaparazzi.spatialite.database.spatial.core.daos.DatabaseCreationAndProperties; import eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties; import eu.geopaparazzi.spatialite.database.spatial.util.comparators.OrderComparator; import eu.geopaparazzi.spatialite.database.spatial.core.enums.SpatialiteDatabaseType; import eu.geopaparazzi.spatialite.database.spatial.util.SpatialiteUtilities; import eu.geopaparazzi.library.style.Style; import jsqlite.Database; import jsqlite.Exception; import jsqlite.Stmt; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.DaoSpatialite.PROPERTIESTABLE; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties.createDefaultPropertiesForTable; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties.createPropertiesTable; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties.deleteStyleTable; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties.getAllStyles; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties.getStyle4Table; import static eu.geopaparazzi.spatialite.database.spatial.core.daos.GeopaparazziDatabaseProperties.updateStyleName; /** * An utility class to handle the spatial database. * * @author Andrea Antonello (www.hydrologis.com) */ @SuppressWarnings("nls") public class SpatialiteDatabaseHandler extends AbstractSpatialDatabaseHandler { private String uniqueDbName4DataProperties = ""; private Database dbJava; private HashMap<String, Paint> fillPaints = new HashMap<String, Paint>(); private HashMap<String, Paint> strokePaints = new HashMap<String, Paint>(); private List<SpatialVectorTable> vectorTableList; private List<SpatialRasterTable> rasterTableList; private SpatialiteDatabaseType databaseType = null; // List of all SpatialView of Database [view_name,view_data] - parse for // 'geometry_column;min_x,min_y,max_x,max_y' private HashMap<String, String> spatialVectorMap = new HashMap<String, String>(); // List of all SpatialView of Database [view_name,view_data] - that have errors private HashMap<String, String> spatialVectorMapErrors = new HashMap<String, String>(); private volatile boolean isOpen = false; /** * Constructor. * * @param dbPath the path to the database this handler connects to. * @throws IOException if something goes wrong. */ public SpatialiteDatabaseHandler(String dbPath) throws IOException { super(dbPath); open(); } @Override public boolean isOpen() { return isOpen; } @Override public void open() { try { uniqueDbName4DataProperties = databasePath; dbJava = new jsqlite.Database(); try { dbJava.open(databasePath, jsqlite.Constants.SQLITE_OPEN_READWRITE | jsqlite.Constants.SQLITE_OPEN_CREATE); isOpen = true; isDatabaseValid = true; } catch (Exception e) { GPLog.error(this, "Database marked as invalid: " + databasePath, e); isDatabaseValid = false; isOpen = false; GPLog.androidLog(4, "SpatialiteDatabaseHandler[" + databaseFile.getAbsolutePath() + "].open has failed", e); } if (isValid()) { // check database and collect the views list try { databaseType = DatabaseCreationAndProperties.checkDatabaseTypeAndValidity(dbJava, spatialVectorMap, spatialVectorMapErrors); } catch (Exception e) { GPLog.error(this, null, e); isDatabaseValid = false; isOpen = false; } switch (databaseType) { /* if (spatialVectorMap.size() == 0) for SPATIALITE3/4 --> DaoSpatialite.checkDatabaseTypeAndValidity will return SpatialiteDatabaseType.UNKNOWN -- there is nothing to load (database empty) */ case GEOPACKAGE: case SPATIALITE3: case SPATIALITE4: isDatabaseValid = true; break; default: { isDatabaseValid = false; isOpen = false; } } } if (!isValid()) { close(); } else { // avoid call for invalid databases [SpatialiteDatabaseType.UNKNOWN] checkAndUpdatePropertiesUniqueNames(); } } catch (Exception e) { GPLog.error(this, "SpatialiteDatabaseHandler[" + databaseFile.getAbsolutePath() + "]", e); } } /** * Is the database file considered valid? * <p/> * <br>- metadata table exists and has data * <br>- 'tiles' is either a table or a view and the correct fields exist * <br>-- if a view: do the tables map and images exist with the correct fields * <br>checking is done once when the 'metadata' is retrieved the first time [fetchMetadata()] * * @return true if valid, otherwise false */ @Override public boolean isValid() { return isDatabaseValid; } @Override public List<SpatialVectorTable> getSpatialVectorTables(boolean forceRead) throws Exception { if (vectorTableList == null || forceRead) { vectorTableList = new ArrayList<SpatialVectorTable>(); checkAndCollectTables(); } return vectorTableList; } @Override public List<SpatialRasterTable> getSpatialRasterTables(boolean forceRead) throws Exception { if (rasterTableList == null || forceRead) { rasterTableList = new ArrayList<SpatialRasterTable>(); checkAndCollectTables(); } return rasterTableList; } /** * Checks if the table names in the properties table are defined properly. * <p/> * <p>The unique table name is a concatenation of:<br> * <b>dbPath#tablename#geometrytype</b> * <p>If the name doesn't start with the database path, it needs to * be updated. The rest is anyways unique inside the database. * * @throws Exception if something went wrong. */ private void checkAndUpdatePropertiesUniqueNames() throws Exception { List<Style> allStyles = null; try { allStyles = getAllStyles(dbJava); } catch (java.lang.Exception e) { // ignore and create a default one } if (allStyles == null) { /* * something went wrong in the reading of the table, * which might be due to an upgrade of table structure. * Remove and recreate the table. */ deleteStyleTable(dbJava); createPropertiesTable(dbJava); } else { for (Style style : allStyles) { if (!style.name.startsWith(uniqueDbName4DataProperties + SpatialiteUtilities.UNIQUENAME_SEPARATOR)) { // need to update the name in the style and also in the database String[] split = style.name.split(SpatialiteUtilities.UNIQUENAME_SEPARATOR); if (split.length == 3) { String newName = uniqueDbName4DataProperties + SpatialiteUtilities.UNIQUENAME_SEPARATOR + split[1] + SpatialiteUtilities.UNIQUENAME_SEPARATOR + split[2]; style.name = newName; updateStyleName(dbJava, newName, style.id); } } } } } /** * Check availability of style for the tables. * * @throws Exception */ private void checkPropertiesTable() throws Exception { int propertiesTableColumnCount = DatabaseCreationAndProperties.checkTableExistence(dbJava, PROPERTIESTABLE); if (propertiesTableColumnCount == 0) { createPropertiesTable(dbJava); for (SpatialVectorTable spatialTable : vectorTableList) { createDefaultPropertiesForTable(dbJava, spatialTable.getUniqueNameBasedOnDbFilePath(), spatialTable.getLabelField()); } } } public float[] getTableBounds(AbstractSpatialTable spatialTable) throws Exception { return spatialTable.getTableBounds(); } /** * Get the fill {@link Paint} for a given style. * <p/> * <p>Paints are cached and reused.</p> * * @param style the {@link Style} to use. * @return the paint. */ public Paint getFillPaint4Style(Style style) { Paint paint = fillPaints.get(style.name); if (paint == null) { paint = new Paint(); fillPaints.put(style.name, paint); } paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); paint.setColor(ColorUtilities.toColor(style.fillcolor)); float alpha = style.fillalpha * 255f; paint.setAlpha((int) alpha); return paint; } /** * Get the stroke {@link Paint} for a given style. * <p/> * <p>Paints are cached and reused.</p> * * @param style the {@link Style} to use. * @return the paint. */ public Paint getStrokePaint4Style(Style style) { Paint paint = strokePaints.get(style.name); if (paint == null) { paint = new Paint(); strokePaints.put(style.name, paint); } paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); paint.setStrokeCap(Cap.ROUND); paint.setStrokeJoin(Join.ROUND); paint.setColor(ColorUtilities.toColor(style.strokecolor)); float alpha = style.strokealpha * 255f; paint.setAlpha((int) alpha); paint.setStrokeWidth(style.width); try { float[] shiftAndDash = Style.dashFromString(style.dashPattern); if (shiftAndDash != null) { float[] dash = Style.getDashOnly(shiftAndDash); if (dash.length > 1) paint.setPathEffect(new DashPathEffect(dash, Style.getDashShift(shiftAndDash))); } } catch (java.lang.Exception e) { GPLog.error(this, "Error on dash creation: " + style.dashPattern, e); } return paint; } /** * Retrieve list of WKB geometries from the given table in the given bounds. * * @param destSrid the destination srid. * @param table the vector table. * @param n north bound. * @param s south bound. * @param e east bound. * @param w west bound. * @return list of WKB geometries. */ public List<byte[]> getWKBFromTableInBounds(String destSrid, SpatialVectorTable table, double n, double s, double e, double w) { List<byte[]> list = new ArrayList<byte[]>(); String query = SpatialiteUtilities.buildGeometriesInBoundsQuery(destSrid, false, table, n, s, e, w); try { Stmt stmt = dbJava.prepare(query); try { while (stmt.step()) { list.add(stmt.column_bytes(0)); } } finally { stmt.close(); } return list; } catch (Exception ex) { GPLog.error(this, null, ex); } return null; } @Override public byte[] getRasterTile(String query) { try { Stmt stmt = dbJava.prepare(query); try { if (stmt.step()) { return stmt.column_bytes(0); } } finally { stmt.close(); } } catch (Exception ex) { GPLog.error(this, null, ex); } return null; } /** * Get the {@link GeometryIterator} of a table in a given bound. * * @param destSrid the srid to which to transform to. * @param table the table to use. * @param n north bound. * @param s south bound. * @param e east bound. * @param w west bound. * @return the geometries iterator. */ public GeometryIterator getGeometryIteratorInBounds(String destSrid, SpatialVectorTable table, double n, double s, double e, double w) { String query = SpatialiteUtilities.buildGeometriesInBoundsQuery(destSrid, false, table, n, s, e, w); // GPLog.androidLog(-1,"GeopaparazziOverlay.getGeometryIteratorInBounds query["+query+"]"); return new GeometryIterator(dbJava, query); } public void close() throws Exception { if (isOpen) { isOpen = false; if (dbJava != null) { dbJava.close(); } } } /** * Performs an intersection query on a vector table and returns a string info version of the result. * * @param boundsSrid the srid of the bounds supplied. * @param spatialTable the vector table to query. * @param n north bound. * @param s south bound. * @param e east bound. * @param w west bound. * @param resultStringBuilder the builder of the result. * @param indentStr the indenting to use for formatting. * @throws Exception if something goes wrong. */ public void intersectionToStringBBOX(String boundsSrid, SpatialVectorTable spatialTable, double n, double s, double e, double w, StringBuilder resultStringBuilder, String indentStr) throws Exception { String query = getIntersectionQueryBBOX(boundsSrid, spatialTable, n, s, e, w); Stmt stmt = dbJava.prepare(query); try { while (stmt.step()) { int column_count = stmt.column_count(); for (int i = 0; i < column_count; i++) { String cName = stmt.column_name(i); String value = stmt.column_string(i); resultStringBuilder.append(indentStr).append(cName).append(": ").append(value).append("\n"); } resultStringBuilder.append("\n"); } } finally { stmt.close(); } } /** * Get the query to run for a bounding box intersection. * <p/> * <p>This assures that the first element of the query is * the id field for the record as defined in {@link SpatialiteUtilities#SPATIALTABLE_ID_FIELD}. * * @param boundsSrid the srid of the bounds requested. * @param spatialTable the {@link SpatialVectorTable} to query. * @param n north bound. * @param s south bound. * @param e east bound. * @param w west bound. * @return the query to run to get all fields. */ public static String getIntersectionQueryBBOX(String boundsSrid, SpatialVectorTable spatialTable, double n, double s, double e, double w) { boolean doTransform = false; String fieldNamesList = SpatialiteUtilities.SPATIALTABLE_ID_FIELD; // List of non-blob fields for (String field : spatialTable.getTableFieldNamesList()) { boolean ignore = SpatialiteUtilities.doIgnoreField(field); if (!ignore) fieldNamesList += "," + field; } if (!spatialTable.getSrid().equals(boundsSrid)) { doTransform = true; } StringBuilder sbQ = new StringBuilder(); sbQ.append("SELECT "); sbQ.append(fieldNamesList); sbQ.append(" FROM \"").append(spatialTable.getTableName()); sbQ.append("\" WHERE ST_Intersects("); if (doTransform) sbQ.append("ST_Transform("); sbQ.append("BuildMBR("); sbQ.append(w); sbQ.append(","); sbQ.append(s); sbQ.append(","); sbQ.append(e); sbQ.append(","); sbQ.append(n); if (doTransform) { sbQ.append(","); sbQ.append(boundsSrid); sbQ.append("),"); sbQ.append(spatialTable.getSrid()); } sbQ.append("),"); sbQ.append(spatialTable.getGeomName()); sbQ.append(");"); return sbQ.toString(); } // public void intersectionToString4Polygon( String queryPointSrid, SpatialVectorTable // spatialTable, double n, double e, // StringBuilder sb, String indentStr ) throws Exception { // boolean doTransform = false; // if (!spatialTable.getSrid().equals(queryPointSrid)) { // doTransform = true; // } // // StringBuilder sbQ = new StringBuilder(); // sbQ.append("SELECT * FROM "); // sbQ.append(spatialTable.getName()); // sbQ.append(" WHERE ST_Intersects("); // sbQ.append(spatialTable.getGeomName()); // sbQ.append(","); // if (doTransform) // sbQ.append("ST_Transform("); // sbQ.append("MakePoint("); // sbQ.append(e); // sbQ.append(","); // sbQ.append(n); // if (doTransform) { // sbQ.append(","); // sbQ.append(queryPointSrid); // sbQ.append("),"); // sbQ.append(spatialTable.getSrid()); // } // sbQ.append(")) = 1 "); // sbQ.append("AND ROWID IN ("); // sbQ.append("SELECT ROWID FROM Spatialindex WHERE f_table_name ='"); // sbQ.append(spatialTable.getName()); // sbQ.append("'"); // // if a table has more than 1 geometry, the column-name MUST be given, otherwise no results. // sbQ.append(" AND f_geometry_column = '"); // sbQ.append(spatialTable.getGeomName()); // sbQ.append("'"); // sbQ.append(" AND search_frame = "); // if (doTransform) // sbQ.append("ST_Transform("); // sbQ.append("MakePoint("); // sbQ.append(e); // sbQ.append(","); // sbQ.append(n); // if (doTransform) { // sbQ.append(","); // sbQ.append(queryPointSrid); // sbQ.append("),"); // sbQ.append(spatialTable.getSrid()); // } // sbQ.append("));"); // String query = sbQ.toString(); // // Stmt stmt = db_java.prepare(query); // try { // while( stmt.step() ) { // int column_count = stmt.column_count(); // for( int i = 0; i < column_count; i++ ) { // String cName = stmt.column_name(i); // if (cName.equalsIgnoreCase(spatialTable.getGeomName())) { // continue; // } // // String value = stmt.column_string(i); // sb.append(indentStr).append(cName).append(": ").append(value).append("\n"); // } // sb.append("\n"); // } // } finally { // stmt.close(); // } // } /** * Load list of Table [Vector/Raster] for GeoPackage Files [gpkg] * <p/> * <b>THIS METHOD IS VERY EXPERIMENTAL AND A WORK IN PROGRESS</b> * - rasterTableList or vectorTableList will be created if == null * <br>- name of Field * <br> - type of field as defined in Database * <br>- OGC 12-128r9 from 2013-11-19 * <br>-- older versions will not be supported * <br>- With SQLite versions 3.7.17 and later : 'PRAGMA application_id' [1196437808] * <br>-- older (for us invalid) SPL_Geopackage Files return 0 */ private void collectGpkgTables() throws Exception { String vector_key = ""; // term used when building the sql, used as map.key String vector_value = ""; // to retrieve map.value (=vector_data+vector_extent) for (Map.Entry<String, String> vector_entry : spatialVectorMap.entrySet()) { // berlin_stadtteile vector_key = vector_entry.getKey(); // soldner_polygon;14;3;2;3068;1;20847.6171111586,18733.613614603,20847.6171111586,18733.613614603 vector_value = vector_entry.getValue(); double[] boundsCoordinates = new double[]{0.0, 0.0, 0.0, 0.0}; double[] centerCoordinate = new double[]{0.0, 0.0}; HashMap<String, String> fields_list = new HashMap<String, String>(); int i_geometry_type = 0; int i_view_read_only = 0; double horz_resolution = 0.0; String s_view_read_only = ""; String[] sa_string = vector_key.split(";"); // fromosm_tiles;tile_data;GeoPackage_tiles;© OpenStreetMap contributors, See // http://www.openstreetmap.org/copyright;OSM Tiles; // geonames;geometry;GeoPackage_features;Data from http://www.geonames.org/, under // Creative Commons Attribution 3.0 License;Geonames; if (sa_string.length == 5) { String table_name = sa_string[0]; // fromosm_tiles / geonames String geometry_column = sa_string[1]; // tile_data / geometry String layerType = sa_string[2]; // GeoPackage_tiles / GeoPackage_features String s_identifier = sa_string[3]; // short description String s_description = sa_string[4]; // long description sa_string = vector_value.split(";"); // RGB;512;3068;1890 - // 1:17777;3;17903.0354299312,17211.5335278146,29889.8601630003,26582.2086184726;2014-05-09T09:18:07.230Z if (sa_string.length == 7) { // 0;10;3857;0; // 1;2;4326;0; String s_geometry_type = sa_string[0]; // 1= POINT / OR min_zoom String s_coord_dimension = sa_string[1]; // 2= XY / OR max_zoom String s_srid = sa_string[2]; // 4326 String s_spatial_index_enabled = sa_string[3]; // 0 // -1;-75.5;18.0;-71.06667;20.08333;2013-12-24T16:32:14.000000Z String s_row_count = sa_string[4]; // 0 = not possible as sub-query - but also // not needed String s_bounds = sa_string[5]; // -75.5;18.0;-71.06667;20.08333 String s_last_verified = sa_string[6]; // 2013-12-24T16:32:14.000000Z sa_string = s_bounds.split(","); if (sa_string.length == 4) { try { boundsCoordinates[0] = Double.parseDouble(sa_string[0]); boundsCoordinates[1] = Double.parseDouble(sa_string[1]); boundsCoordinates[2] = Double.parseDouble(sa_string[2]); boundsCoordinates[3] = Double.parseDouble(sa_string[3]); } catch (NumberFormatException e) { } if (!s_srid.equals("4326")) { // Transform into wsg84 if needed SpatialiteUtilities.collectBoundsAndCenter(dbJava, s_srid, centerCoordinate, boundsCoordinates); } else { centerCoordinate[0] = boundsCoordinates[0] + (boundsCoordinates[2] - boundsCoordinates[0]) / 2; centerCoordinate[1] = boundsCoordinates[1] + (boundsCoordinates[3] - boundsCoordinates[1]) / 2; } checkAndAdaptDatabaseBounds(boundsCoordinates, null); if (vector_key.contains("GeoPackage_tiles")) { int i_min_zoom = Integer.parseInt(s_geometry_type); int i_max_zoom = Integer.parseInt(s_coord_dimension); SpatialRasterTable table = new SpatialRasterTable(getDatabasePath(), "", s_srid, i_min_zoom, i_max_zoom, centerCoordinate[0], centerCoordinate[1], null, boundsCoordinates); table.setMapType(layerType); // table.setTableName(s_table_name); table.setColumnName(geometry_column); // setDescription(s_table_name); // table.setDescription(this.databaseDescription); if (rasterTableList == null) rasterTableList = new ArrayList<SpatialRasterTable>(); rasterTableList.add(table); } else { if (vector_key.contains("GeoPackage_features")) { // String table_name=sa_string[0]; // lakemead_clipped // String geometry_column=sa_string[1]; // shape i_view_read_only = 0; // always i_geometry_type = Integer.parseInt(s_geometry_type); GeometryType geometry_type = GeometryType.forValue(i_geometry_type); s_geometry_type = geometry_type.toString(); int i_spatial_index_enabled = Integer.parseInt(s_spatial_index_enabled); // 0=no // spatialiIndex // for // GeoPackage // Files int i_row_count = Integer.parseInt(s_row_count); // will always be 0 // no Zoom levels with // vector data if (i_spatial_index_enabled == 1) { SpatialVectorTable table = new SpatialVectorTable(getDatabasePath(), table_name, geometry_column, i_geometry_type, s_srid, centerCoordinate, boundsCoordinates, layerType); // compleate list of fields of // this table fields_list = DaoSpatialite.collectTableFields(dbJava, table_name); table.setFieldsList(fields_list, "ROWID", i_view_read_only); if (vectorTableList == null) vectorTableList = new ArrayList<SpatialVectorTable>(); vectorTableList.add(table); } } } } } } } } /** * Load list of Table [Vector] for Spatialite4+ Files * - for Spaltialite4+ all needed information has been collected in DaoSpatialite.checkDatabaseTypeAndValidity() * - rasterTableList or vectorTableList will be created if == null * <br>- name of Field * <br>- type of field as defined in Database */ private void collectVectorTables() throws Exception { String vector_key = ""; // term used when building the sql, used as map.key String vector_value = ""; // to retrieve map.value (=vector_data+vector_extent) for (Map.Entry<String, String> vector_entry : spatialVectorMap.entrySet()) { // berlin_stadtteile vector_key = vector_entry.getKey(); // soldner_polygon;14;3;2;3068;1;20847.6171111586,18733.613614603,20847.6171111586,18733.613614603 vector_value = vector_entry.getValue(); double[] boundsCoordinates = new double[]{0.0, 0.0, 0.0, 0.0}; double[] centerCoordinate = new double[]{0.0, 0.0}; HashMap<String, String> fields_list = new HashMap<String, String>(); int i_geometry_type = 0; int i_view_read_only = 0; String s_view_read_only = ""; String[] sa_string = vector_key.split(";"); // berlin_postgrenzen.1890;LOSSY_WEBP;RasterLite2;Berlin Straube Postgrenzen;1890 - // 1:17777; if (sa_string.length == 5) { String table_name = sa_string[0]; String geometry_column = sa_string[1]; String layerType = sa_string[2]; String s_ROWID_PK = sa_string[3]; s_view_read_only = sa_string[4]; sa_string = vector_value.split(";"); // RGB;512;3068;1.13008623862252;3;17903.0354299312,17211.5335278146,29889.8601630003,26582.2086184726;2014-05-09T09:18:07.230Z if (sa_string.length == 7) { String s_geometry_type = sa_string[0]; String s_coord_dimension = sa_string[1]; String s_srid = sa_string[2]; String s_spatial_index_enabled = sa_string[3]; String s_row_count_enabled = sa_string[4]; String s_bounds = sa_string[5]; String s_last_verified = sa_string[6]; sa_string = s_bounds.split(","); // must be > 0 for Wsg84 support int i_srid = Integer.parseInt(s_srid); if ((sa_string.length == 4) && (i_srid > 0)) { try { boundsCoordinates[0] = Double.parseDouble(sa_string[0]); boundsCoordinates[1] = Double.parseDouble(sa_string[1]); boundsCoordinates[2] = Double.parseDouble(sa_string[2]); boundsCoordinates[3] = Double.parseDouble(sa_string[3]); } catch (NumberFormatException e) { // ignore } if (!s_srid.equals(LibraryConstants.SRID_WGS84_4326)) { // Transform into wsg84 if needed SpatialiteUtilities.collectBoundsAndCenter(dbJava, s_srid, centerCoordinate, boundsCoordinates); } else { centerCoordinate[0] = boundsCoordinates[0] + (boundsCoordinates[2] - boundsCoordinates[0]) / 2; centerCoordinate[1] = boundsCoordinates[1] + (boundsCoordinates[3] - boundsCoordinates[1]) / 2; } checkAndAdaptDatabaseBounds(boundsCoordinates, null); if (layerType.equals(ESpatialDataSources.RASTERLITE2.getTypeName())) { // s_ROWID_PK == title [Berlin Straube Postgrenzen] - needed // s_view_read_only == abstract [1890 - 1:17777] - needed // s_geometry_type == pixel_type [RGB] - not needed // s_coord_dimension == tile_width - maybe usefull // geometry_column == compression [LOSSY_WEBP] - not needed // s_row_count_enabled == num_bands [3] - not needed // int i_tile_width = Integer.parseInt(s_coord_dimension); // double horz_resolution = Double.parseDouble(s_spatial_index_enabled); // int i_num_bands = Integer.parseInt(s_row_count_enabled); // TODO in next version add RasterTable // berlin_postgrenzen.1890 SpatialRasterTable table = new SpatialRasterTable(getDatabasePath(), table_name, s_srid, 0, 22, centerCoordinate[0], centerCoordinate[1], null, boundsCoordinates); table.setMapType(layerType); table.setTitle(s_ROWID_PK); table.setDescription(s_view_read_only); // prevent a possible double loading if (rasterTableList == null) rasterTableList = new ArrayList<SpatialRasterTable>(); rasterTableList.add(table); } if ((layerType.equals(TableTypes.SPATIALTABLE.getDescription())) || (layerType.equals(TableTypes.SPATIALVIEW.getDescription()))) { i_view_read_only = Integer.parseInt(s_view_read_only); i_geometry_type = Integer.parseInt(s_geometry_type); GeometryType geometry_type = GeometryType.forValue(i_geometry_type); s_geometry_type = geometry_type.toString(); int i_spatial_index_enabled = Integer.parseInt(s_spatial_index_enabled); // should // always // be // 1 int i_row_count = Integer.parseInt(s_row_count_enabled); // no Zoom levels with // vector data if (i_spatial_index_enabled == 1) { SpatialVectorTable table = new SpatialVectorTable(getDatabasePath(), table_name, geometry_column, i_geometry_type, s_srid, centerCoordinate, boundsCoordinates, layerType); // compleate list of fields of // this table fields_list = DaoSpatialite.collectTableFields(dbJava, table_name); table.setFieldsList(fields_list, s_ROWID_PK, i_view_read_only); if (vectorTableList == null) vectorTableList = new ArrayList<SpatialVectorTable>(); vectorTableList.add(table); } } } } } } } /** * Checks (and adapts) the overall database bounds based on the passed coordinates. * <p/> * <p>Goal: when painting the Geometries: check of viewport is inside these bounds. * <br>- if the Viewport is outside these Bounds: all Tables can be ignored * <br>-- this is called when the Tables are created * * @param boundsCoordinates bounds to check against the overall. */ private void checkAndAdaptDatabaseBounds(double[] boundsCoordinates, int[] zoomLevels) { if ((this.boundsWest == 0.0) && (this.boundsSouth == 0.0) && (this.boundsEast == 0.0) && (this.boundsNorth == 0.0)) { this.boundsWest = boundsCoordinates[0]; this.boundsSouth = boundsCoordinates[1]; this.boundsEast = boundsCoordinates[2]; this.boundsNorth = boundsCoordinates[2]; } else { if (boundsCoordinates[0] < this.boundsWest) this.boundsWest = boundsCoordinates[0]; if (boundsCoordinates[1] < this.boundsSouth) this.boundsSouth = boundsCoordinates[1]; if (boundsCoordinates[2] > this.boundsEast) this.boundsEast = boundsCoordinates[2]; if (boundsCoordinates[3] < this.boundsNorth) this.boundsNorth = boundsCoordinates[3]; } centerX = this.boundsWest + (this.boundsEast - this.boundsWest) / 2; centerY = this.boundsSouth + (this.boundsNorth - this.boundsSouth) / 2; if ((zoomLevels != null) && (zoomLevels.length == 2)) { if ((this.minZoom == 0) && (this.maxZoom == 0)) { this.minZoom = zoomLevels[0]; this.maxZoom = zoomLevels[1]; } else { if (zoomLevels[0] < this.minZoom) this.minZoom = zoomLevels[0]; if (zoomLevels[1] > this.maxZoom) this.maxZoom = zoomLevels[1]; } } } /** * Collects tables. * <p/> * <p>The {@link HashMap} will contain: * <ul> * <li>name of Field * <li>type of field as defined in Database * </ul> */ private void checkAndCollectTables() throws Exception { switch (databaseType) { case GEOPACKAGE: { // GeoPackage Files [gpkg] collectGpkgTables(); } break; case SPATIALITE3: case SPATIALITE4: { // Spatialite Files version 2.4 ; 3 and 4 collectVectorTables(); } break; default: break; } if (isValid()) { if (vectorTableList != null) { // now read styles checkPropertiesTable(); // assign the styles for (SpatialVectorTable spatialTable : vectorTableList) { Style style4Table = null; try { style4Table = getStyle4Table(dbJava, spatialTable.getUniqueNameBasedOnDbFilePath(), spatialTable.getLabelField()); } catch (java.lang.Exception e) { deleteStyleTable(dbJava); checkPropertiesTable(); } if (style4Table == null) { spatialTable.makeDefaultStyle(); } else { spatialTable.setStyle(style4Table); } } OrderComparator orderComparator = new OrderComparator(); Collections.sort(vectorTableList, orderComparator); } } } /** * Update a style definiton in the db. * * @param style the {@link Style} to update. * @throws Exception if something goes wrong. */ public void updateStyle(Style style) throws Exception { GeopaparazziDatabaseProperties.updateStyle(dbJava, style); } /** * Delete and recreate a default properties table for this database. * * @throws Exception if something goes wrong. */ public void resetStyleTable() throws Exception { deleteStyleTable(dbJava); createPropertiesTable(dbJava); for (SpatialVectorTable spatialTable : vectorTableList) { createDefaultPropertiesForTable(dbJava, spatialTable.getUniqueNameBasedOnDbFilePath(), spatialTable.getLabelField()); } } /** * Getter for the spatialite db reference. * * @return the spatialite database reference. */ public Database getDatabase() { return dbJava; } }