ArcObjects Library Reference  

frmClosestFacilitySolver

About the Closest facility solver Sample

[C#]

frmClosestFacilitySolver.cs

//*************************************************************************************
//       Network Analyst - Closest Facility Demonstration
//
//   This simple code shows how to :
//    1) Open a workspace and open a Network DataSet
//    2) Create a NAContext and its NASolver
//    3) Load Incidents/Facilites from Feature Classes and create Network Locations
//    4) Set the Solver parameters
//    5) Solve a Closest Facility problem
//    6) Read the CFRoutes output to display the total facilities
//       and the list of the routes found
//************************************************************************************

using System;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.NetworkAnalyst;

namespace ClosestFacilitySolver
{
	public partial class frmClosestFacilitySolver : Form
	{
		private INAContext m_NAContext;

		public frmClosestFacilitySolver()
		{
			InitializeComponent();
			Initialize();
		}

		private void Initialize()
		{
			IFeatureWorkspace featureWorkspace = null;
			INetworkDataset networkDataset = null;

			try
			{
				// Open Geodatabase and network dataset
				IWorkspace workspace = OpenWorkspace(Application.StartupPath + @"\..\..\..\..\..\Data\SanFrancisco\SanFrancisco.gdb");
				networkDataset = OpenNetworkDataset(workspace, "Transportation", "Streets_ND");
				featureWorkspace = workspace as IFeatureWorkspace;
			}
			catch (Exception ex)
			{
				System.Windows.Forms.MessageBox.Show("Unable to open dataset. Error Message: " + ex.Message);
				this.Close();
				return;
			}

			// Create NAContext and NASolver
			m_NAContext = CreateSolverContext(networkDataset);

			// Get Cost Attributes
			INetworkAttribute networkAttribute;
			for (int i = 0; i < networkDataset.AttributeCount - 1; i++)
			{
				networkAttribute = networkDataset.get_Attribute(i);
				if (networkAttribute.UsageType == esriNetworkAttributeUsageType.esriNAUTCost)
				{
					cboCostAttribute.Items.Add(networkAttribute.Name);
					cboCostAttribute.SelectedIndex = 0;
				}
			}

			txtTargetFacility.Text = "1";
			txtCutOff.Text = "";

			// Load locations from a feature class
			IFeatureClass inputFClass = featureWorkspace.OpenFeatureClass("Stores");
			LoadNANetworkLocations("Incidents", inputFClass, 100);

			inputFClass = featureWorkspace.OpenFeatureClass("FireStations");
			LoadNANetworkLocations("Facilities", inputFClass, 100);

			//Create Layer for Network Dataset and add to ArcMap
			ILayer layer;
			INetworkLayer networkLayer;
			networkLayer = new NetworkLayerClass();
			networkLayer.NetworkDataset = networkDataset;
			layer = networkLayer as ILayer;
			layer.Name = "Network Dataset";
			axMapControl.AddLayer(layer, 0);

			//Create a Network Analysis Layer and add to ArcMap
			INALayer naLayer = m_NAContext.Solver.CreateLayer(m_NAContext);
			layer = naLayer as ILayer;
			layer.Name = m_NAContext.Solver.DisplayName;
			axMapControl.AddLayer(layer, 0);
		}

		private void cmdSolve_Click(object sender, System.EventArgs e)
		{
			try
			{
				lstOutput.Items.Clear();
				lstOutput.Items.Add("Solving...");

				SetSolverSettings();

				// Solve
				IGPMessages gpMessages = new GPMessagesClass();
				if (!m_NAContext.Solver.Solve(m_NAContext, gpMessages, null))
					GetCFOutput("CFRoutes");
				else
					lstOutput.Items.Add("Partial Result");

				// Display  Error/Warning/Informative Messages
				if (gpMessages != null)
				{
					for (int i = 0; i < gpMessages.Count; i++)
					{
						switch (gpMessages.GetMessage(i).Type)
						{

							case esriGPMessageType.esriGPMessageTypeError:
								lstOutput.Items.Add("Error " + gpMessages.GetMessage(i).ErrorCode.ToString() + " " + gpMessages.GetMessage(i).Description);
								break;
							case esriGPMessageType.esriGPMessageTypeWarning:
								lstOutput.Items.Add("Warning " + gpMessages.GetMessage(i).Description);
								break;
							default:
								lstOutput.Items.Add("Information " + gpMessages.GetMessage(i).Description);
								break;
						}
					}
				}
				//Zoom to the extent of the route
				IGeoDataset geoDataset;
				IEnvelope envelope;
				geoDataset = m_NAContext.NAClasses.get_ItemByName("CFRoutes") as IGeoDataset;
				envelope = geoDataset.Extent;
				if (!envelope.IsEmpty)
					envelope.Expand(1.1, 1.1, true);
				axMapControl.Extent = envelope;
				axMapControl.Refresh();
			}
			catch (Exception ee)
			{
				MessageBox.Show(ee.Message);
				cmdSolve.Text = "Find Closest Facilities";
			}
		}

		// Get the Impedance Cost form the CFRoute Class Output
		public void GetCFOutput(string strNAClass)
		{
			ITable table = m_NAContext.NAClasses.get_ItemByName(strNAClass) as ITable;
			if (table == null)
			{
				lstOutput.Items.Add("Impossible to get the " + strNAClass + " table");
			}
			lstOutput.Items.Add("Number facilities found " + table.RowCount(null).ToString());
			lstOutput.Items.Add("");
			if (table.RowCount(null) > 0)
			{
				lstOutput.Items.Add("IncidentID, FacilityID,FacilityRank,Total_" + cboCostAttribute.Text);
				double total_impedance;
				long incidentID;
				long facilityID;
				long facilityRank;
				ICursor cursor;
				IRow row;

				cursor = table.Search(null, false);
				row = cursor.NextRow();
				while (row != null)
				{
					incidentID = long.Parse(row.get_Value(table.FindField("IncidentID")).ToString());
					facilityID = long.Parse(row.get_Value(table.FindField("FacilityID")).ToString());
					facilityRank = long.Parse(row.get_Value(table.FindField("FacilityRank")).ToString());
					total_impedance = double.Parse(row.get_Value(table.FindField("Total_" + cboCostAttribute.Text)).ToString());
					lstOutput.Items.Add(incidentID.ToString() + ",\t" + facilityID.ToString() +
						",\t" + facilityRank.ToString() + ",\t" + total_impedance.ToString("F2"));

					row = cursor.NextRow();
				}
			}

			lstOutput.Refresh();
		}

		//*********************************************************************************
		// Network Analyst functions
		// ********************************************************************************

		//*********************************************************************************
		// Create NASolver and NAContext
		//*********************************************************************************
		public INAContext CreateSolverContext(INetworkDataset networkDataset)
		{
			//Get the Data Element
			IDENetworkDataset deNDS = GetDENetworkDataset(networkDataset);

			INASolver naSolver;
			naSolver = new NAClosestFacilitySolver();
			INAContextEdit contextEdit = naSolver.CreateContext(deNDS, naSolver.Name) as INAContextEdit;
			contextEdit.Bind(networkDataset, new GPMessagesClass());
			return contextEdit as INAContext;
		}

		//*********************************************************************************
		// Set Solver Settings
		//*********************************************************************************
		public void LoadNANetworkLocations(string strNAClassName, IFeatureClass inputFC, double snapTolerance)
		{
			INAClass naClass;
			INamedSet classes;
			classes = m_NAContext.NAClasses;
			naClass = classes.get_ItemByName(strNAClassName) as INAClass;

			// delete existing Locations except if that a barriers
			naClass.DeleteAllRows();

			// Create a NAClassLoader and set the snap tolerance (meters unit)
			INAClassLoader classLoader = new NAClassLoader();
			classLoader.Locator = m_NAContext.Locator;
			if (snapTolerance > 0) classLoader.Locator.SnapTolerance = snapTolerance;
			classLoader.NAClass = naClass;

			//Create field map to automatically map fields from input class to NAClass
			INAClassFieldMap fieldMap;
			fieldMap = new NAClassFieldMap();
			fieldMap.CreateMapping(naClass.ClassDefinition, inputFC.Fields);
			classLoader.FieldMap = fieldMap;

			// Avoid loading network locations onto non-traversable portions of elements
			INALocator3 locator = m_NAContext.Locator as INALocator3;
			locator.ExcludeRestrictedElements = true;
			locator.CacheRestrictedElements(m_NAContext);

			//Load Network Locations
			int rowsIn = 0;
			int rowsLocated = 0;
			IFeatureCursor featureCursor = inputFC.Search(null, true);
			classLoader.Load((ICursor)featureCursor, null, ref rowsIn, ref rowsLocated);

			//Message all of the network analysis agents that the analysis context has changed
			((INAContextEdit)m_NAContext).ContextChanged();
		}

		//*********************************************************************************
		// Set Solver Settings
		//*********************************************************************************
		public void SetSolverSettings()
		{
			//Set Route specific Settings
			INASolver naSolver = m_NAContext.Solver;

			INAClosestFacilitySolver cfSolver = naSolver as INAClosestFacilitySolver;
			if (txtCutOff.Text.Length > 0 && IsNumeric(txtCutOff.Text.Trim()))
				cfSolver.DefaultCutoff = txtCutOff.Text;
			else
				cfSolver.DefaultCutoff = null;

			if (txtTargetFacility.Text.Length > 0 && IsNumeric(txtTargetFacility.Text))
				cfSolver.DefaultTargetFacilityCount = int.Parse(txtTargetFacility.Text);
			else
				cfSolver.DefaultTargetFacilityCount = 1;

			cfSolver.OutputLines = esriNAOutputLineType.esriNAOutputLineTrueShapeWithMeasure;
			cfSolver.TravelDirection = esriNATravelDirection.esriNATravelDirectionToFacility;

			// Set generic solver settings
			// Set the impedance attribute
			INASolverSettings naSolverSettings;
			naSolverSettings = naSolver as INASolverSettings;
			naSolverSettings.ImpedanceAttributeName = cboCostAttribute.Text;

			// Set the OneWay Restriction if necessary
			IStringArray restrictions;
			restrictions = naSolverSettings.RestrictionAttributeNames;
			restrictions.RemoveAll();
			if (chkUseRestriction.Checked)
				restrictions.Add("oneway");

			naSolverSettings.RestrictionAttributeNames = restrictions;

			//Restrict UTurns
			naSolverSettings.RestrictUTurns = esriNetworkForwardStarBacktrack.esriNFSBNoBacktrack;
			naSolverSettings.IgnoreInvalidLocations = true;

			// Set the Hierarchy attribute
			naSolverSettings.UseHierarchy = chkUseHierarchy.Checked;
			if (naSolverSettings.UseHierarchy)
				naSolverSettings.HierarchyAttributeName = "hierarchy";

			// Do not forget to update the context after you set your impedance
			naSolver.UpdateContext(m_NAContext, GetDENetworkDataset(m_NAContext.NetworkDataset), new GPMessagesClass());
		}

		//*********************************************************************************
		// Geodatabase functions
		// ********************************************************************************
		public IWorkspace OpenWorkspace(string strGDBName)
		{
			// As Workspace Factories are Singleton objects, they must be instantiated with the Activator
			var workspaceFactory = System.Activator.CreateInstance(System.Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")) as ESRI.ArcGIS.Geodatabase.IWorkspaceFactory;
			return workspaceFactory.OpenFromFile(strGDBName, 0);
		}

		//*********************************************************************************
		// Open the network dataset
		//*********************************************************************************
		public INetworkDataset OpenNetworkDataset(IWorkspace workspace, string featureDatasetName, string strNDSName)
		{
			// Obtain the dataset container from the workspace
			var featureWorkspace = workspace as IFeatureWorkspace;
			ESRI.ArcGIS.Geodatabase.IFeatureDataset featureDataset = featureWorkspace.OpenFeatureDataset(featureDatasetName);
			var featureDatasetExtensionContainer = featureDataset as ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtensionContainer;
			ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtension featureDatasetExtension = featureDatasetExtensionContainer.FindExtension(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset);
			var datasetContainer3 = featureDatasetExtension as ESRI.ArcGIS.Geodatabase.IDatasetContainer3;

			// Use the container to open the network dataset.
			ESRI.ArcGIS.Geodatabase.IDataset dataset = datasetContainer3.get_DatasetByName(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset, strNDSName);
			return dataset as ESRI.ArcGIS.Geodatabase.INetworkDataset;
		}

		public IDENetworkDataset GetDENetworkDataset(INetworkDataset networkDataset)
		{
			//Cast from the Network Dataset to the DatasetComponent
			IDatasetComponent dsComponent;
			dsComponent = networkDataset as IDatasetComponent;

			//Get the Data Element
			return dsComponent.DataElement as IDENetworkDataset;
		}

		private bool IsNumeric(string str)
		{
			try
			{
				double.Parse(str.Trim());
			}
			catch (Exception) { return false; }
			return true;
		}
	}
}
[Visual Basic .NET]

frmClosestFacilitySolver.vb

'*************************************************************************************
'       Network Analyst - Closest Facility Demonstration
'
'   This simple code shows how to :
'    1) Open an shapefile workspace and open a Network DataSet
'    2) Create a NAContext and its NASolver
'    3) Load Incidents/Facilites from Feature Classes and create Network Locations
'    4) Set the Solver parameters
'    5) Solve a Closest Facility problem
'    6) Read the CFRoutes output to display the total facilities
'       and the list of the routes found
'************************************************************************************

Imports System
Imports System.Windows.Forms
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.NetworkAnalyst

Public Class frmClosestFacilitySolver
	Private m_NAContext As INAContext

	Public Sub New()

		'This call is required by the Windows Form Designer.
		InitializeComponent()

		'Add any initialization after the InitializeComponent() call
		Initialize()

	End Sub

	Private Sub Initialize()
		' Open geodatabase and network dataset
		Dim featureWorkspace As IFeatureWorkspace = Nothing
		Dim networkDataset As INetworkDataset = Nothing

		Try
			Dim workspace As IWorkspace = OpenWorkspace(Application.StartupPath & "\..\..\..\..\..\Data\SanFrancisco\SanFrancisco.gdb")
			networkDataset = OpenNetworkDataset(workspace, "Transportation", "Streets_ND")
			featureWorkspace = TryCast(workspace, IFeatureWorkspace)
		Catch ex As Exception
			Windows.Forms.MessageBox.Show("Unable to open dataset. Error Message: " + ex.Message)
			Me.Close()
			Return
		End Try

		' Create NAContext and NASolver
		m_NAContext = CreateSolverContext(networkDataset)

		' Get Cost Attributes
		Dim networkAttribute As INetworkAttribute, i As Integer
		For i = 0 To networkDataset.AttributeCount - 2
			networkAttribute = networkDataset.Attribute(i)
			If networkAttribute.UsageType = esriNetworkAttributeUsageType.esriNAUTCost Then
				cboCostAttribute.Items.Add(networkAttribute.Name)
				cboCostAttribute.SelectedIndex = 0
			End If
		Next

		txtTargetFacility.Text = "1"
		txtCutOff.Text = ""

		' Load locations from FC
		Dim inputFClass As IFeatureClass = featureWorkspace.OpenFeatureClass("Stores")
		LoadNANetworkLocations("Incidents", inputFClass, 100)

		inputFClass = featureWorkspace.OpenFeatureClass("FireStations")
		LoadNANetworkLocations("Facilities", inputFClass, 100)

		' Create Layer for Network Dataset and add to ArcMap
		Dim networkLayer As INetworkLayer = New NetworkLayerClass
		networkLayer.NetworkDataset = networkDataset
		Dim layer As ILayer = networkLayer
		layer.Name = "Network Dataset"
		axMapControl.AddLayer(layer, 0)

		' Create a Network Analysis Layer and add to ArcMap
		Dim naLayer As INALayer = m_NAContext.Solver.CreateLayer(m_NAContext)
		layer = naLayer
		layer.Name = m_NAContext.Solver.DisplayName
		axMapControl.AddLayer(layer, 0)
	End Sub

	Private Sub cmdSolve_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSolve.Click
		Try
			lstOutput.Items.Clear()
			lstOutput.Items.Add("Solving...")

			SetSolverSettings()

			' Solve
			Dim gpMessages As IGPMessages = New GPMessagesClass
			If Not m_NAContext.Solver.Solve(m_NAContext, gpMessages, Nothing) Then
				GetCFOutput("CFRoutes")
			Else
				lstOutput.Items.Add("Partial Result")
			End If

			' Display  Error/Warning/Informative Messages
			If Not gpMessages Is Nothing Then
				Dim i As Integer
				For i = 0 To gpMessages.Count - 1
					Select Case gpMessages.GetMessage(i).Type
						Case esriGPMessageType.esriGPMessageTypeError
							lstOutput.Items.Add("Error " + gpMessages.GetMessage(i).ErrorCode.ToString() + " " + gpMessages.GetMessage(i).Description)
						Case esriGPMessageType.esriGPMessageTypeWarning
							lstOutput.Items.Add("Warning " + gpMessages.GetMessage(i).Description)
						Case Else
							lstOutput.Items.Add("Information " + gpMessages.GetMessage(i).Description)
					End Select
				Next
			End If

			' Zoom to the extent of the route
			Dim geoDataset As IGeoDataset = m_NAContext.NAClasses.ItemByName("CFRoutes")
			Dim envelope As IEnvelope = geoDataset.Extent
			If Not envelope.IsEmpty Then
				envelope.Expand(1.1, 1.1, True)
				axMapControl.Extent = envelope
				axMapControl.Refresh()
			End If
		Catch ee As Exception
			MessageBox.Show(ee.Message)
			cmdSolve.Text = "Find Closest Facilities"
		End Try
	End Sub

	' Get the Impedance Cost form the CFRoute Class Output
	Public Sub GetCFOutput(ByVal strNAClass As String)
		Dim table As ITable = m_NAContext.NAClasses.ItemByName(strNAClass)
		If table Is Nothing Then
			lstOutput.Items.Add("Impossible to get the " + strNAClass + " table")
		End If

		lstOutput.Items.Add("Number facilities found " + table.RowCount(Nothing).ToString())
		lstOutput.Items.Add("")
		If table.RowCount(Nothing) > 0 Then
			lstOutput.Items.Add("IncidentID, FacilityID, FacilityRank, Total_" + cboCostAttribute.Text)
			Dim total_impedance As Double
			Dim incidentID As Long
			Dim facilityID As Long
			Dim facilityRank As Long
			Dim cursor As ICursor
			Dim row As IRow

			cursor = table.Search(Nothing, False)
			row = cursor.NextRow()
			While Not row Is Nothing
				incidentID = Long.Parse(row.Value(table.FindField("IncidentID")).ToString())
				facilityID = Long.Parse(row.Value(table.FindField("FacilityID")).ToString())
				facilityRank = Long.Parse(row.Value(table.FindField("FacilityRank")).ToString())
				total_impedance = Double.Parse(row.Value(table.FindField("Total_" + cboCostAttribute.Text)).ToString())
				lstOutput.Items.Add(incidentID.ToString() + "," + vbTab + facilityID.ToString() + "," + vbTab + facilityRank.ToString() + "," + vbTab + total_impedance.ToString("F2"))

				row = cursor.NextRow()
			End While
		End If
		lstOutput.Refresh()
	End Sub

	'*********************************************************************************
	' Network Analyst functions
	' ********************************************************************************

	'*********************************************************************************
	' Create NASolver and NAContext
	'*********************************************************************************
	Public Function CreateSolverContext(ByVal networkDataset As INetworkDataset) As INAContext
		' Get the Data Element
		Dim deNDS As IDENetworkDataset = GetDENetworkDataset(networkDataset)

		Dim naSolver As INASolver = New NAClosestFacilitySolver
		Dim contextEdit As INAContextEdit = naSolver.CreateContext(deNDS, naSolver.Name)
		contextEdit.Bind(networkDataset, New GPMessagesClass)
		Return contextEdit
	End Function

	'*********************************************************************************
	' Load network locations
	'*********************************************************************************
	Public Sub LoadNANetworkLocations(ByVal strNAClassName As String, ByVal inputFC As IFeatureClass, ByVal snapTolerance As Double)
		Dim classes As INamedSet = m_NAContext.NAClasses
		Dim naClass As INAClass = classes.ItemByName(strNAClassName)

		' delete existing Locations except if that a barriers
		naClass.DeleteAllRows()

		' Create a NAClassLoader and set the snap tolerance (meters unit)
		Dim classLoader As INAClassLoader = New NAClassLoader
		classLoader.Locator = m_NAContext.Locator
		If snapTolerance > 0 Then
			classLoader.Locator.SnapTolerance = snapTolerance
		End If
		classLoader.NAClass = naClass

		' Create field map to automatically map fields from input class to naclass
		Dim fieldMap As INAClassFieldMap = New NAClassFieldMap
		fieldMap.CreateMapping(naClass.ClassDefinition, inputFC.Fields)
		classLoader.FieldMap = fieldMap

		' Avoid loading network locations onto non-traversable portions of elements
		Dim locator As INALocator3 = TryCast(m_NAContext.Locator, INALocator3)
		locator.ExcludeRestrictedElements = True
		locator.CacheRestrictedElements(m_NAContext)

		' Load Network Locations
		Dim rowsIn As Integer = 0
		Dim rowsLocated As Integer = 0
		Dim featureCursor As IFeatureCursor = inputFC.Search(Nothing, True)
		classLoader.Load(featureCursor, Nothing, rowsIn, rowsLocated)

		' Message all of the network analysis agents that the analysis context has changed
		Dim naContextEdit As INAContextEdit = m_NAContext
		naContextEdit.ContextChanged()
	End Sub

	'*********************************************************************************
	' Set Solver Settings
	'*********************************************************************************
	Public Sub SetSolverSettings()
		'Set Route specific Settings
		Dim naSolver As INASolver = m_NAContext.Solver

		Dim cfSolver As INAClosestFacilitySolver = naSolver
		If txtCutOff.Text.Length > 0 And IsNumeric(txtCutOff.Text.Trim()) Then
			cfSolver.DefaultCutoff = txtCutOff.Text
		Else
			cfSolver.DefaultCutoff = Nothing
		End If

		If txtTargetFacility.Text.Length > 0 And IsNumeric(txtTargetFacility.Text) Then
			cfSolver.DefaultTargetFacilityCount = Integer.Parse(txtTargetFacility.Text)
		Else
			cfSolver.DefaultTargetFacilityCount = 1
		End If

		cfSolver.OutputLines = esriNAOutputLineType.esriNAOutputLineTrueShapeWithMeasure
		cfSolver.TravelDirection = esriNATravelDirection.esriNATravelDirectionToFacility

		'Set generic Solver settings
		' set the impedance attribute
		Dim naSolverSettings As INASolverSettings = naSolver
		naSolverSettings.ImpedanceAttributeName = cboCostAttribute.Text

		' Set the OneWay Restriction if necessary
		Dim restrictions As IStringArray = naSolverSettings.RestrictionAttributeNames
		restrictions.RemoveAll()
		If chkUseRestriction.Checked Then
			restrictions.Add("oneway")
		End If

		naSolverSettings.RestrictionAttributeNames = restrictions

		'Restrict UTurns
		naSolverSettings.RestrictUTurns = esriNetworkForwardStarBacktrack.esriNFSBNoBacktrack
		naSolverSettings.IgnoreInvalidLocations = True

		' Set the Hierarchy attribute
		naSolverSettings.UseHierarchy = chkUseHierarchy.Checked
		If naSolverSettings.UseHierarchy Then
			naSolverSettings.HierarchyAttributeName = "hierarchy"
		End If

		' Do not forget to update the context after you set your impedance
		naSolver.UpdateContext(m_NAContext, GetDENetworkDataset(m_NAContext.NetworkDataset), New GPMessagesClass)
	End Sub

	'*********************************************************************************
	' Solve the problem
	'*********************************************************************************
	Public Function Solve(ByVal naContext As INAContext, ByVal gpMessages As IGPMessages) As String
		Dim errStr As String = ""
		Try
			' Solving the Problem
			errStr = "Error when solving"
			Dim isPartialSolution As Boolean = naContext.Solver.Solve(naContext, gpMessages, Nothing)

			If Not isPartialSolution Then
				errStr = "OK"
			Else
				errStr = "Partial Solution"
			End If
		Catch e As Exception
			errStr += " Error Description " + e.Message
		End Try
		Return errStr
	End Function

	'*********************************************************************************
	' Geodatabase functions
	'*********************************************************************************
	Public Function OpenWorkspace(ByVal strGDBName As String) As IWorkspace
		' As Workspace Factories are Singleton objects, they must be instantiated with the Activator
		Dim workspaceFactory As IWorkspaceFactory = TryCast(Activator.CreateInstance(Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")), IWorkspaceFactory)
		Return workspaceFactory.OpenFromFile(strGDBName, 0)
	End Function

	'*********************************************************************************
	' Open the network dataset
	'*********************************************************************************
	Public Function OpenNetworkDataset(ByVal workspace As IWorkspace, ByVal featureDatasetName As String, ByVal strNDSName As String) As INetworkDataset
		' Obtain the dataset container from the workspace
		Dim featureWorkspace As IFeatureWorkspace = TryCast(workspace, IFeatureWorkspace)
		Dim featureDataset As IFeatureDataset = featureWorkspace.OpenFeatureDataset(featureDatasetName)
		Dim featureDatasetExtensionContainer As IFeatureDatasetExtensionContainer = TryCast(featureDataset, IFeatureDatasetExtensionContainer)
		Dim featureDatasetExtension As IFeatureDatasetExtension = featureDatasetExtensionContainer.FindExtension(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset)
		Dim datasetContainer3 As IDatasetContainer3 = TryCast(featureDatasetExtension, IDatasetContainer3)

		' Use the container to open the network dataset
		Dim dataset As Object = datasetContainer3.DatasetByName(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset, strNDSName)
		Return TryCast(dataset, INetworkDataset)
	End Function

	Public Function GetDENetworkDataset(ByVal pNetDataset As INetworkDataset) As IDENetworkDataset
		'Cast from the Network Dataset to the DatasetComponent
		Dim dsComponent As IDatasetComponent = pNetDataset

		'Get the Data Element
		Return dsComponent.DataElement
	End Function

	Private Function IsNumeric(ByVal str As String) As Boolean
		Try
			Double.Parse(str.Trim())
		Catch
			Return False
		End Try
		Return True
	End Function
End Class