SubsetNetworkEvaluators\ScaleSubsetEvaluator.cs
// Copyright 2012 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the use restrictions. // using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; namespace SubsetNetworkEvaluators { /// <summary> /// The scale subset network evaluator is a custom network evaluator for modeling slowdown polygons /// where traffic speeds are slowed down in only a particular subset of the network. In this /// example the subset of network elements that are slowed down is determined based on the geometry /// of graphic elements drawn in arc map, but it does not matter how the element subset is determined. /// The elements that are not in the subset just return the non-scaled base attribute value. This could /// be useful, for example, if certain low lying areas had a flash flood, or other localized congestion that /// does not affect the network as a whole. The subset of elements to be scaled and the scale factor to /// scale the base attribute by in the scale subset evaluator are network attribute parameters of the attribute /// the evaluator is assigned to. /// </summary> [ClassInterface(ClassInterfaceType.None)] [Guid("67cf8446-22a2-4baf-9c97-3c22a33cc0c7")] [ProgId("SubsetNetworkEvaluators.ScaleSubsetEvaluator")] public class ScaleSubsetEvaluator : INetworkEvaluator2, INetworkEvaluatorSetup { #region Member Variables private INetworkDataset m_networkDataset; private INetworkSource m_networkSource; private INetworkAttribute m_networkAttribute; private double m_scaleFactor = 1; private int m_thisNetworkAttributeID = -1; // the ID for this attribute private int m_baseNetworkAttributeID = -1; // the ID for the other attribute that should be scale (determined based on attribute name) private int m_countSourceEIDs = 0; // number of EIDs to override for this source private Dictionary<int, int> m_sourceEIDHashTable; // the EIDs to override values for, by scaling, for this source #endregion #region INetworkEvaluator Members public bool CacheAttribute { // CacheAttribute returns whether or not we want the network dataset to cache our evaluated attribute values during the network dataset build // Since this is a dynamic evaluator, we will return false, so that our attribute values are dynamically queried at runtime get { return false; } } public string DisplayName { get { return "ScaleSubset"; } } public string Name { get { return "SubsetNetworkEvaluators.ScaleSubset"; } } #endregion #region INetworkEvaluator2 Members public void Refresh() { // This method is called internally during a solve operation immediately prior to performing the actual solve // This gives us an opportunity to update our evaluator's internal state based on parameter values m_scaleFactor = 1; m_countSourceEIDs = 0; m_sourceEIDHashTable = new Dictionary<int, int>(); INetworkAttribute2 netAttribute2 = m_networkAttribute as INetworkAttribute2; IArray netAttributeParams = netAttribute2.Parameters; // Parameters: "ScaleSubset_Factor", "ScaleSubset_eids_<SourceName>" string prefix = BaseParameterName + "_"; string paramScaleFactorName = prefix + "Factor"; string paramEIDsName = prefix + "eids_" + m_networkSource.Name; int nParamScaleFactor = SubsetHelper.FindParameter(netAttributeParams, paramScaleFactorName); int nParamEIDs = SubsetHelper.FindParameter(netAttributeParams, paramEIDsName); object value; INetworkAttributeParameter paramScaleFactor; INetworkAttributeParameter paramEIDs; if (nParamScaleFactor >= 0) { paramScaleFactor = netAttributeParams.get_Element(nParamScaleFactor) as INetworkAttributeParameter; value = paramScaleFactor.Value; if (value != null) m_scaleFactor = (double)value; } if (nParamEIDs >= 0) { paramEIDs = netAttributeParams.get_Element(nParamEIDs) as INetworkAttributeParameter; value = paramEIDs.Value as int[]; if (value != null) { int eid; int[] rgEIDs; rgEIDs = (int[])value; int lb = rgEIDs.GetLowerBound(0); int ub = rgEIDs.GetUpperBound(0); for (int i = lb; i <= ub; ++i) { ++m_countSourceEIDs; eid = rgEIDs[i]; m_sourceEIDHashTable.Add(eid, eid); } } } } public IStringArray RequiredFieldNames { // This custom evaluator does not require any field names get { return null; } } #endregion #region INetworkEvaluatorSetup Members public UID CLSID { get { // Create and return the GUID for this custom evaluator UID uid = new UIDClass(); uid.Value = "{67cf8446-22a2-4baf-9c97-3c22a33cc0c7}"; return uid; } } public IPropertySet Data { // The Data property is intended to make use of property sets to get/set the custom evaluator's properties using only one call to the evaluator object // This custom evaluator does not make use of this property get { return null; } set { } } public bool DataHasEdits { // Since this custom evaluator does not make any data edits, return false get { return false; } } public void Initialize(INetworkDataset networkDataset, IDENetworkDataset DataElement, INetworkSource netSource, IEvaluatedNetworkAttribute netAttribute) { // Initialize is called once per session (ArcMap session, ArcCatalog session, etc.) to initialize the evaluator for an associated network dataset m_networkDataset = networkDataset; m_networkSource = netSource; m_networkAttribute = netAttribute; m_thisNetworkAttributeID = netAttribute.ID; m_baseNetworkAttributeID = -1; //The attribute name must begin with one or more non underscore characters followed by //an underscore character and then the name of the base cost attribute. //The underscore prior to the base attribute name should be the first underscore in the name. string thisAttributeName = netAttribute.Name; int nPos = thisAttributeName.IndexOf('_'); int nLastPos = thisAttributeName.Length - 1; string baseNetAttributeName; INetworkAttribute baseNetAttribute = null; if (nPos > 0 && nPos < nLastPos) { baseNetAttributeName = thisAttributeName.Remove(0, nPos + 1); try { baseNetAttribute = networkDataset.get_AttributeByName(baseNetAttributeName); } catch (COMException ex) { baseNetAttribute = null; string msg = string.Format("Base Attribute ({0}) not found. {1}.", baseNetAttributeName, ex.Message); System.Diagnostics.Trace.WriteLine(msg, "Scale Subset Network Evaluator"); } if (baseNetAttribute != null) { if (baseNetAttribute.ID != m_thisNetworkAttributeID) m_baseNetworkAttributeID = baseNetAttribute.ID; } } Refresh(); } public object QueryValue(INetworkElement Element, IRow Row) { if (m_baseNetworkAttributeID < 0) return -1; object value = Element.get_AttributeValue(m_baseNetworkAttributeID); if (value == null) return -1; double baseValue = (double)value; if (baseValue <= 0 || m_scaleFactor == 1 || m_countSourceEIDs <= 0) return baseValue; bool isScaled = false; int eid = -1; if (m_sourceEIDHashTable.TryGetValue(Element.EID, out eid)) isScaled = (eid > 0); object resultValue = baseValue; if (isScaled) { if (m_scaleFactor >= 0) resultValue = m_scaleFactor * baseValue; else resultValue = -1; } return resultValue; } public object QueryPartialEdgeValue(INetworkEdge2 edge, double fromPos, double toPos) { // Partial Edge values are not appropriate for restriction evaluators. throw new NotImplementedException(); } public bool SupportsDefault(esriNetworkElementType ElementType, IEvaluatedNetworkAttribute netAttribute) { return false; } public bool SupportsSource(INetworkSource netSource, IEvaluatedNetworkAttribute netAttribute) { // This custom evaluator supports cost attributes for all sources return netAttribute.UsageType == esriNetworkAttributeUsageType.esriNAUTCost; } public bool ValidateDefault(esriNetworkElementType ElementType, IEvaluatedNetworkAttribute netAttribute, ref int ErrorCode, ref string ErrorDescription, ref string errorAppendInfo) { if (SupportsDefault(ElementType, netAttribute)) { ErrorCode = 0; ErrorDescription = errorAppendInfo = string.Empty; return true; } else { ErrorCode = -1; ErrorDescription = errorAppendInfo = string.Empty; return false; } } public bool ValidateSource(IDatasetContainer2 datasetContainer, INetworkSource netSource, IEvaluatedNetworkAttribute netAttribute, ref int ErrorCode, ref string ErrorDescription, ref string errorAppendInfo) { if (SupportsSource(netSource, netAttribute)) { ErrorCode = 0; ErrorDescription = errorAppendInfo = string.Empty; return true; } else { ErrorCode = -1; ErrorDescription = errorAppendInfo = string.Empty; return false; } } #endregion #region Static Members public static string BaseParameterName { get { return "ScaleSubset"; } } public static void RemoveScaleSubsetAttributes(IDENetworkDataset deNet) { IArray netAttributes = SubsetHelper.RemoveAttributesByPrefix(deNet.Attributes, BaseParameterName); deNet.Attributes = netAttributes; } public static List<IEvaluatedNetworkAttribute> AddScaleSubsetAttributes(IDENetworkDataset deNet) { List<IEvaluatedNetworkAttribute> scaleSubsetAttributes = new List<IEvaluatedNetworkAttribute>(); IArray netAttributesArray = deNet.Attributes; List<int> baseIndexes = SubsetHelper.FindAttributeIndexes(netAttributesArray, esriNetworkAttributeUsageType.esriNAUTCost, esriNetworkAttributeDataType.esriNADTDouble, true, false); List<INetworkAttribute2> baseNetAttributes = SubsetHelper.FindAttributes(netAttributesArray, baseIndexes); foreach (INetworkAttribute2 baseNetAttribute in baseNetAttributes) scaleSubsetAttributes.Add(AddScaleSubsetAttribute(deNet, baseNetAttribute)); return scaleSubsetAttributes; } public static IEvaluatedNetworkAttribute AddScaleSubsetAttribute(IDENetworkDataset deNet, INetworkAttribute2 baseNetAttribute) { if (baseNetAttribute == null) return null; if (baseNetAttribute.UsageType != esriNetworkAttributeUsageType.esriNAUTCost) return null; IArray netAttributes = deNet.Attributes; IEvaluatedNetworkAttribute netAttribute = new EvaluatedNetworkAttributeClass() as IEvaluatedNetworkAttribute; string netAttributeName = BaseParameterName; netAttributeName += "_"; netAttributeName += baseNetAttribute.Name; netAttribute.Name = netAttributeName; netAttribute.UsageType = baseNetAttribute.UsageType; netAttribute.DataType = baseNetAttribute.DataType; netAttribute.Units = baseNetAttribute.Units; List<INetworkSource> allNetSources = SubsetHelper.GetSourceList(deNet.Sources); List<INetworkSource> netSources = SubsetHelper.GetSourceList(allNetSources, esriNetworkElementType.esriNETEdge); List<string> netSourceNames = SubsetHelper.GetSourceNames(netSources); ResetScaleSubsetParameters((INetworkAttribute2)netAttribute, netSourceNames); bool supportTurns = deNet.SupportsTurns; //default evaluators SubsetHelper.SetDefaultEvaluator(netAttribute, 0, esriNetworkElementType.esriNETEdge); SubsetHelper.SetDefaultEvaluator(netAttribute, 0, esriNetworkElementType.esriNETJunction); if (supportTurns) SubsetHelper.SetDefaultEvaluator(netAttribute, 0, esriNetworkElementType.esriNETTurn); //sourced evaluators foreach (INetworkSource netSource in netSources) SubsetHelper.SetEvaluators(netAttribute, netSource, typeof(ScaleSubsetEvaluator)); netAttributes.Add(netAttribute); deNet.Attributes = netAttributes; return netAttribute; } public static void ResetScaleSubsetParameters(INetworkAttribute2 netAttribute, List<string> netSourceNames) { IArray netParams = new ESRI.ArcGIS.esriSystem.ArrayClass(); INetworkAttributeParameter netParam = null; object paramValue = null; string paramName = ""; netParam = new NetworkAttributeParameterClass(); paramValue = 1; paramName = BaseParameterName; paramName += "_Factor"; netParam.Name = paramName; netParam.VarType = (int)VarType.Double; netParam.Value = paramValue; netParam.DefaultValue = paramValue; netParams.Add(netParam); foreach (string netSourceName in netSourceNames) { netParam = new NetworkAttributeParameterClass(); paramValue = null; paramName = BaseParameterName; paramName += "_eids_"; paramName += netSourceName; netParam.Name = paramName; netParam.VarType = (int)(VarType.Array | VarType.Integer); netParam.Value = paramValue; netParam.DefaultValue = paramValue; netParams.Add(netParam); } //does not preserve existing parameters if any netAttribute.Parameters = netParams; } #endregion } }