/* * 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.daos; import android.content.Context; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.util.HashMap; import java.util.Map; import eu.geopaparazzi.library.database.GPLog; import eu.geopaparazzi.library.util.FileUtilities; import eu.geopaparazzi.spatialite.database.spatial.core.enums.GeometryType; import eu.geopaparazzi.spatialite.database.spatial.core.enums.SpatialiteVersion; import jsqlite.Database; import jsqlite.Stmt; /** * Created by hydrologis on 18/07/14. */ public class Shapefile { /** * Extension for shapefiles prjs. */ public static final String PRJ_EXTENSION = ".prj"; //$NON-NLS-1$ /** * Create geometry Table from Shape Table. * <p/> * <p>'RegisterVirtualGeometry' needs SpatiaLite 4.0.0 * * @param sqlite_db Database connection to use * @param s_table_path full path to Shape-Table [without .shp] * @param s_table_name Table name of Shape-Table [without path] * @param s_char_set Characterset used in Shape [default 'CP1252', Windows Latin 1] * @param i_srid srid of Shape-Table * @return i_rc 0 or last_error from Database */ private static int createShapeTable(Database sqlite_db, String s_table_path, String s_table_name, String s_char_set, int i_srid) { int i_rc = 0; Stmt this_stmt = null; int i_geometry_type = 0; if (s_char_set.equals("")) s_char_set = "CP1252"; String s_table_name_work = s_table_name + "_work"; // GPLog.androidLog(-1,"SpatialiteUtilities create_shape_table[" + s_table_name + // "] srid["+i_srid+"] ["+s_table_path+"]"); // CREATE VIRTUAL TABLE roads using virtualshape('/sdcard/maps/roads',CP1252,3857); String s_sql_command = "CREATE VIRTUAL TABLE " + s_table_name_work + " USING VirtualShape('" + s_table_path + "'," + s_char_set + "," + i_srid + ");"; // GPLog.androidLog(-1,"SpatialiteUtilities create_shape_table[" + s_sql_command+"]"); try { sqlite_db.exec(s_sql_command, null); // SELECT RegisterVirtualGeometry('roads'); s_sql_command = "SELECT RegisterVirtualGeometry('" + s_table_name_work + "');"; sqlite_db.exec(s_sql_command, null); // CREATE TABLE myroads AS SELECT * FROM roads; s_sql_command = "CREATE TABLE " + s_table_name + " AS SELECT * FROM " + s_table_name_work + ";"; sqlite_db.exec(s_sql_command, null); s_sql_command = "SELECT geometry_type FROM vector_layers WHERE table_name='" + s_table_name + "'"; this_stmt = sqlite_db.prepare(s_sql_command); try { if (this_stmt.step()) { i_geometry_type = this_stmt.column_int(0); } } catch (jsqlite.Exception e_stmt) { i_rc = sqlite_db.last_error(); GPLog.androidLog(4, "SpatialiteUtilities: create_shape_table sql[" + s_sql_command + "] rc=" + i_rc + "]", e_stmt); } GeometryType geometry_type = GeometryType.forValue(i_geometry_type); String s_geometry_type = geometry_type.toString(); // SELECT RecoverGeometryColumn('myroads','Geometry',3857,'LINESTRING') s_sql_command = "SELECT RecoverGeometryColumn('" + s_table_name + "', 'Geometry'," + i_srid + ",'" + s_geometry_type + "');"; sqlite_db.exec(s_sql_command, null); // SELECT CreateSpatialIndex('myroads','Geometry'); s_sql_command = "SELECT CreateSpatialIndex('" + s_table_name + "', 'Geometry');"; sqlite_db.exec(s_sql_command, null); // SELECT DropVirtualGeometry('berlin_ortsteile_2010_work'); s_sql_command = "SELECT DropVirtualGeometry('" + s_table_name_work + "');"; sqlite_db.exec(s_sql_command, null); } catch (jsqlite.Exception e_stmt) { i_rc = sqlite_db.last_error(); GPLog.androidLog(4, "SpatialiteUtilities: create_shape_table sql[" + s_sql_command + "] rc=" + i_rc + "]", e_stmt); } return i_rc; } // ----------------------------------------------- /** * Attempt to determine srid from Shape .prj file * <p/> * <p>Shape-WKT rarely conforms to that used in 'spatial_ref_sys' * * @param sqlite_db Database connection to use * @param s_srs_wkt name of 'spatial_ref_sys' to search [dependent on spatilite version] * @param s_well_known_text read from the Shape .prj file * @return srid of .prj file where possible */ private static int readShapeSrid(Database sqlite_db, String s_srs_wkt, String s_well_known_text) { int i_srid = 0; if ((s_well_known_text.contains("GCS_WGS_1984")) && (s_well_known_text.contains("D_WGS_1984")) && (s_well_known_text.contains("Greenwich")) && (s_well_known_text.contains("Degree"))) { /* * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984", * SPHEROID["WGS_1984",6378137.0,298.257223563]], * PRIMEM["Greenwich",0.0], * UNIT["Degree",0.017453292519943295]] */ i_srid = 4326; } if ((s_well_known_text.indexOf("GCS_DHDN") != -1) && (s_well_known_text.indexOf("D_Deutsches_Hauptdreiecksnetz") != -1) && (s_well_known_text.indexOf("Bessel_1841") != -1) && (s_well_known_text.indexOf("Greenwich") != -1) && (s_well_known_text.indexOf("Degree") != -1)) { /* * PROJCS["Cassini",GEOGCS["GCS_DHDN", * DATUM["D_Deutsches_Hauptdreiecksnetz", * SPHEROID["Bessel_1841",6377397.155,299.1528128]], * PRIMEM["Greenwich",0], * UNIT["Degree",0.017453292519943295]] */ if ((s_well_known_text.indexOf("Cassini") != -1) && (s_well_known_text.indexOf("52.4186482") != -1) && (s_well_known_text.indexOf("13.62720") != -1)) { /* * ,PROJECTION["Cassini"], * PARAMETER["latitude_of_origin",52.41864827777778], * PARAMETER["central_meridian",13.62720366666667], */ if ((s_well_known_text.indexOf("40000") != -1) && (s_well_known_text.indexOf("10000") != -1)) { // PARAMETER["false_easting",40000],PARAMETER["false_northing",10000],UNIT["Meter",1],PARAMETER["scale_factor",1.0]] i_srid = 3068; } } } if (i_srid == 0) { /* * TODO: do a lot of guessing * PROJCS["DHDN / Soldner Berlin", * GEOGCS["DHDN",DATUM["Deutsches_Hauptdreiecksnetz", * SPHEROID["Bessel 1841",6377397.155,299.1528128, * AUTHORITY["EPSG","7004"]],AUTHORITY["EPSG","6314"]], * PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]], * UNIT["degree",0.01745329251994328, * AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4314"]], * UNIT["metre",1,AUTHORITY["EPSG","9001"]], * PROJECTION["Cassini_Soldner"], * PARAMETER["latitude_of_origin",52.41864827777778], * PARAMETER["central_meridian",13.62720366666667], * PARAMETER["false_easting",40000], * PARAMETER["false_northing",10000], * AUTHORITY["EPSG","3068"],AXIS["x",NORTH],AXIS["y",EAST]] * SELECT srid FROM spatial_ref_sys WHERE (srs_wkt LIKE * 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984", * SPHEROID["WGS_1984",6378137.0,298.257223563]], * PRIMEM["Greenwich",0.0],UNIT["Degree",0.017453292519943295]]') */ } return i_srid; } /** * General Function to search for Shape files * <p/> * <p/> * - A Shape-File(s) resides in a directory<br> * - - the Directory name is the Database-Name<br> * - each Shape-Table must have a '.shp','.prj','.shx' and '.dbf'<br> * - the name with extention is the Table-Name<br> * * @param prjFile2ParentFolderMap File as found '.prj' files, File as directory */ private static void createDbForShapefile(HashMap<File, File> prjFile2ParentFolderMap) { File shape_db = null; File shape_dir = null; Database sqlite_db = null; SpatialiteVersion spatialiteVersion = SpatialiteVersion.NO_SPATIALITE; String s_srs_wkt = "srs_wkt"; String s_shape_path = ""; String s_shape_name = ""; for (Map.Entry<File, File> shape_list : prjFile2ParentFolderMap.entrySet()) { File file_prj = shape_list.getKey(); File file_directory = shape_list.getValue(); if (sqlite_db == null) { shape_dir = file_directory; s_shape_path = shape_dir.getParentFile().getAbsolutePath(); s_shape_name = shape_dir.getName(); // .substring(0, // shape_dir.getName().lastIndexOf(".")); shape_db = new File(s_shape_path + File.separator + s_shape_name + ".db"); // GPLog.androidLog(-1,"SpatialiteUtilities create_shape_db[" + // shape_db.getAbsolutePath() + // "] shape_name["+s_shape_name+"] db.exists["+shape_db.exists()+"]"); if (shape_db.exists()) { // A database exist - abort return; } try { sqlite_db = DatabaseCreationAndProperties.createDb(shape_db.getAbsolutePath()); spatialiteVersion = DatabaseCreationAndProperties.getSpatialiteDatabaseVersion(sqlite_db, ""); } catch (Throwable t) { GPLog.androidLog(4, "SpatialiteUtilities create_shape_db[" + shape_db.getAbsolutePath() + "] spatialite_version[" + spatialiteVersion + "]", t); } if (spatialiteVersion.getCode() >= 3) { // created valid spatialite db if (spatialiteVersion == SpatialiteVersion.AFTER_4_0_0_RC1) { s_srs_wkt = "srtext"; } } } if (sqlite_db != null) { String s_table_name = file_prj.getName().substring(0, file_prj.getName().lastIndexOf(".")); String s_well_known_text = ""; try { // GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.017453292519943295]] s_well_known_text = FileUtilities.readfile(file_prj); int i_srid = readShapeSrid(sqlite_db, s_srs_wkt, s_well_known_text); String s_char_set = "CP1252"; if (i_srid > 0) { String s_table_path = s_shape_path + File.separator + s_shape_name + File.separator + s_table_name; int i_rc = createShapeTable(sqlite_db, s_table_path, s_table_name, s_char_set, i_srid); // GPLog.androidLog(-1,"SpatialiteUtilities create_shape_db[" + s_table_name // + "] srid["+i_srid+"]"); } } catch (IOException e) { GPLog.error("Shapefile", null, e); } } } if (sqlite_db != null) { try { sqlite_db.close(); } catch (jsqlite.Exception e_stmt) { GPLog.androidLog(4, "SpatialiteUtilities: create_shape_db: close() : failed", e_stmt); } sqlite_db = null; } } /** * Collects a {@link HashMap} of prj files of shapefiles. * <p/> * <p/> * - A Shape-File(s) resides in a directory<br> * - - the Directory name is the Database-Name<br> * - each Shape-Table must have a '.shp','.prj','.shx' and '.dbf'<br> * - the name with extension is the Table-Name<br> * * @param context 'this' of Application Activity class * @param mapsDir Directory to search [ResourcesManager.getInstance(this).getMapsDir();] * @return shapes_list: a {@link HashMap} that maps the prj file to the parent folder file. */ public static HashMap<File, File> findShapefilePrjFiles(Context context, File mapsDir) { File[] list_files = mapsDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String filename) { return filename.endsWith(PRJ_EXTENSION); } }); // each shape file must have a prj file, we will read the prj file later HashMap<File, File> shapes_list = new HashMap<File, File>(); File this_directoy = mapsDir; for (File this_file : list_files) { if (this_file.isDirectory()) { // read recursive directories inside the sdcard/maps directory shapes_list = findShapefilePrjFiles(context, this_file); if (shapes_list.size() > 0) { // shape file Directory has been found: do something // with it // GPLog.androidLog(-1,"SpatialiteUtilities find_shapes[" // + this_file.getAbsolutePath() + "] shapes[" + // shapes_list.size() + "]"); createDbForShapefile(shapes_list); } } else { // store each prj file and the directory found shapes_list.put(this_file, this_directoy); } } // GPLog.androidLog(-1,"SpatialiteUtilities find_shapes[" + mapsDir.getName() + // "] size["+shapes_list+"]"); return shapes_list; } }