====== Source Code Routing Index Generator.zip ======
====RoutingIndexGenerator.cs====
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.Routing;
namespace RoutingIndexGenerator
{
public partial class RoutingIndexGenerator : Form
{
// If the area is more than 1,000,000 square miles, we would throw a warning as the index generating might take too much time.
private double warningAreaInSquareMiles = 1000000;
private ConfigModel currentConfigModel;
private RoutingIndexBuilder routingIndexbuilder;
private Dictionary configModelsDictionary;
public RoutingIndexGenerator()
{
InitializeComponent();
configModelsDictionary = new Dictionary();
if (File.Exists("InitConfig.xml"))
{
ConfigModel model = new ConfigModel("InitConfig.xml");
string key = model.FileType.Split('|').Last();
configModelsDictionary.Add(key, model);
}
if (File.Exists("WkbConfig.xml"))
{
ConfigModel model = new ConfigModel("WkbConfig.xml");
string key = model.FileType.Split('|').Last();
configModelsDictionary.Add(key, model);
}
// We will always load shapefile configuration by default, even there is no configuration file.
if (!configModelsDictionary.Any(i => i.Value.FileType.Contains("*.shp")))
{
ConfigModel model = new ConfigModel(XDocument.Parse(Properties.Resources.DefaultConfig));
string key = model.FileType.Split('|').Last();
configModelsDictionary.Add(key, model);
}
}
private void btnBrowseSqliteFile_Click(object sender, EventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filter = GetSelectFileFilter();
if (fileDialog.ShowDialog() == DialogResult.OK)
{
string currentKey = string.Format("*.{0}", fileDialog.FileName.Split('.').Last());
currentConfigModel = configModelsDictionary[currentKey];
// Get the bounding box of the feature source.
FeatureSource featureSource = null;
if (currentConfigModel.FileType.EndsWith(".sqlite", StringComparison.InvariantCultureIgnoreCase))
{
featureSource = new SqliteFeatureSource(string.Format("Data Source={0};Version=3;", fileDialog.FileName), currentConfigModel.TableName, currentConfigModel.FeatureIdColumn, currentConfigModel.GeometryColumnName);
}
if (currentConfigModel.FileType.EndsWith(".shp", StringComparison.InvariantCultureIgnoreCase))
{
featureSource = new ShapeFileFeatureSource(fileDialog.FileName);
((ShapeFileFeatureSource)featureSource).RequireIndex = false;
}
if (currentConfigModel.FileType.EndsWith(".wkb", StringComparison.InvariantCultureIgnoreCase))
{
featureSource = new WkbFileFeatureSource(fileDialog.FileName);
}
featureSource.Open();
WellKnownType wellKnownType = featureSource.GetFirstFeaturesWellKnownType();
if (wellKnownType != WellKnownType.Line && wellKnownType != WellKnownType.Multiline)
{
ShowErrorMessageBox();
return;
}
txtDataProviderFilePath.Text = fileDialog.FileName;
txtRoutableFile.Text = Path.ChangeExtension(fileDialog.FileName, ".routable.shp");
txtIndexFilePath.Text = Path.ChangeExtension(fileDialog.FileName, ".routable.rtg");
RectangleShape boundingBox = featureSource.GetBoundingBox();
txtUpperLeftX.Text = string.Format("{0},{1}", boundingBox.UpperLeftPoint.X, boundingBox.UpperLeftPoint.Y);
txtLowerRightX.Text = string.Format("{0},{1}", boundingBox.LowerRightPoint.X, boundingBox.LowerRightPoint.Y);
// Get the columns of the feature source.
Collection columns = featureSource.GetColumns();
featureSource.Close();
if (boundingBox.UpperLeftPoint.X < -180 || boundingBox.UpperLeftPoint.Y > 90 || boundingBox.LowerRightPoint.X > 180 || boundingBox.LowerRightPoint.Y < -90)
{
cmbGeographyUnit.SelectedIndex = 2;
}
else
{
cmbGeographyUnit.SelectedIndex = 0;
}
InitCombColumns(cmbOnewayRoadColumn, columns, currentConfigModel.IdentifierColumnName);
InitCombColumns(cmbOnewayIndicatorColumn, columns, currentConfigModel.IndicatorColumnName);
InitCombColumns(cmbRoadClassColumn, columns, currentConfigModel.SpeedColumnName);
InitCombColumns(cmbSpeedColumn, columns, currentConfigModel.SpeedColumnName);
InitCombColumns(cmbClosedRoadColumn, columns, currentConfigModel.ClosedColumnName);
if (currentConfigModel.RoutingIndexType == 0)
{
rbtnClassSpeed.Checked = true;
tbOptions.Enabled = true;
}
cmbRouteIndexType.SelectedIndex = currentConfigModel.RoutingIndexType;
cmbSpeedUnit.SelectedIndex = currentConfigModel.SpeedUnit;
txtDefaultSpeed.Text = currentConfigModel.DefaultSpeed.ToString();
txtOneWayRoadValue.Text = currentConfigModel.IdentifierColumnValue;
txtFromToValue.Text = currentConfigModel.IndicatorStartEndValue;
btnGenerate.Enabled = true;
}
}
private void btnGenerate_Click(object sender, EventArgs e)
{
RoutingIndexBuilderParameters buildRoutingIndexParameters = GetIndexBuildingParameters();
if (buildRoutingIndexParameters == null)
{
return;
}
//create a new RoutingIndexFileBuilder.
routingIndexbuilder = new RoutingIndexBuilder(buildRoutingIndexParameters);
//Add an event to display refresh the ProgressBar.
routingIndexbuilder.ExtractingSqliteDatabase += routingIndexbuilder_ExtractingSqliteDatabase;
routingIndexbuilder.BuildingRoutableSegment += routingIndexbuilder_BuildingRoutableSegment;
routingIndexbuilder.BuildingRouteRTSegment += routingIndexbuilder_BuildingRouteSegment;
routingIndexbuilder.BuildingIndexFinished += routingIndexbuilder_BuildingIndexFinished;
routingIndexbuilder.BuildingShapeFileIndex += routingIndexbuilder_BuildingShapeFileIndex;
btnGenerate.Enabled = false;
//Start building index file(.rtg).
Task.Factory.StartNew(() =>
{
routingIndexbuilder.ExtractRoadsFromSqliteToShapefileWithLowerMemory(currentConfigModel);
routingIndexbuilder.StartBuildingRoutableFile();
routingIndexbuilder.StartBuildingRtgFile();
});
}
private void routingIndexbuilder_BuildingShapeFileIndex(object sender, RoutingIndexBuilderEventArgs e)
{
if (e.ProcessedRecordCount % 100 == 0 || e.ProcessedRecordCount == e.TotalRecordCount)
{
this.BeginInvoke(new Action(() =>
{
lblProcessingMessage.Text = string.Format("Building shape file index: {0}/{1}", e.ProcessedRecordCount, e.TotalRecordCount);
pgbBuildProgress.Value = (int)(((double)e.ProcessedRecordCount / (double)e.TotalRecordCount) * 100);
}));
}
}
private void routingIndexbuilder_BuildingIndexFinished(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
btnGenerate.Enabled = true;
MessageBox.Show(this, "Generation Completed!", "Completed");
}));
}
private void routingIndexbuilder_ExtractingSqliteDatabase(object sender, RoutingIndexBuilderEventArgs e)
{
if (e.ProcessedRecordCount % 100 == 0 || e.ProcessedRecordCount == e.TotalRecordCount)
{
this.BeginInvoke(new Action(() =>
{
lblProcessingMessage.Text = string.Format("Generating Index (1/3): Extracting source file: {0}/{1}", e.ProcessedRecordCount, e.TotalRecordCount);
pgbBuildProgress.Value = (int)(((double)e.ProcessedRecordCount / (double)e.TotalRecordCount) * 100); ;
}));
}
}
private void routingIndexbuilder_BuildingRoutableSegment(object sender, RoutingIndexBuilderEventArgs e)
{
if (e.ProcessedRecordCount % 100 == 0 || e.ProcessedRecordCount == e.TotalRecordCount)
{
this.BeginInvoke(new Action(() =>
{
lblProcessingMessage.Text = string.Format("Generating Index (2/3) Building Routable shape file: {0}/{1}", e.ProcessedRecordCount, e.TotalRecordCount);
pgbBuildProgress.Value = (int)(((double)e.ProcessedRecordCount / (double)e.TotalRecordCount) * 100);
}));
}
}
private void routingIndexbuilder_BuildingRouteSegment(object sender, RoutingIndexBuilderEventArgs e)
{
if (e.ProcessedRecordCount % 100 == 0 || e.ProcessedRecordCount == e.TotalRecordCount)
{
this.BeginInvoke(new Action(() =>
{
lblProcessingMessage.Text = string.Format("Generating Index (3/3) Building rtg file: {0}/{1}", e.ProcessedRecordCount, e.TotalRecordCount);
pgbBuildProgress.Value = (int)(((double)e.ProcessedRecordCount / (double)e.TotalRecordCount) * 100);
}));
}
}
private void btnSaveRtgFile_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.FileName = Path.ChangeExtension(txtDataProviderFilePath.Text, ".routable.rtg"); ;
saveFileDialog.Filter = "Routing Index File(*.rtg)|*.rtg";
saveFileDialog.DefaultExt = ".rtg";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
txtIndexFilePath.Text = saveFileDialog.FileName;
}
}
private void btnSaveRoutableFile_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.FileName = Path.ChangeExtension(txtDataProviderFilePath.Text, ".Routable.shp");
saveFileDialog.Filter = "Shape File(*.shp)|*.shp";
saveFileDialog.DefaultExt = ".shp";
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
this.txtRoutableFile.Text = saveFileDialog.FileName;
}
}
private void SpeedTypeRadioButton_CheckedChanged(object sender, EventArgs e)
{
lblRoadClassColumn.Enabled = rbtnClassSpeed.Checked;
cmbRoadClassColumn.Enabled = rbtnClassSpeed.Checked;
dgvRoadClassSpeed.Enabled = rbtnClassSpeed.Checked;
cmbSpeedColumn.Enabled = rbtnRoadSpeed.Checked;
}
private void cmbRouteIndexType_SelectedIndexChanged(object sender, EventArgs e)
{
bool considerringSpeedLimit = cmbRouteIndexType.SelectedItem.ToString() == "Fastest";
panelRouteSpeedOptions.Enabled = considerringSpeedLimit;
}
private void cmbSpeedUnit_SelectedIndexChanged(object sender, EventArgs e)
{
if (cmbSpeedUnit.SelectedIndex == 0)
{
txtDefaultSpeed.Text = "50";
}
else
{
txtDefaultSpeed.Text = "30";
}
BindRoadClassSpeed();
}
private void cmbOnewayRoadColumn_SelectedIndexChanged(object sender, EventArgs e)
{
bool oneWayIdentifierIsNotNull = (cmbOnewayRoadColumn.SelectedItem.ToString() != string.Empty);
label8.Enabled = oneWayIdentifierIsNotNull;
txtOneWayRoadValue.Enabled = oneWayIdentifierIsNotNull;
panelOneWayIndicator.Enabled = oneWayIdentifierIsNotNull;
}
private void cmbOnewayIndicatorColumn_SelectedIndexChanged(object sender, EventArgs e)
{
bool oneWayIndicatorColumnNotNull = (cmbOnewayIndicatorColumn.SelectedItem.ToString() != string.Empty);
panelOneWayIndicatorDetail.Enabled = oneWayIndicatorColumnNotNull;
}
private void cmbClosedRoadColumn_SelectedIndexChanged(object sender, EventArgs e)
{
bool closedRoadColumnNotNull = (cmbClosedRoadColumn.SelectedItem.ToString() != string.Empty);
panelClosedRoad.Enabled = closedRoadColumnNotNull;
}
private void cmbRoadClassColumn_SelectedIndexChanged(object sender, EventArgs e)
{
BindRoadClassSpeed();
}
private void btnClose_Click(object sender, EventArgs e)
{
if (routingIndexbuilder != null)
{
routingIndexbuilder.CancelBuildingRtgFile();
}
this.Close();
}
private RoutingIndexBuilderParameters GetIndexBuildingParameters()
{
RoutingIndexBuilderParameters buildRoutingIndexParameters = new RoutingIndexBuilderParameters();
buildRoutingIndexParameters.SourceSqlitePathName = txtDataProviderFilePath.Text;
buildRoutingIndexParameters.GeographyUnit = (GeographyUnit)Enum.Parse(typeof(GeographyUnit), cmbGeographyUnit.SelectedItem.ToString());
buildRoutingIndexParameters.RouteIndexType = (RoutingIndexType)Enum.Parse(typeof(RoutingIndexType), cmbRouteIndexType.SelectedItem.ToString());
buildRoutingIndexParameters.RtgFilePathName = txtIndexFilePath.Text;
buildRoutingIndexParameters.RoutableShapeFilePathName = txtRoutableFile.Text;
buildRoutingIndexParameters.BuildRoutingDataMode = chkRebuildRtgFile.Checked ? BuildRoutingDataMode.Rebuild : BuildRoutingDataMode.DoNotRebuild;
buildRoutingIndexParameters.OverrideRoutableFile = chkRebuildRoutableFile.Checked ? true : false;
//Get restrict extent if specify.
if (this.txtUpperLeftX.Text.Split(',').Length == 2 && this.txtUpperLeftX.Text.Split(',').Length == 2)
{
buildRoutingIndexParameters.RestrictExtent = new RectangleShape(double.Parse(this.txtUpperLeftX.Text.Split(',')[0]), double.Parse(this.txtUpperLeftX.Text.Split(',')[1]), double.Parse(this.txtLowerRightX.Text.Split(',')[0]), double.Parse(this.txtLowerRightX.Text.Split(',')[1]));
// Check if restrict extent is too large and give it a warning if does.
if (buildRoutingIndexParameters.RestrictExtent.GetArea(buildRoutingIndexParameters.GeographyUnit, AreaUnit.SquareMiles) > warningAreaInSquareMiles)
{
string routingAreaTooLargeWarning = "The selected area is too big and may take a long time, we suggest making the selected area smaller, do you want to continue anyway?";
if (DialogResult.No == MessageBox.Show(routingAreaTooLargeWarning, "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning))
{
return null;
}
}
}
else
{
MessageBox.Show("Either Upper Left Point or Lower Right Point is not correctly");
return null;
}
// Get the Speed Options.
if (cmbRouteIndexType.SelectedItem.ToString() == "Fastest")
{
buildRoutingIndexParameters.SpeedOption.SpeedUnit = (SpeedUnit)Enum.Parse(typeof(SpeedUnit), cmbSpeedUnit.SelectedIndex.ToString());
buildRoutingIndexParameters.SpeedOption.DefaultSpeed = Convert.ToSingle(txtDefaultSpeed.Text);
buildRoutingIndexParameters.SpeedOption.SpeedSourceType = rbtnClassSpeed.Checked ? RoadSpeedSourceType.BasedOnRoadType : RoadSpeedSourceType.DefinedInAttribution;
buildRoutingIndexParameters.SpeedOption.SpeedColumnName = cmbSpeedColumn.Text;
buildRoutingIndexParameters.SpeedOption.RoadTypeColumnName = cmbRoadClassColumn.Text;
DataTable dataTable = (DataTable)dgvRoadClassSpeed.DataSource;
buildRoutingIndexParameters.SpeedOption.RoadSpeeds.Clear();
foreach (DataRow dataRow in dataTable.Rows)
{
buildRoutingIndexParameters.SpeedOption.RoadSpeeds.Add(dataRow[0].ToString(), Convert.ToDouble(dataRow[1]));
}
}
// Get the One way Road Options.
buildRoutingIndexParameters.OneWayRoadOption.OneWayColumnName = cmbOnewayRoadColumn.Text;
if (buildRoutingIndexParameters.OneWayRoadOption.OneWayColumnName != string.Empty)
{
buildRoutingIndexParameters.IncludeOnewayOptions = true;
buildRoutingIndexParameters.OneWayRoadOption.IndicatorColumnName = cmbOnewayIndicatorColumn.Text;
buildRoutingIndexParameters.OneWayRoadOption.OneWayIdentifier = txtOneWayRoadValue.Text;
buildRoutingIndexParameters.OneWayRoadOption.StartToEnd = txtFromToValue.Text;
buildRoutingIndexParameters.OneWayRoadOption.EndToStart = txtToFromValue.Text;
}
// Get the closed Road Options.
buildRoutingIndexParameters.ClosedRoadOption.ClosedColumnName = cmbClosedRoadColumn.Text;
buildRoutingIndexParameters.ClosedRoadOption.ClosedRoadValue = txtColsedRoad.Text;
return buildRoutingIndexParameters;
}
private void ShowErrorMessageBox()
{
MessageBox.Show(this, "The chosen data doesn't include line shapes. Please choose another one.", "Invalid data", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private string GetSelectFileFilter()
{
string filter = string.Empty;
string allExName = string.Empty;
List fileExNames = new List();
foreach (var item in configModelsDictionary)
{
if (string.IsNullOrEmpty(filter)) filter += item.Value.FileType;
else
{
filter += "|" + item.Value.FileType;
}
if (string.IsNullOrEmpty(allExName)) allExName += item.Key;
else
{
allExName += ";" + item.Key;
}
fileExNames.Add(item.Value.FileType.Split('|').Last());
}
filter += string.Format("|All Surpported Files({0})|{0}", allExName);
return filter;
}
private void BindRoadClassSpeed()
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add("RoadClass");
dataTable.Columns.Add("Speed");
Dictionary roadSpeed = currentConfigModel.RoadSpeedForKPH;
if (cmbSpeedUnit.SelectedIndex == 1)
{
roadSpeed = currentConfigModel.RoadSpeedForMPH;
}
foreach (var item in roadSpeed)
{
DataRow dr = dataTable.NewRow();
dr[0] = item.Key;
dr[1] = item.Value;
dataTable.Rows.Add(dr);
}
dgvRoadClassSpeed.DataSource = dataTable;
}
private void InitCombColumns(ComboBox comboBox, Collection columns, string defaultValue)
{
comboBox.Items.Clear();
comboBox.Items.Add("");
foreach (FeatureSourceColumn item in columns)
{
comboBox.Items.Add(item.ColumnName);
if (item.ColumnName.Equals(defaultValue, StringComparison.InvariantCultureIgnoreCase))
{
comboBox.SelectedIndex = comboBox.Items.Count - 1;
}
}
}
}
}
====RoutingIndexBuilder.cs====
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.Routing;
namespace RoutingIndexGenerator
{
public class RoutingIndexBuilder
{
public event EventHandler BuildingShapeFileIndex;
public event EventHandler ExtractingSqliteDatabase;
public event EventHandler BuildingRoutableSegment;
public event EventHandler BuildingRouteRTSegment;
public event EventHandler BuildingIndexFinished;
private bool cancelBuilding;
private int totalRecordCount;
private int processedRecordCount;
private Feature previousFeature;
private Collection requiredColumns;
private ShapeFileFeatureSource routableFeatureSource;
private RoutingIndexBuilderParameters buildRtgParameter;
public RoutingIndexBuilder()
: this(new RoutingIndexBuilderParameters())
{ }
public RoutingIndexBuilder(RoutingIndexBuilderParameters buildRtgParameter)
{
this.buildRtgParameter = buildRtgParameter;
this.buildRtgParameter.ClosedRoadOption.InitRegexes();
this.buildRtgParameter.OneWayRoadOption.InitRegexes();
RtgRoutingSource.GeneratingRoutableShapeFile += RtgRoutingSource_GeneratingRoutableShapeFile;
RtgRoutingSource.BuildingRoutingData += RtgRoutingSource_BuildingRoutingData;
}
//This method uses lower memory than the other method, but only works with .sqlite files
public void ExtractRoadsFromSqliteToShapefileWithLowerMemory(ConfigModel config)
{
// If don't override routable file, let's skip this step.
if (buildRtgParameter.OverrideRoutableFile || !File.Exists(buildRtgParameter.RoutableShapeFilePathName))
{
SqliteFeatureSource source = new SqliteFeatureSource(string.Format("Data Source={0};Version=3;", buildRtgParameter.SourceSqlitePathName), config.TableName, config.FeatureIdColumn, config.GeometryColumnName);
source.Open();
RectangleShape restrictExtent = buildRtgParameter.RestrictExtent == null ? source.GetBoundingBox() : buildRtgParameter.RestrictExtent;
Collection ids = new Collection();
ids = source.GetFeatureIdsInsideBoundingBox(restrictExtent);
Collection dbfColumns = new Collection();
foreach (string columnName in config.ExtractRequiredColumns)
{
dbfColumns.Add(new DbfColumn(columnName, DbfColumnType.Character, 255, 0));
}
ShapeFileFeatureSource.CreateShapeFile(ShapeFileType.Polyline, buildRtgParameter.SourceShapefilePathName, dbfColumns, Encoding.UTF8, OverwriteMode.Overwrite);
ShapeFileFeatureSource target = new ShapeFileFeatureSource(buildRtgParameter.SourceShapefilePathName, ShapeFileReadWriteMode.ReadWrite);
target.Open();
int processedRecordCount = 0;
int totalRecordCount = ids.Count;
target.BeginTransaction();
//load 10,000 features into memory at a time from the sqlite database
int loadingFeatureCount = 10000;
int startIndex = 0;
int length = 0;
string[] totalIds = new string[ids.Count];
ids.CopyTo(totalIds, 0);
while (startIndex + length < ids.Count)
{
startIndex = startIndex + length;
length = Math.Min(ids.Count - startIndex, loadingFeatureCount);
string[] fetchIds = new string[length];
Array.Copy(totalIds, startIndex, fetchIds, 0, length);
Collection features = source.GetFeaturesByIds(fetchIds, config.ExtractRequiredColumns);
foreach (Feature feature in features)
{
target.AddFeature(feature);
processedRecordCount++;
//write 100,000 features to shapefile at a time
if (processedRecordCount % 100000 == 0)
{
target.CommitTransaction();
target.BeginTransaction();
}
OnExtractingSqliteDatabase(new RoutingIndexBuilderEventArgs(totalRecordCount, processedRecordCount));
}
}
target.CommitTransaction();
target.Close();
source.Close();
}
}
public void ExtractRoadsFromSqliteToShapefile(ConfigModel config)
{
// If don't override routable file, let's skip this step.
if (buildRtgParameter.OverrideRoutableFile || !File.Exists(buildRtgParameter.RoutableShapeFilePathName))
{
FeatureSource source = null;
if (config.FileType.EndsWith(".sqlite", StringComparison.InvariantCultureIgnoreCase))
{
source = new SqliteFeatureSource(string.Format("Data Source={0};Version=3;", buildRtgParameter.SourceSqlitePathName), config.TableName, config.FeatureIdColumn, config.GeometryColumnName);
}
else if (config.FileType.EndsWith(".shp", StringComparison.InvariantCultureIgnoreCase))
{
ShapeFileFeatureSource.BuildingIndex += ShapeFileFeatureSource_BuildingIndex;
ShapeFileFeatureSource.BuildIndexFile(buildRtgParameter.SourceSqlitePathName, BuildIndexMode.DoNotRebuild);
source = new ShapeFileFeatureSource(buildRtgParameter.SourceSqlitePathName);
}
else if (config.FileType.EndsWith(".wkb", StringComparison.InvariantCultureIgnoreCase))
{
source = new WkbFileFeatureSource(buildRtgParameter.SourceSqlitePathName);
}
source.Open();
RectangleShape restrictExtent = buildRtgParameter.RestrictExtent == null ? source.GetBoundingBox() : buildRtgParameter.RestrictExtent;
Collection features = new Collection();
Collection dbfColumns = new Collection();
if (config.ExtractRequiredColumns.Count == 0)
{
features = source.GetFeaturesInsideBoundingBox(restrictExtent, ReturningColumnsType.AllColumns);
foreach (var column in source.GetColumns())
{
dbfColumns.Add(new DbfColumn(column.ColumnName, DbfColumnType.Character, column.MaxLength, 0));
}
}
else
{
features = source.GetFeaturesInsideBoundingBox(restrictExtent, config.ExtractRequiredColumns);
foreach (string columnName in config.ExtractRequiredColumns)
{
dbfColumns.Add(new DbfColumn(columnName, DbfColumnType.Character, 255, 0));
}
}
ShapeFileFeatureSource.CreateShapeFile(ShapeFileType.Polyline, buildRtgParameter.SourceShapefilePathName, dbfColumns, Encoding.UTF8, OverwriteMode.Overwrite);
ShapeFileFeatureSource target = new ShapeFileFeatureSource(buildRtgParameter.SourceShapefilePathName, ShapeFileReadWriteMode.ReadWrite);
target.Open();
int processedRecordCount = 0;
int totalRecordCount = features.Count;
target.BeginTransaction();
foreach (Feature feature in features)
{
target.AddFeature(feature);
processedRecordCount++;
if (processedRecordCount % 100000 == 0)
{
target.CommitTransaction();
target.BeginTransaction();
}
OnExtractingSqliteDatabase(new RoutingIndexBuilderEventArgs(totalRecordCount, processedRecordCount));
}
target.CommitTransaction();
target.Close();
source.Close();
}
}
public void StartBuildingRoutableFile()
{
if (buildRtgParameter.OverrideRoutableFile)
{
ShapeFileFeatureSource sourceFeatureSource = new ShapeFileFeatureSource(buildRtgParameter.SourceShapefilePathName);
sourceFeatureSource.Open();
// reset the process status.
this.processedRecordCount = 0;
this.totalRecordCount = sourceFeatureSource.GetCount();
RtgRoutingSource.GenerateRoutableShapeFile(buildRtgParameter.SourceShapefilePathName, buildRtgParameter.RoutableShapeFilePathName, buildRtgParameter.OverrideRoutableFile ? OverwriteMode.Overwrite : OverwriteMode.DoNotOverwrite, buildRtgParameter.GeographyUnit, 2);
sourceFeatureSource.Close();
}
}
public void StartBuildingRtgFile()
{
routableFeatureSource = new ShapeFileFeatureSource(buildRtgParameter.RoutableShapeFilePathName);
routableFeatureSource.Open();
// reset the process status.
this.processedRecordCount = 0;
this.totalRecordCount = routableFeatureSource.GetCount();
RtgRoutingSource.GenerateRoutingData(buildRtgParameter.RtgFilePathName, buildRtgParameter.SourceShapefilePathName, buildRtgParameter.RoutableShapeFilePathName, buildRtgParameter.BuildRoutingDataMode, buildRtgParameter.GeographyUnit, DistanceUnit.Meter);
routableFeatureSource.Close();
if (cancelBuilding == true)
{
File.Delete(Path.ChangeExtension(buildRtgParameter.RtgFilePathName, ".rtg"));
File.Delete(Path.ChangeExtension(buildRtgParameter.RtgFilePathName, ".rtx"));
}
// clear up the temporary shape files extracted from sqlite.
if (File.Exists(buildRtgParameter.SourceSqlitePathName) && File.Exists(buildRtgParameter.SourceShapefilePathName))
{
string tempShapefile = Path.GetFileNameWithoutExtension(buildRtgParameter.SourceShapefilePathName);
string[] files = Directory.GetFiles(Path.GetDirectoryName(buildRtgParameter.SourceShapefilePathName));
foreach (string file in files)
{
if (Path.GetFileNameWithoutExtension(file).Equals(tempShapefile, StringComparison.InvariantCultureIgnoreCase))
{
File.Delete(file);
}
}
}
OnBuildingIndexFinished(new EventArgs());
}
public void CancelBuildingRtgFile()
{
cancelBuilding = true;
}
private void ShapeFileFeatureSource_BuildingIndex(object sender, BuildingIndexShapeFileFeatureSourceEventArgs e)
{
var handler = BuildingShapeFileIndex;
if (handler != null)
{
handler(this, new RoutingIndexBuilderEventArgs(e.RecordCount, e.CurrentRecordIndex));
}
}
private void RtgRoutingSource_GeneratingRoutableShapeFile(object sender, GeneratingRoutableShapeFileRoutingSourceEventArgs e)
{
if (previousFeature == null)
{
previousFeature = e.PreviousFeature;
}
// we add the previous feature is because this event may be triggered multi times in one feature.
if (previousFeature.Id != e.PreviousFeature.Id)
{
previousFeature = e.PreviousFeature;
this.processedRecordCount++;
OnBuildingRoutableSegment(new RoutingIndexBuilderEventArgs(this.totalRecordCount, this.processedRecordCount));
}
}
private void RtgRoutingSource_BuildingRoutingData(object sender, BuildingRoutingDataRtgRoutingSourceEventArgs e)
{
// Make progressBar move forward a step
this.processedRecordCount++;
OnBuildingRouteRTSegment(new RoutingIndexBuilderEventArgs(this.totalRecordCount, this.processedRecordCount));
// Get the processing Feature
if (requiredColumns == null)
{
requiredColumns = GetRequiredColumns();
}
Feature feature = routableFeatureSource.GetFeatureById(e.RouteSegment.FeatureId, requiredColumns);
if (buildRtgParameter.IncludeOnewayOptions)
{
ProcessOneWayRoad(e, feature, requiredColumns);
}
if (buildRtgParameter.RouteIndexType == RoutingIndexType.Fastest)
{
if (buildRtgParameter.SpeedOption.SpeedSourceType == RoadSpeedSourceType.BasedOnRoadType && !string.IsNullOrEmpty(buildRtgParameter.SpeedOption.RoadTypeColumnName))
{
string featureRoadClassValue = feature.ColumnValues[buildRtgParameter.SpeedOption.RoadTypeColumnName];
e.RouteSegment.Weight = GetDistance(e.RouteSegment.Distance) / GetSpeed(featureRoadClassValue);
}
else if (buildRtgParameter.SpeedOption.SpeedSourceType == RoadSpeedSourceType.DefinedInAttribution && !string.IsNullOrEmpty(buildRtgParameter.SpeedOption.SpeedColumnName))
{
string speedString = feature.ColumnValues[buildRtgParameter.SpeedOption.SpeedColumnName];
float speed = float.TryParse(speedString, out speed) ? speed : buildRtgParameter.SpeedOption.DefaultSpeed;
e.RouteSegment.Weight = GetDistance(e.RouteSegment.Distance) / speed;
}
else
{
e.RouteSegment.Weight = GetDistance(e.RouteSegment.Distance) / buildRtgParameter.SpeedOption.DefaultSpeed;
}
}
e.Cancel = cancelBuilding;
}
private Collection GetRequiredColumns()
{
Collection requiredColumns = new Collection();
if (buildRtgParameter.IncludeOnewayOptions)
{
if (!string.IsNullOrEmpty(buildRtgParameter.OneWayRoadOption.OneWayColumnName))
{
requiredColumns.Add(buildRtgParameter.OneWayRoadOption.OneWayColumnName);
}
if (!string.IsNullOrEmpty(buildRtgParameter.OneWayRoadOption.IndicatorColumnName))
{
requiredColumns.Add(buildRtgParameter.OneWayRoadOption.IndicatorColumnName);
}
}
string speedColumn = string.Empty;
switch (buildRtgParameter.SpeedOption.SpeedSourceType)
{
case RoadSpeedSourceType.BasedOnRoadType:
speedColumn = buildRtgParameter.SpeedOption.RoadTypeColumnName;
break;
case RoadSpeedSourceType.DefinedInAttribution:
speedColumn = buildRtgParameter.SpeedOption.SpeedColumnName;
break;
default:
break;
}
if (!string.IsNullOrEmpty(speedColumn))
{
requiredColumns.Add(speedColumn);
}
return requiredColumns;
}
private void ProcessOneWayRoad(BuildingRoutingDataRtgRoutingSourceEventArgs e, Feature roadFeature, Collection oneWayColumns)
{
LineShape lineShape = GetLineShape(roadFeature);
// handled feature is one-way road
if (buildRtgParameter.OneWayRoadOption.MatchOneWayIdentifier(roadFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.OneWayColumnName]))
{
if (buildRtgParameter.OneWayRoadOption.MatchStartToEnd(roadFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.IndicatorColumnName]))
{
e.RouteSegment.StartPointAdjacentIds.Clear();
}
else if (buildRtgParameter.OneWayRoadOption.MatchEndToStart(roadFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.IndicatorColumnName]))
{
e.RouteSegment.EndPointAdjacentIds.Clear();
}
else if (buildRtgParameter.ClosedRoadOption.MatchClosedRoadValue(roadFeature.ColumnValues[buildRtgParameter.ClosedRoadOption.ClosedColumnName]))
{
e.RouteSegment.StartPointAdjacentIds.Clear();
e.RouteSegment.EndPointAdjacentIds.Clear();
}
}
// analysis adjacent one-way road features
Collection removedStartPointAdjacentIds = GetRemovedAdjacentIds(e.RouteSegment.StartPointAdjacentIds, new PointShape(lineShape.Vertices[0]), oneWayColumns);
foreach (string id in removedStartPointAdjacentIds)
{
e.RouteSegment.StartPointAdjacentIds.Remove(id);
}
Collection removedEndPointAdjacentIds = GetRemovedAdjacentIds(e.RouteSegment.EndPointAdjacentIds, new PointShape(lineShape.Vertices[lineShape.Vertices.Count - 1]), oneWayColumns);
foreach (string id in removedEndPointAdjacentIds)
{
e.RouteSegment.EndPointAdjacentIds.Remove(id);
}
}
private Collection GetRemovedAdjacentIds(Collection adjacentIds, PointShape intersectingPoint, Collection oneWayColumns)
{
Collection removedIds = new Collection();
foreach (string id in adjacentIds)
{
Feature adjacentFeature = routableFeatureSource.GetFeatureById(id, oneWayColumns);
if (buildRtgParameter.OneWayRoadOption.MatchOneWayIdentifier(adjacentFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.OneWayColumnName]))
//if (adjacentFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.OneWayColumnName].Equals(buildRtgParameter.OneWayRoadOption.OneWayIdentifier, StringComparison.InvariantCultureIgnoreCase))
{
LineShape adjacentLineShape = GetLineShape(adjacentFeature);
double distanceFromAdjacentStartToIntersecting = new PointShape(adjacentLineShape.Vertices[0]).GetDistanceTo(intersectingPoint, buildRtgParameter.GeographyUnit, DistanceUnit.Meter);
double distanceFromAdjacentEndToIntersecting = new PointShape(adjacentLineShape.Vertices[adjacentLineShape.Vertices.Count - 1]).GetDistanceTo(intersectingPoint, buildRtgParameter.GeographyUnit, DistanceUnit.Meter);
if (distanceFromAdjacentStartToIntersecting <= distanceFromAdjacentEndToIntersecting && buildRtgParameter.OneWayRoadOption.MatchEndToStart(adjacentFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.IndicatorColumnName]))
//if (distanceFromAdjacentStartToIntersecting <= distanceFromAdjacentEndToIntersecting && adjacentFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.IndicatorColumnName].Equals(buildRtgParameter.OneWayRoadOption.EndToStart))
{
removedIds.Add(id);
}
else if (distanceFromAdjacentEndToIntersecting <= distanceFromAdjacentStartToIntersecting
&& buildRtgParameter.OneWayRoadOption.MatchStartToEnd(adjacentFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.IndicatorColumnName]))
//&& adjacentFeature.ColumnValues[buildRtgParameter.OneWayRoadOption.IndicatorColumnName].Equals(buildRtgParameter.OneWayRoadOption.StartToEnd))
{
removedIds.Add(id);
}
else if (buildRtgParameter.ClosedRoadOption.ClosedColumnName != string.Empty && buildRtgParameter.ClosedRoadOption.MatchClosedRoadValue(adjacentFeature.ColumnValues[buildRtgParameter.ClosedRoadOption.ClosedColumnName]))
//else if (buildRtgParameter.ClosedRoadOption.ClosedColumnName != string.Empty && adjacentFeature.ColumnValues[buildRtgParameter.ClosedRoadOption.ClosedColumnName].Equals(buildRtgParameter.ClosedRoadOption.ClosedRoadValue))
{
removedIds.Add(id);
}
}
}
return removedIds;
}
private float GetSpeed(String featureRoadSpeedClassValue)
{
float result = buildRtgParameter.SpeedOption.DefaultSpeed;
foreach (var item in buildRtgParameter.SpeedOption.RoadSpeeds)
{
if (item.Key.Equals(featureRoadSpeedClassValue, StringComparison.OrdinalIgnoreCase))
{
result = (float)item.Value;
break;
}
}
return result;
}
private float GetDistance(float distanceMeter)
{
switch (buildRtgParameter.SpeedOption.SpeedUnit)
{
case SpeedUnit.KilometersPerHour:
return (float)(distanceMeter * 0.001);
case SpeedUnit.MilesPerHour:
return (float)(distanceMeter * 0.00062137);
}
return distanceMeter;
}
private static LineShape GetLineShape(Feature lineFeature)
{
BaseShape baseShape = lineFeature.GetShape();
LineShape lineShape = baseShape as LineShape;
if (lineShape == null)
{
MultilineShape lineShapes = ((MultilineShape)baseShape);
Collection vertices = new Collection();
foreach (LineShape line in lineShapes.Lines)
{
for (int i = 0; i < line.Vertices.Count; i++)
{
vertices.Add(line.Vertices[i]);
}
}
lineShape = new LineShape(vertices);
lineShape.Id = baseShape.Id;
lineShape.Tag = baseShape.Tag;
}
return lineShape;
}
protected virtual void OnBuildingRouteRTSegment(RoutingIndexBuilderEventArgs e)
{
var handler = BuildingRouteRTSegment;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnBuildingRoutableSegment(RoutingIndexBuilderEventArgs e)
{
var handler = BuildingRoutableSegment;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnExtractingSqliteDatabase(RoutingIndexBuilderEventArgs e)
{
var handler = ExtractingSqliteDatabase;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnBuildingIndexFinished(EventArgs e)
{
var handler = BuildingIndexFinished;
if (handler != null)
{
handler(this, e);
}
}
}
}
====Program.cs====
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace RoutingIndexGenerator
{
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new RoutingIndexGenerator());
}
}
}
====SpeedUnit.cs====
namespace RoutingIndexGenerator
{
public enum SpeedUnit
{
KilometersPerHour = 0,
MilesPerHour = 1
}
}
====RoutingIndexType.cs====
namespace RoutingIndexGenerator
{
public enum RoutingIndexType
{
Fastest = 0,
Shortest = 1
}
}
====RoadSpeedOption.cs====
using System.Collections.Generic;
namespace RoutingIndexGenerator
{
public class RoadSpeedOption
{
private SpeedUnit speedUnit;
private float defaultSpeed;
private RoadSpeedSourceType roadSpeedSourceType;
private string roadSpeedColumnName;
private string roadTypeColumnName;
private Dictionary roadSpeeds;
public RoadSpeedOption()
{
DefaultSpeed = 50;
SpeedUnit = SpeedUnit.KilometersPerHour;
}
public SpeedUnit SpeedUnit
{
get { return speedUnit; }
set { speedUnit = value; }
}
public float DefaultSpeed
{
get { return defaultSpeed; }
set { defaultSpeed = value; }
}
public RoadSpeedSourceType SpeedSourceType
{
get { return roadSpeedSourceType; }
set { roadSpeedSourceType = value; }
}
public string SpeedColumnName
{
get { return roadSpeedColumnName; }
set { roadSpeedColumnName = value; }
}
public string RoadTypeColumnName
{
get { return roadTypeColumnName; }
set { roadTypeColumnName = value; }
}
public Dictionary RoadSpeeds
{
get
{
if (roadSpeeds == null)
{
roadSpeeds = new Dictionary();
}
return roadSpeeds;
}
}
}
}
====OneWayRoadOption.cs====
using System;
using System.Text.RegularExpressions;
namespace RoutingIndexGenerator
{
public class OneWayRoadOption
{
private string oneWayColumnName;
private string oneWayIdentifier;
private string indicatorColumnName;
private string startToEnd;
private string endToStart;
private Regex startToEndRegex;
private Regex endToStartRegex;
private Regex oneWayIdentifierRegex;
public OneWayRoadOption()
{ }
public string OneWayColumnName
{
get { return oneWayColumnName; }
set { oneWayColumnName = value; }
}
public string IndicatorColumnName
{
get { return indicatorColumnName; }
set { indicatorColumnName = value; }
}
public string OneWayIdentifier
{
get { return oneWayIdentifier; }
set { oneWayIdentifier = value; }
}
public string StartToEnd
{
get { return startToEnd; }
set { startToEnd = value; }
}
public string EndToStart
{
get { return endToStart; }
set { endToStart = value; }
}
private Regex GetRegex(string stringToMatch)
{
if (String.IsNullOrEmpty(stringToMatch))
{
return null;
}
Regex regex = null;
if (stringToMatch.StartsWith("[") && stringToMatch.EndsWith("]"))
{
string regexString = stringToMatch.Substring(1, stringToMatch.Length - 2);
regex = new Regex(regexString, RegexOptions.Compiled);
}
return regex;
}
public void InitRegexes()
{
this.endToStartRegex = GetRegex(this.endToStart);
this.startToEndRegex = GetRegex(this.startToEnd);
this.oneWayIdentifierRegex = GetRegex(this.oneWayIdentifier);
}
public bool MatchEndToStart(string endToStart)
{
bool match = false;
if (endToStartRegex == null)
{
match = endToStart.Equals(this.endToStart, StringComparison.InvariantCultureIgnoreCase);
}
else
{
match = endToStartRegex.Match(endToStart).Success;
}
return match;
}
public bool MatchStartToEnd(string startToEnd)
{
bool match = false;
if (startToEndRegex == null)
{
match = startToEnd.Equals(this.startToEnd, StringComparison.InvariantCultureIgnoreCase);
}
else
{
match = startToEndRegex.Match(startToEnd).Success;
}
return match;
}
public bool MatchOneWayIdentifier(string oneWayIdentifier)
{
bool match = false;
if (oneWayIdentifierRegex == null)
{
match = oneWayIdentifier.Equals(this.oneWayIdentifier, StringComparison.InvariantCultureIgnoreCase);
}
else
{
match = oneWayIdentifierRegex.Match(oneWayIdentifier).Success;
}
return match;
}
}
}
====RoutingIndexBuilderParameters.cs====
using System.IO;
using ThinkGeo.MapSuite.Core;
using ThinkGeo.MapSuite.Routing;
namespace RoutingIndexGenerator
{
public class RoutingIndexBuilderParameters
{
private BuildRoutingDataMode buildRoutingDataMode;
private GeographyUnit geographyUnit;
private OneWayRoadOption oneWayRoadOption;
private ClosedRoadOption closedRoadOption;
private RoadSpeedOption speedOption;
private RoutingIndexType routeIndexType;
private RectangleShape restrictExtent;
private string routableShapeFilePathName;
private string rtgFilePathName;
private string sourceSqlitePathName;
private bool includeOnewayOptions;
private bool overrideRoutableFile;
public RoutingIndexBuilderParameters()
{
RouteIndexType = RoutingIndexType.Fastest;
GeographyUnit = GeographyUnit.Meter;
BuildRoutingDataMode = BuildRoutingDataMode.Rebuild;
OneWayRoadOption = new OneWayRoadOption();
closedRoadOption = new ClosedRoadOption();
SpeedOption = new RoadSpeedOption();
overrideRoutableFile = true;
}
public RectangleShape RestrictExtent
{
get { return restrictExtent; }
set { restrictExtent = value; }
}
public BuildRoutingDataMode BuildRoutingDataMode
{
get { return buildRoutingDataMode; }
set { buildRoutingDataMode = value; }
}
public GeographyUnit GeographyUnit
{
get { return geographyUnit; }
set { geographyUnit = value; }
}
public OneWayRoadOption OneWayRoadOption
{
get { return oneWayRoadOption; }
set { oneWayRoadOption = value; }
}
public RoadSpeedOption SpeedOption
{
get { return speedOption; }
set { speedOption = value; }
}
public ClosedRoadOption ClosedRoadOption
{
get { return closedRoadOption; }
set { closedRoadOption = value; }
}
public RoutingIndexType RouteIndexType
{
get { return routeIndexType; }
set { routeIndexType = value; }
}
public string RtgFilePathName
{
get { return rtgFilePathName; }
set { rtgFilePathName = value; }
}
public string RoutableShapeFilePathName
{
get { return routableShapeFilePathName; }
set { routableShapeFilePathName = value; }
}
public string SourceSqlitePathName
{
get { return sourceSqlitePathName; }
set { sourceSqlitePathName = value; }
}
public string SourceShapefilePathName
{
get { return Path.ChangeExtension(sourceSqlitePathName, ".source.shp"); ; }
}
public bool IncludeOnewayOptions
{
get { return includeOnewayOptions; }
set { includeOnewayOptions = value; }
}
public bool OverrideRoutableFile
{
get { return overrideRoutableFile; }
set { overrideRoutableFile = value; }
}
}
}
====RoutingIndexBuilderEventArgs.cs====
using System;
namespace RoutingIndexGenerator
{
public class RoutingIndexBuilderEventArgs : EventArgs
{
private int totalRecordAccount;
private int processedRecordAccount;
public RoutingIndexBuilderEventArgs()
{ }
public RoutingIndexBuilderEventArgs(int totalRecordAccount, int processedRecordAccount)
{
this.totalRecordAccount = totalRecordAccount;
this.processedRecordAccount = processedRecordAccount;
}
public int TotalRecordCount
{
get { return totalRecordAccount; }
set { totalRecordAccount = value; }
}
public int ProcessedRecordCount
{
get { return processedRecordAccount; }
set { processedRecordAccount = value; }
}
}
}
====ClosedRoadOptions.cs====
using System;
using System.Text.RegularExpressions;
namespace RoutingIndexGenerator
{
public class ClosedRoadOption
{
private string closedRoadValue;
private string closedColumnName;
private Regex closedRoadValueRegex;
public string ClosedColumnName
{
get { return closedColumnName; }
set { closedColumnName = value; }
}
public string ClosedRoadValue
{
get { return closedRoadValue; }
set { closedRoadValue = value; }
}
private Regex GetRegex(string stringToMatch)
{
if (String.IsNullOrEmpty(stringToMatch))
{
return null;
}
Regex regex = null;
if (stringToMatch.StartsWith("[") && stringToMatch.EndsWith("]"))
{
string regexString = stringToMatch.Substring(1, stringToMatch.Length - 2);
regex = new Regex(regexString, RegexOptions.Compiled);
}
return regex;
}
public void InitRegexes()
{
this.closedRoadValueRegex = GetRegex(this.closedRoadValue);
}
public bool MatchClosedRoadValue(string closedRoadValue)
{
bool match = false;
if (closedRoadValue == null)
{
match = closedRoadValue.Equals(this.closedRoadValue, StringComparison.InvariantCultureIgnoreCase);
}
else
{
match = closedRoadValueRegex.Match(closedRoadValue).Success;
}
return match;
}
}
}