====== Source Code WorldMapKitDataExtractor.zip ====== ====App.xaml.cs==== using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; namespace WorldMapKitDataExtractor { /// /// Interaction logic for App.xaml /// public partial class App : Application { } } ====MainWindow.xaml.cs==== using System; using System.Collections.ObjectModel; using System.Data; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Forms; using ThinkGeo.MapSuite.Core; using WorldMapKitDataExtractor.Model; namespace WorldMapKitDataExtractor { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void btnOk_Click(object sender, RoutedEventArgs e) { if (ValidateInput()) { EnableUI(false); Extractor extractor = new Extractor(txtInputDatabase.Text, txtOutputDatabase.Text); extractor.InputDataPrj = ManagedProj4Projection.GetEpsgParametersString(int.Parse(txtInputDatabaseSrid.Text)); extractor.UpdateStatus = value => { Dispatcher.Invoke(() => { lblStatus.Content = string.Format("Status: {0}", value); }); }; extractor.PreserveCountryLevelData = chkPreserveCountryLevelData.IsChecked == true; Collection boundariesFeatures = new Collection(); if(extractor.PreserveCountryLevelData) { RectangleShape boundingBox = new RectangleShape(); switch(txtInputDatabaseSrid.Text) { case "4326": boundingBox = new RectangleShape(-180, 90, 180, -90); break; case "3857": boundingBox = new RectangleShape(-20026376, 20048966, 20026376, -20048966); break; default: boundingBox = new RectangleShape(0, 0, 0, 0); break; } boundariesFeatures.Add(new BoundingBoxWithZoomLevels(boundingBox, (int)cmbCountryStartZoomLevel.SelectedValue, (int)cmbCountryEndZoomLevel.SelectedValue)); } if (rbtnShapeFile.IsChecked == true) { ShapeFileFeatureLayer shapeFileLayer = new ShapeFileFeatureLayer(txtShapeFile.Text); shapeFileLayer.Open(); string prjFilePath = Path.ChangeExtension(txtShapeFile.Text, ".prj"); if (File.Exists(prjFilePath)) extractor.BoundaryPrj = ManagedProj4Projection.ConvertPrjToProj4(File.ReadAllText(prjFilePath)); else extractor.BoundaryPrj = ManagedProj4Projection.GetEpsgParametersString(int.Parse(shapeFileSrid.Text)); var selectItems = featureTable.SelectedItems.Count == 0 ? featureTable.Items.Cast() : featureTable.SelectedItems.Cast(); foreach (DataRowView row in selectItems) { boundariesFeatures.Add(new BoundingBoxWithZoomLevels(shapeFileLayer.QueryTools.GetFeatureById(row.Row[0].ToString(), ReturningColumnsType.NoColumns).GetBoundingBox(), 1, 20)); } } else { BoundingBoxRow row1 = new BoundingBoxRow(txtUpperLeft1, txtLowerRight1, cmbStartZoomLevel1, cmbEndZoomLevel1, chkEnable1); BoundingBoxRow row2 = new BoundingBoxRow(txtUpperLeft2, txtLowerRight2, cmbStartZoomLevel2, cmbEndZoomLevel2, chkEnable2); BoundingBoxRow row3 = new BoundingBoxRow(txtUpperLeft3, txtLowerRight3, cmbStartZoomLevel3, cmbEndZoomLevel3, chkEnable3); BoundingBoxRow row4 = new BoundingBoxRow(txtUpperLeft4, txtLowerRight4, cmbStartZoomLevel4, cmbEndZoomLevel4, chkEnable4); BoundingBoxRow row5 = new BoundingBoxRow(txtUpperLeft5, txtLowerRight5, cmbStartZoomLevel5, cmbEndZoomLevel5, chkEnable5); BoundingBoxRow[] boundingBoxRows = { row1, row2, row3, row4, row5 }; extractor.BoundaryPrj = ManagedProj4Projection.GetEpsgParametersString(int.Parse(boundarySrid.Text)); foreach (BoundingBoxRow row in boundingBoxRows) { if ((bool)row.chkRowEnabled.IsChecked) { var uppperLeftPoint = row.txtUpperLeftPoint.Text.Split(',').Select(a => double.Parse(a.Trim())).ToArray(); var lowerRightPoint = row.txtLowerRightPoint.Text.Split(',').Select(a => double.Parse(a.Trim())).ToArray(); RectangleShape boundingBox = new RectangleShape(uppperLeftPoint[0], uppperLeftPoint[1], lowerRightPoint[0], lowerRightPoint[1]); boundariesFeatures.Add(new BoundingBoxWithZoomLevels(boundingBox, (int)row.cmbStartZoomLevel.SelectedValue, (int)row.cmbEndZoomLevel.SelectedValue)); } } } Task.Run(() => extractor.ExtractDataByShape(boundariesFeatures)).ContinueWith(task => EnableUI(true)); } } private bool ValidateInput() { bool result = true; StringBuilder errorMessage = new StringBuilder(); int srid; if (!File.Exists(txtInputDatabase.Text)) errorMessage.AppendLine("Please enter correct input database file path."); if (!int.TryParse(txtInputDatabaseSrid.Text, out srid)) errorMessage.AppendLine("Please enter correct SRID for input database."); if (string.IsNullOrEmpty(txtOutputDatabase.Text)) errorMessage.AppendLine("Please enter correct output database file path."); if (rbtnShapeFile.IsChecked == true) { if (!File.Exists(txtShapeFile.Text)) errorMessage.AppendLine("Please enter correct shape file path."); if (!File.Exists(Path.ChangeExtension(txtShapeFile.Text, ".prj")) && !int.TryParse(shapeFileSrid.Text, out srid)) errorMessage.AppendLine("Please enter correct SRID for boundary shaplefile."); } if (rbtnBoundingBox.IsChecked == true) { if(!int.TryParse(boundarySrid.Text, out srid)) errorMessage.AppendLine("Please enter correct SRID for boundary."); if((bool)chkPreserveCountryLevelData.IsChecked) { if((int)cmbCountryStartZoomLevel.SelectedValue > (int)cmbCountryEndZoomLevel.SelectedValue) errorMessage.AppendLine("Invalid ZoomLevel Input for Preserve Country-Level Data."); } BoundingBoxRow row1 = new BoundingBoxRow(txtUpperLeft1, txtLowerRight1, cmbStartZoomLevel1, cmbEndZoomLevel1, chkEnable1); BoundingBoxRow row2 = new BoundingBoxRow(txtUpperLeft2, txtLowerRight2, cmbStartZoomLevel2, cmbEndZoomLevel2, chkEnable2); BoundingBoxRow row3 = new BoundingBoxRow(txtUpperLeft3, txtLowerRight3, cmbStartZoomLevel3, cmbEndZoomLevel3, chkEnable3); BoundingBoxRow row4 = new BoundingBoxRow(txtUpperLeft4, txtLowerRight4, cmbStartZoomLevel4, cmbEndZoomLevel4, chkEnable4); BoundingBoxRow row5 = new BoundingBoxRow(txtUpperLeft5, txtLowerRight5, cmbStartZoomLevel5, cmbEndZoomLevel5, chkEnable5); BoundingBoxRow[] boundingBoxRows = { row1, row2, row3, row4, row5 }; foreach (BoundingBoxRow row in boundingBoxRows) { if ((bool)row.chkRowEnabled.IsChecked) { var upperLeftPoint = row.txtUpperLeftPoint.Text.Split(',').Select(a => double.Parse(a.Trim())).ToArray(); var lowerRightPoint = row.txtLowerRightPoint.Text.Split(',').Select(a => double.Parse(a.Trim())).ToArray(); if(upperLeftPoint[0] > lowerRightPoint[0] || upperLeftPoint[1] < lowerRightPoint[1]) errorMessage.AppendLine("Invalid BoundingBox Input."); if ((int)row.cmbStartZoomLevel.SelectedValue > (int)row.cmbEndZoomLevel.SelectedValue || (int)row.cmbStartZoomLevel.SelectedValue < 0 || (int)row.cmbEndZoomLevel.SelectedValue < 0) errorMessage.AppendLine("Invalid ZoomLevel Input."); } } if(!((bool)chkEnable1.IsChecked || (bool)chkEnable2.IsChecked || (bool)chkEnable3.IsChecked || (bool)chkEnable4.IsChecked || (bool)chkEnable5.IsChecked)) errorMessage.AppendLine("Please enable a bounding box."); } if (!string.IsNullOrEmpty(errorMessage.ToString())) { System.Windows.MessageBox.Show(errorMessage.ToString(), "Warning"); result = false; } return result; } private void EnableUI(bool enable) { Dispatcher.Invoke(() => { btnOk.IsEnabled = enable; btnCancel.IsEnabled = enable; btnOutputDatabase.IsEnabled = enable; btnOpenShapeFile.IsEnabled = enable; btnInputDatabase.IsEnabled = enable; }); } private void ExtractorTypeChanged(object sender, RoutedEventArgs e) { if (IsLoaded) { if (rbtnBoundingBox.IsChecked == true) { shapeFilePanel.Visibility = Visibility.Hidden; boundingBoxPanel.Visibility = Visibility.Visible; } else { shapeFilePanel.Visibility = Visibility.Visible; boundingBoxPanel.Visibility = Visibility.Hidden; } } } private void btnInputDatabase_Click(object sender, RoutedEventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); dlg.DefaultExt = ".sqlite"; dlg.Filter = "SQLite Database (.sqlite)|*.sqlite"; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) txtInputDatabase.Text = dlg.FileName; } private void btnOutputDatabase_Click(object sender, RoutedEventArgs e) { SaveFileDialog dlg = new SaveFileDialog(); dlg.DefaultExt = ".sqlite"; dlg.Filter = "SQLite Database (.sqlite)|*.sqlite"; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) txtOutputDatabase.Text = dlg.FileName; } private void btnOpenShapeFile_Click(object sender, RoutedEventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); dlg.DefaultExt = ".shp"; dlg.Filter = "Shape File (.shp)|*.shp"; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) txtShapeFile.Text = dlg.FileName; ShapeFileFeatureSource shapeFile = new ShapeFileFeatureSource(txtShapeFile.Text); shapeFile.Open(); Collection features = shapeFile.GetAllFeatures(ReturningColumnsType.AllColumns); shapeFile.Close(); DataTable dt = new DataTable(); bool isColumnName = true; foreach (var feature in features) { var columnValues = feature.ColumnValues; if (isColumnName) { dt.Columns.Add(new DataColumn("FeatureId")); foreach (var column in columnValues.Keys) { dt.Columns.Add(new DataColumn(column)); } isColumnName = false; } DataRow row = dt.NewRow(); row["FeatureId"] = feature.Id; foreach (var item in columnValues) { row[item.Key] = item.Value; } dt.Rows.Add(row); } featureTable.ItemsSource = dt.DefaultView; } private void btnCancel_Click(object sender, RoutedEventArgs e) { Close(); } private void Window_Loaded(object sender, RoutedEventArgs e) { System.Windows.Controls.ComboBox[] zoomLevelBoxes = { cmbEndZoomLevel1, cmbEndZoomLevel2, cmbEndZoomLevel3, cmbEndZoomLevel4, cmbEndZoomLevel5, cmbStartZoomLevel1, cmbStartZoomLevel2, cmbStartZoomLevel3, cmbStartZoomLevel4, cmbStartZoomLevel5, cmbCountryStartZoomLevel, cmbCountryEndZoomLevel }; foreach (System.Windows.Controls.ComboBox comboBox in zoomLevelBoxes) { int[] zoomLevels = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; comboBox.ItemsSource = zoomLevels; } cmbStartZoomLevel1.SelectedIndex = 7; cmbEndZoomLevel1.SelectedIndex = 19; cmbCountryStartZoomLevel.SelectedIndex = 0; cmbCountryEndZoomLevel.SelectedIndex = 6; } } } ====DynamicGridPolygonIndexer.cs==== using System.Collections.Generic; using System.Collections.ObjectModel; namespace ThinkGeo.MapSuite.Core { public static class DynamicGridPolygonIndexer { //Get all Cells without cutting polygon. restricts how many levels to iterate based on minimum cell area public static GeoCollection GetIntersectingGridCells(BaseShape source, GeographyUnit sourceUnit, double minimumCellArea, AreaUnit minimumCellAreaUnit) { //find bounding box of set of boundary RectangleShape boundingBox = source.GetBoundingBox(); Stack processingStack = new Stack(); processingStack.Push(boundingBox); Collection insideRectangles = new Collection(); Collection intersectingRectangles = new Collection(); while (processingStack.Count > 0) { RectangleShape currentBoundingBox = processingStack.Pop(); bool toBeSplit = false; if (source.Contains(currentBoundingBox)) { //if inside a boundary add to inside rectangles holder insideRectangles.Add(currentBoundingBox); } else if (source.Intersects(currentBoundingBox)) { //if intersecting //we multiply the minimum cell area by 9 to do this check because if it is below it we are splitting it into 9 equal parts //this guarantees that after it is split they new cells are still larger than the minimum area. if (currentBoundingBox.GetArea(sourceUnit, minimumCellAreaUnit) > minimumCellArea * 9) { //if it is too big it needs to be split toBeSplit = true; } else { //if small enough add to intersecting rectangles holder intersectingRectangles.Add(currentBoundingBox); } } if (toBeSplit) { //split bounding boxes Collection splitBoundingBoxes = splitRectangles(currentBoundingBox); //and add each to stack foreach (RectangleShape splitBoundingBox in splitBoundingBoxes) { processingStack.Push(splitBoundingBox); } } } GeoCollection cells = new GeoCollection(); foreach (var rect in insideRectangles) { RectangleShape bboxShape = rect; Feature bbox = new Feature(bboxShape); bbox.ColumnValues["type"] = "in"; cells.Add(bbox); } foreach (var rect in intersectingRectangles) { RectangleShape bboxShape = rect; Feature bbox = new Feature(bboxShape); bbox.ColumnValues["type"] = "intersecting"; cells.Add(bbox); } return cells; } private static Collection splitRectangles(RectangleShape currentBoundingBox) { double x1, x2, x3, x4, y1, y2, y3, y4; x1 = currentBoundingBox.UpperLeftPoint.X; x4 = currentBoundingBox.UpperRightPoint.X; x2 = x1 + (x4 - x1) / 3.0; x3 = x4 - (x4 - x1) / 3.0; y1 = currentBoundingBox.UpperLeftPoint.Y; y4 = currentBoundingBox.LowerLeftPoint.Y; y2 = y1 + (y4 - y1) / 3.0; y3 = y4 - (y4 - y1) / 3.0; Collection splitBoundingBoxes = new Collection(); splitBoundingBoxes.Add(new RectangleShape(x1, y1, x2, y2)); splitBoundingBoxes.Add(new RectangleShape(x2, y1, x3, y2)); splitBoundingBoxes.Add(new RectangleShape(x3, y1, x4, y2)); splitBoundingBoxes.Add(new RectangleShape(x1, y2, x2, y3)); splitBoundingBoxes.Add(new RectangleShape(x2, y2, x3, y3)); splitBoundingBoxes.Add(new RectangleShape(x3, y2, x4, y3)); splitBoundingBoxes.Add(new RectangleShape(x1, y3, x2, y4)); splitBoundingBoxes.Add(new RectangleShape(x2, y3, x3, y4)); splitBoundingBoxes.Add(new RectangleShape(x3, y3, x4, y4)); return splitBoundingBoxes; } } } ====Extractor.cs==== using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.SQLite; using System.Text; using ThinkGeo.MapSuite.Core; using System.Linq; using WorldMapKitDataExtractor.Model; namespace WorldMapKitDataExtractor { public class Extractor { private string inputDataPath; private string outputDataPath; private string inputDataPrj; private string boundaryPrj; private bool preserveCountryLevelData; public Extractor(string inputDataPath, string outputDataPath, string inputDataPrj = null, string boundaryPrj = null, bool preserveCountryLevelData = true) { this.inputDataPath = inputDataPath; this.outputDataPath = outputDataPath; this.inputDataPrj = inputDataPrj; this.boundaryPrj = boundaryPrj; this.preserveCountryLevelData = preserveCountryLevelData; } public Action UpdateStatus { get; set; } public string InputDataPath { get { return inputDataPath; } set { inputDataPath = value; } } public string OutputDataPath { get { return outputDataPath; } set { outputDataPath = value; } } public string InputDataPrj { get { return inputDataPrj; } set { inputDataPrj = value; } } public string BoundaryPrj { get { return boundaryPrj; } set { boundaryPrj = value; } } public bool PreserveCountryLevelData { get { return preserveCountryLevelData; } set { preserveCountryLevelData = value; } } public void ExtractDataByShape(Collection boundaryFeatureSet) { UpdateStatus("Beginning to extract world map kit data by shape file."); Collection projectedBoundaryFeaturesWithZoomLevels = new Collection(); Collection projectedBoundingBoxes = new Collection(); foreach (BoundingBoxWithZoomLevels boundaryFeatureWithZoomLevels in boundaryFeatureSet) { RectangleShape projectedBoundaryFeature = ProjectBoundingBox(boundaryFeatureWithZoomLevels.BoundingBox); projectedBoundaryFeaturesWithZoomLevels.Add(new BoundingBoxWithZoomLevels(projectedBoundaryFeature, boundaryFeatureWithZoomLevels.StartingZoomLevel, boundaryFeatureWithZoomLevels.EndingZoomLevel)); projectedBoundingBoxes.Add(projectedBoundaryFeature); } SQLiteConnection.CreateFile(outputDataPath); SQLiteConnection targetDatabaseConnection = new SQLiteConnection($"Data Source={outputDataPath};Version=3;"); targetDatabaseConnection.Open(); SQLiteConnection sourceDatabaseConnection = new SQLiteConnection($"Data Source={inputDataPath};Version=3;"); sourceDatabaseConnection.Open(); //this is the set of layers we use to determine which tables to grab for each bounding area OsmWorldMapKitLayer wmkLayer = new OsmWorldMapKitLayer(sourceDatabaseConnection.ConnectionString, OsmWorldMapKitDatabaseType.Sqlite); wmkLayer.Open(); CopyDataToABuffer(GetBoundingBoxesForLayers(projectedBoundaryFeaturesWithZoomLevels, sourceDatabaseConnection, wmkLayer.Layers), sourceDatabaseConnection); ProcessBaselandByShapes(projectedBoundingBoxes, targetDatabaseConnection); UpdateStatus("Executing vacuum for output database."); ExecuteNonQueryCommand("VACUUM;", targetDatabaseConnection); targetDatabaseConnection.Close(); targetDatabaseConnection.Dispose(); UpdateStatus("Done extracting world map kit data!"); } private void CopyDataToABuffer(Dictionary> layersWithBoundingShapes, SQLiteConnection sourceDatabaseConnection) { Proj4Projection proj4 = new Proj4Projection(inputDataPrj, inputDataPrj); GeographyUnit geographyUnit = proj4.GetInternalGeographyUnit(); //OSM WorldMapKit contains several views and view indices that we want to grab as well for our OSMLayer, so we create temporary tables of the data from these within the boundingbox var views = GetViews(sourceDatabaseConnection); foreach (View view in views) { if (layersWithBoundingShapes.Keys.Where(featureLayer => featureLayer.Name == view.Name).Count() > 0) { Collection boundingBoxes = layersWithBoundingShapes[layersWithBoundingShapes.Keys.Where(featureLayer => featureLayer.Name == view.Name).ElementAt(0)]; CreateTempTableForView(view, boundingBoxes, sourceDatabaseConnection); } else { //create the table so the database is valid CreateTempTableForView(view, new Collection() { new RectangleShape(0, 0, 0, 0) }, sourceDatabaseConnection); } } //get the features from every table within the bounding box and add them to the temporary output file var tables = GetTables(sourceDatabaseConnection); foreach (var table in tables) { UpdateStatus($"Copying {table.TableName} table to output database."); SqliteFeatureSource source = new SqliteFeatureSource($@"Data Source={inputDataPath};Version=3;", table.TableName); source.Open(); Collection intersectFeatures = new Collection(); if (layersWithBoundingShapes.Keys.Where(featureLayer => featureLayer.Name == table.TableName).Count() > 0) { intersectFeatures = GetFeaturesIntersects(source, layersWithBoundingShapes[layersWithBoundingShapes.Keys.Where(featureLayer => featureLayer.Name == table.TableName).ElementAt(0)], ReturningColumnsType.AllColumns); } Collection targetTables = SqliteFeatureSource.GetTableNames($@"Data Source={outputDataPath};Version=3;"); if (!targetTables.Contains(table.TableName)) SqliteFeatureSource.CreateTable($@"Data Source={outputDataPath};Version=3;", table.TableName, table.Columns, geographyUnit); SqliteFeatureSource tempSource = new SqliteFeatureSource($@"Data Source={outputDataPath};Version=3;", table.TableName); tempSource.Open(); tempSource.BeginTransaction(); int counter = 0; UpdateStatus($"Adding <1000 new features."); foreach (var feature in intersectFeatures.Distinct(new FeatureComparer())) { tempSource.AddFeature(feature); counter++; if (counter % 1000 == 0) { UpdateStatus($"Adding {counter} new features."); } } UpdateStatus("Commiting sqlite database transaction."); tempSource.CommitTransaction(); tempSource.Close(); } } private void ProcessBaselandByShapes(Collection boundingBoxes, SQLiteConnection connection) { UpdateStatus("Processing baseland by shapes."); if (!preserveCountryLevelData) return; //remove full world bounding box from boundary features boundingBoxes.RemoveAt(0); SqliteFeatureSource baselandFeatureSource = new SqliteFeatureSource(connection.ConnectionString, "osm_baseland_polygon", "id", "geometry"); SqliteFeatureSource baseland1mFeatureSource = new SqliteFeatureSource(connection.ConnectionString, "osm_baseland1m_polygon", "id", "geometry"); baselandFeatureSource.Open(); baseland1mFeatureSource.Open(); UpdateStatus("Querying baseland features from osm_baseland_polygon table."); List baselandFeatures = new List(); foreach (var boundingBox in boundingBoxes) { Collection features = baselandFeatureSource.SpatialQuery(boundingBox, QueryType.Intersects, ReturningColumnsType.NoColumns); baselandFeatures.AddRange(features); } UpdateStatus("Querying baseland1m features from osm_baseland1m_polygon table."); Collection baseland1mFeatures = baseland1mFeatureSource.GetAllFeatures(ReturningColumnsType.NoColumns); if (baselandFeatures.Count == 0 || baseland1mFeatures.Count == 0) { UpdateStatus("Cannot process baseland by shapes - one or more tables is empty"); return; } Collection newBaselandFeatures = new Collection(); int counter = 0; UpdateStatus($"Getting <1000 intersection features for baseland feature."); foreach (Feature feature in baselandFeatures) { Feature validFeature = SqlTypesGeometryHelper.MakeValid(feature); Feature intersectionFeature = GetInterSection(validFeature, boundingBoxes); if (!(intersectionFeature == null)) { newBaselandFeatures.Add(intersectionFeature); counter++; if (counter % 1000 == 0) { UpdateStatus($"Getting {counter} intersection features for baseland feature."); } } } counter = 0; UpdateStatus($"Getting <1000 difference features for baseland1m feature."); foreach (Feature feature in baseland1mFeatures) { if (IsDisjointed(feature, boundingBoxes)) { newBaselandFeatures.Add(feature); counter++; } else { Feature validFeature = SqlTypesGeometryHelper.MakeValid(feature); Feature difference = GetDifference(validFeature, boundingBoxes); if (difference != null) { newBaselandFeatures.Add(difference); counter++; } } if (counter != 0 && counter % 1000 == 0) { UpdateStatus($"Getting {counter} difference features for baseland1m feature."); } } baselandFeatureSource.BeginTransaction(); UpdateStatus("Deleting table osm_baseland_polygon."); baselandFeatureSource.ExecuteNonQuery("DELETE FROM osm_baseland_polygon;"); UpdateStatus("Deleting table idx_osm_baseland_polygon_geometry."); baselandFeatureSource.ExecuteNonQuery("DELETE FROM idx_osm_baseland_polygon_geometry;"); counter = 0; UpdateStatus($"Adding <1000 new features."); foreach (Feature f in newBaselandFeatures) { Feature feature = new Feature(f.GetWellKnownBinary()); baselandFeatureSource.AddFeature(feature); counter++; if (counter % 1000 == 0) { UpdateStatus($"Adding {counter} new features."); } } UpdateStatus("Commiting sqlite database transaction."); baselandFeatureSource.CommitTransaction(); } private Collection GetViews(SQLiteConnection connection) { // Here we query all of the views SQLiteCommand getTablesCommand = new SQLiteCommand(@"SELECT name, sql FROM sqlite_master WHERE (type='view');", connection); SQLiteDataReader getTablesreader = getTablesCommand.ExecuteReader(); Collection views = new Collection(); // Add the views into a collection while (getTablesreader.Read()) { string viewName = getTablesreader.GetValue(0).ToString(); string createStatement = getTablesreader.GetValue(1).ToString(); //Extract the base table from the create statement //Get rid of new lines string baseTable = createStatement.Replace("\n", ""); //Get rid of tabs baseTable = baseTable.Replace("\t", ""); //Get only the text after the "FROM" Statement baseTable = baseTable.Substring(baseTable.LastIndexOf("FROM ") + "FROM ".Length); //Get only the text before tho "WHERE" statement //uses inline if to handle the case of no "WHERE" statement //see osm_address_point for an example of this baseTable = baseTable.Substring(0, baseTable.LastIndexOf("WHERE") > 0 ? baseTable.LastIndexOf("WHERE") : baseTable.Length); //Get rid of any leading or trailing spaces that might exist baseTable = baseTable.Trim(); View view = new View(viewName, baseTable, createStatement); views.Add(view); } return views; } private Collection GetTables(SQLiteConnection connection) { // Here we query all of the tables which are not master tables or the indexes SQLiteCommand getTablesCommand = new SQLiteCommand(@"SELECT sqlite_master.name FROM sqlite_master LEFT OUTER JOIN sqlite_temp_master ON sqlite_master.name = sqlite_temp_master.name WHERE (sqlite_master.type = 'table' OR sqlite_temp_master.type = 'table') AND sqlite_master.name NOT LIKE 'sqlite_%' and sqlite_master.name NOT LIKE 'idx_%' and sqlite_master.name NOT LIKE 'planet_%'", connection); SQLiteDataReader getTablesreader = getTablesCommand.ExecuteReader(); Collection
tables = new Collection
(); // Add the tables into a collection of table objects while (getTablesreader.Read()) { Table table = new Table(); table.TableName = getTablesreader.GetValue(0).ToString(); table.Columns = new Collection(); tables.Add(table); } // Cleanup the table reader and command getTablesreader.Close(); getTablesreader.Dispose(); // For each table we now get and load the column names and data types foreach (Table table in tables) { // Get the column info for the table SQLiteCommand getTableSchemasCommand = new SQLiteCommand(string.Format("Pragma table_info({0});", table.TableName), connection); SQLiteDataReader getSchemaReader = getTableSchemasCommand.ExecuteReader(); while (getSchemaReader.Read()) { string columnName = getSchemaReader.GetValue(1).ToString(); string columnType = getSchemaReader.GetValue(2).ToString(); if (!(columnName.Equals("geometry") || columnName.Equals("id"))) { switch (columnType) { case "character varying": table.Columns.Add(new SqliteColumn() { ColumnName = columnName, ColumnType = SqliteColumnType.Text }); break; case "bigint": case "INT": table.Columns.Add(new SqliteColumn() { ColumnName = columnName, ColumnType = SqliteColumnType.Integer }); break; case "double precision": table.Columns.Add(new SqliteColumn() { ColumnName = columnName, ColumnType = SqliteColumnType.Real }); break; case "numeric": table.Columns.Add(new SqliteColumn() { ColumnName = columnName, ColumnType = SqliteColumnType.Text }); break; default: table.Columns.Add(new SqliteColumn() { ColumnName = columnName, ColumnType = (SqliteColumnType)Enum.Parse(typeof(SqliteColumnType), columnType, true) }); break; } } } // Cleanup the column command and reader getSchemaReader.Close(); getSchemaReader.Dispose(); } return tables; } private void CreateTempTableForView(View view, Collection boundingBoxes, SQLiteConnection sourceDatabaseConnection) { UpdateStatus($"Creating temporary table for {view.Name}"); StringBuilder createNewTempTableFromViewCommand = new StringBuilder(); createNewTempTableFromViewCommand.AppendFormat("CREATE TEMP TABLE {0} AS ", view.Name); createNewTempTableFromViewCommand.AppendFormat("SELECT * FROM {0} WHERE id in (", view.Name); createNewTempTableFromViewCommand.AppendFormat("SELECT id FROM {0} WHERE id in (", view.BaseTable); createNewTempTableFromViewCommand.AppendFormat("SELECT id from idx_{0}_geometry WHERE (maxx < {1} AND maxy < {2} AND minx > {3} AND miny > {4})", view.Name, boundingBoxes[0].UpperRightPoint.X, boundingBoxes[0].UpperRightPoint.Y, boundingBoxes[0].LowerLeftPoint.X, boundingBoxes[0].LowerLeftPoint.Y); for (int i = 1; i < boundingBoxes.Count; i++) { createNewTempTableFromViewCommand.AppendFormat(" OR (maxx < {0} AND maxy < {1} AND minx > {2} AND miny > {3})", boundingBoxes[i].UpperRightPoint.X, boundingBoxes[i].UpperRightPoint.Y, boundingBoxes[i].LowerLeftPoint.X, boundingBoxes[i].LowerLeftPoint.Y); } createNewTempTableFromViewCommand.AppendFormat("));"); ExecuteNonQueryCommand(createNewTempTableFromViewCommand.ToString(), sourceDatabaseConnection); } private void ExecuteNonQueryCommand(StringBuilder commandText, SQLiteConnection connection) { ExecuteNonQueryCommand(commandText.ToString(), connection); } private void ExecuteNonQueryCommand(string commandText, SQLiteConnection connection) { SQLiteCommand command = new SQLiteCommand(commandText, connection); command.ExecuteNonQuery(); command.Dispose(); } private RectangleShape ProjectBoundingBox(RectangleShape boundingBox) { Proj4Projection proj = new Proj4Projection(boundaryPrj, inputDataPrj); proj.Open(); RectangleShape projectedBoundaryFeature = proj.ConvertToExternalProjection(boundingBox); proj.Close(); return projectedBoundaryFeature; } private Collection GetFeaturesIntersects(FeatureSource source, Collection boundingBoxes, ReturningColumnsType returningColumnsType) { List results = new List(); foreach (var boundingBox in boundingBoxes) { Collection allPossibleFeatures = source.GetFeaturesInsideBoundingBox(boundingBox, returningColumnsType); Collection returnFeatures = new Collection(); foreach (Feature feature in allPossibleFeatures) { ShapeValidationResult validationResult = feature.GetShape().Validate(ShapeValidationMode.Simple); if (validationResult.IsValid && feature.GetShape().Intersects(boundingBox)) { returnFeatures.Add(feature); } } results.AddRange(returnFeatures); } return new Collection(results); } private Dictionary> GetBoundingBoxesForLayers(Collection boundaryFeatures, SQLiteConnection sourceDatabaseConnection, Collection featureLayers) { Dictionary> layersWithBoundingBoxes = new Dictionary>(); foreach (BoundingBoxWithZoomLevels boundingBoxParameters in boundaryFeatures) { Collection layersForBoundingBoxes = GetAllFeatureLayers(featureLayers, boundingBoxParameters.StartingZoomLevel, boundingBoxParameters.EndingZoomLevel); foreach (FeatureLayer featureLayer in layersForBoundingBoxes) { if (!layersWithBoundingBoxes.Keys.Contains(featureLayer)) { var boxes = new Collection(); boxes.Add(boundingBoxParameters.BoundingBox); layersWithBoundingBoxes.Add(featureLayer, boxes); } else { layersWithBoundingBoxes[featureLayer].Add(boundingBoxParameters.BoundingBox); } } } return layersWithBoundingBoxes; } private Collection GetAllFeatureLayers(Collection featureLayers, int fromZoomLevelNumber, int toZoomLevelNumber) { Collection featureLayersForZoomLevels = new Collection(); Dictionary> allZoomLevelFeatureLayers = GetAllFeatureLayersCore(featureLayers); for (int i = fromZoomLevelNumber; i <= toZoomLevelNumber; i++) { foreach (FeatureLayer featureLayer in allZoomLevelFeatureLayers[i]) { if (!featureLayersForZoomLevels.Contains(featureLayer)) { featureLayersForZoomLevels.Add(featureLayer); } } } return featureLayersForZoomLevels; } private Dictionary> GetAllFeatureLayersCore(Collection featureLayers) { Dictionary> featureLayersInAllZoomLevels = new Dictionary>(); for (int i = 1; i <= 20; i++) { featureLayersInAllZoomLevels.Add(i, new Collection()); } foreach (FeatureLayer layer in featureLayers) { Collection layerZoomLevels = layer.ZoomLevelSet.GetZoomLevels(); for (int i = 1; i <= 20; i++) { ZoomLevel zoomLevel = layerZoomLevels[i - 1]; if (zoomLevel.CustomStyles.Count != 0 || !IsDefaultStyleSet(zoomLevel)) { if ((int)zoomLevel.ApplyUntilZoomLevel == 0) { if (!featureLayersInAllZoomLevels[i].Contains(layer)) { featureLayersInAllZoomLevels[i].Add(layer); } } else { for (int j = i; j <= (int)zoomLevel.ApplyUntilZoomLevel; j++) { if (!featureLayersInAllZoomLevels[j].Contains(layer)) { featureLayersInAllZoomLevels[j].Add(layer); } } } } } } return featureLayersInAllZoomLevels; } private bool IsDefaultStyleSet(ZoomLevel zoomLevel) { return IsDefaultAreaStyle(zoomLevel.DefaultAreaStyle) && IsDefaultLineStyle(zoomLevel.DefaultLineStyle) && IsDefaultPointStyle(zoomLevel.DefaultPointStyle) && IsDefaultTextStyle(zoomLevel.DefaultTextStyle); } private bool IsDefaultAreaStyle(AreaStyle style) { if (!style.IsActive) { return true; } bool isDefault = false; if (style.OutlinePen.Color.IsTransparent && style.FillSolidBrush.Color.IsTransparent && style.OutlinePen.Brush is GeoSolidBrush) { isDefault = true; } if (isDefault && style.Advanced.FillCustomBrush != null) { isDefault = false; } if (isDefault && style.CustomAreaStyles.Count != 0) { isDefault = false; } return isDefault; } private bool IsDefaultLineStyle(LineStyle style) { if (!style.IsActive) { return true; } bool isDefault = false; if (style.OuterPen.Color.IsTransparent && style.InnerPen.Color.IsTransparent && style.CenterPen.Color.IsTransparent) { if (style.OuterPen.Brush is GeoSolidBrush && style.InnerPen.Brush is GeoSolidBrush && style.CenterPen.Brush is GeoSolidBrush) { isDefault = true; } } if (style.CustomLineStyles.Count > 0) { isDefault = false; } return isDefault; } private bool IsDefaultPointStyle(PointStyle style) { if (!style.IsActive) { return true; } switch (style.PointType) { case PointType.Symbol: bool isDefault = false; if (style.SymbolPen.Color.IsTransparent && style.SymbolSolidBrush.Color.IsTransparent && style.SymbolPen.Brush is GeoSolidBrush) { isDefault = true; } if (isDefault && style.Advanced.CustomBrush != null) { isDefault = false; } return isDefault && style.CustomPointStyles.Count == 0; case PointType.Bitmap: return style.Image == null && style.CustomPointStyles.Count == 0; case PointType.Character: return style.CharacterSolidBrush.Color.IsTransparent && style.CustomPointStyles.Count == 0; default: return true; } } private bool IsDefaultTextStyle(TextStyle style) { if (!style.IsActive) { return true; } bool isDefault = false; if (style.TextSolidBrush.Color.IsTransparent) { isDefault = true; } if (isDefault && style.Advanced.TextCustomBrush != null) { isDefault = false; } return isDefault; } private Feature GetInterSection(Feature feature, Collection boundingBoxes) { Feature result = null; foreach (var boundingBox in boundingBoxes) { var intersection = feature.GetIntersection(boundingBox.GetFeature()); if (result == null) { result = intersection; } else if (intersection != null) { result = result.Union(intersection); } } return result; } private bool IsDisjointed(Feature feature, Collection boundingBoxes) { bool result = true; foreach (var boundingBox in boundingBoxes) { result = result && feature.IsDisjointed(boundingBox.GetFeature()); } return result; } private Feature GetDifference(Feature feature, Collection boundingBoxes) { Feature result = null; foreach (var boundingBox in boundingBoxes) { if (result == null) { result = SqlTypesGeometryHelper.GetDifference(feature, boundingBox.GetFeature()); } else { result = SqlTypesGeometryHelper.GetDifference(result, boundingBox.GetFeature()); } } return result; } } } ====Column.cs==== namespace WorldMapKitDataExtractor { public class Column { public string ColumnName { get; set; } public string DataType { get; set; } } } ====Table.cs==== using System.Collections.ObjectModel; namespace WorldMapKitDataExtractor { public class Table { public string TableName { get; set; } public Collection Columns { get; set; } } } ====View.cs==== namespace WorldMapKitDataExtractor { public class View { public View(string name, string baseTable) { this.Name = name; this.BaseTable = baseTable; } public string Name { get; set; } public string BaseTable { get; set; } } } ====BoundingBoxRow.cs==== namespace WorldMapKitDataExtractor.Model { public class BoundingBoxRow { public System.Windows.Controls.TextBox txtUpperLeftPoint { get; set; } public System.Windows.Controls.TextBox txtLowerRightPoint { get; set; } public System.Windows.Controls.ComboBox cmbStartZoomLevel { get; set; } public System.Windows.Controls.ComboBox cmbEndZoomLevel { get; set; } public System.Windows.Controls.CheckBox chkRowEnabled { get; set; } public BoundingBoxRow() { } public BoundingBoxRow(System.Windows.Controls.TextBox txtUpperLeftPoint, System.Windows.Controls.TextBox txtLowerRightPoint, System.Windows.Controls.ComboBox cmbStartZoomLevel, System.Windows.Controls.ComboBox cmbEndZoomLevel, System.Windows.Controls.CheckBox chkRowEnabled) { this.txtUpperLeftPoint = txtUpperLeftPoint; this.txtLowerRightPoint = txtLowerRightPoint; this.cmbStartZoomLevel = cmbStartZoomLevel; this.cmbEndZoomLevel = cmbEndZoomLevel; this.chkRowEnabled = chkRowEnabled; } } } ====BoundingBoxWithZoomLevels.cs==== using ThinkGeo.MapSuite.Core; namespace WorldMapKitDataExtractor.Model { public struct BoundingBoxWithZoomLevels { public RectangleShape BoundingBox { get; } public int StartingZoomLevel { get; } public int EndingZoomLevel { get; } public BoundingBoxWithZoomLevels(RectangleShape boundingBox, int startingZoomLevel, int endingZoomLevel) { this.BoundingBox = boundingBox; this.StartingZoomLevel = startingZoomLevel; this.EndingZoomLevel = endingZoomLevel; } } } ====AssemblyInfo.cs==== using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("WorldMapKitDataExtractor")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("WorldMapKitDataExtractor")] [assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] //In order to begin building localizable applications, set //CultureYouAreCodingWith in your .csproj file //inside a . For example, if you are using US english //in your source files, set the to en-US. Then uncomment //the NeutralResourceLanguage attribute below. Update the "en-US" in //the line below to match the UICulture setting in the project file. //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] [assembly: ThemeInfo( ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located //(used if a resource is not found in the page, // or application resource dictionaries) ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located //(used if a resource is not found in the page, // app, or any theme specific resource dictionaries) )] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ====Resources.Designer.cs==== //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace WorldMapKitDataExtractor.Properties { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WorldMapKitDataExtractor.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } } } ====Settings.Designer.cs==== //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace WorldMapKitDataExtractor.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { get { return defaultInstance; } } } }