ArcFM Desktop Overview > OHDA Overview > Export Poles to OHDA |
Out of the box, Overhead Design Analysis (OHDA) provides a user interface to export ArcFM poles for use in OHDA models. The default behavior is for an administrator to add the HEIGHT, CLASS, MATERIAL, and ASSETID field model names to the SUPPORTSTRUCTURE Feature class in the geodatabase for OHDA to consume. You can programmatically create custom logic to change the field model name or control how assembly descriptions are processed, and the out-of-the-box user interface will utilize this custom logic. The code snippet below demonstrates how this works.
If your data model does not match this structure, you can modify the code sample and use it to extract this information from your database and send it to OHDA for analysis. These data extractors are used when you use the Export to Overhead Design and Analysis tool in ArcMap to extract these fields out of the poles and cables.
Poles with custom data miners for OHDA must be located in the bin directory where the OHDA files are installed. You can verify where this folder is by checking your registry key:
Export Poles |
Copy Code
|
---|---|
using System; using System.ComponentModel.Composition; using Miner.Interop; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using Miner.Geodatabase; using Miner.Desktop.StructuralAnalysis; using System.Collections.Generic; using ESRI.ArcGIS.esriSystem; namespace OHDADataMinerSample { [Export(typeof(IGISPoleModel))] public class GISPoleModel : IGISPoleModel { private static readonly log4net.ILog _log = log4net.LogManager.GetLogger("Miner.StructuralAnalysis"); private double _height = 35; private int _class = 1; //private int _remainingPoleStrength = 100; private string _material; private string _assetId; //Added to allow export of ArcMap location private double _z; private double _x; private double _y; private List<IObject> _assembliesFromPole = new List<IObject>(); public List<IObject> AssembliesFromPole { get { return _assembliesFromPole; } set { _assembliesFromPole = value; } } #region IGISPoleModel Members public double GetHeight() { return _height; } // We are only supporting Class 1 through Class 5 poles. public int GetClass() { if (_class > 5 || _class < 1) { _class = 1; } return _class; } public double GetZ() { return _z; } public double GetX() { return _x; } public double GetY() { return _y; } // User has to match up return values from GIS to appropriate enum for pole material in PoleSpec. // For now we assume all poles come across as wood. public string GetMaterial() { return _material; } public string GetAssetId() { return _assetId; } /// <summary> /// Display the label according to the system of units in ArcMap /// Get the GetCoordinateUnit of the shape (in this case, pole) and display the label likewise /// </summary> /// <param name="poleFeature"></param> /// <returns></returns> public string GetLabelOfUnits(IFeature poleFeature) { string unitLabel = String.Empty; Point poleShape = poleFeature.Shape as Point; if (poleShape != null) { ILinearUnit coordinateUnit = GetCoordinateUnit(poleShape); if (coordinateUnit != null) { if (coordinateUnit.Name.Contains("Foot")) unitLabel = "ft"; if (coordinateUnit.Name.Contains("Meter")) unitLabel = "m"; } } return unitLabel; } #endregion public void Hydrate(ESRI.ArcGIS.Geodatabase.IFeature poleFeature) { System.Windows.Forms.MessageBox.Show("Hello from SampleGISPoleModel!"); FindLocation(poleFeature); IFeatureClass featureClass = poleFeature.Class as IFeatureClass; IMMModelNameManager modelNameManager = ModelNameManager.Instance; if (featureClass != null) { if (modelNameManager != null) { bool hasMaterialModelName = false; bool hasHeightModelName = false; bool hasClassModelName = false; bool hasAssetId = false; IFields poleFields = featureClass.Fields; for (int i = 0; i < poleFields.FieldCount; i++) { IField currField = poleFields.get_Field(i); ICodedValueDomain _subtypeDomain = null; ISubtypes subtypes = (ISubtypes)poleFeature.Class; if (subtypes.HasSubtype) { IRowSubtypes rowSubtypes = (IRowSubtypes)poleFeature; var domaininfo = subtypes.get_Domain(rowSubtypes.SubtypeCode, ModelNames.OverheadMaterial); _subtypeDomain = domaininfo as ICodedValueDomain; } if (modelNameManager.ContainsFieldModelName(featureClass, currField, ModelNames.OverheadHeight)) { _height = GenerateHeight(poleFeature.get_Value(i), currField.AliasName); hasHeightModelName = true; } else if (modelNameManager.ContainsFieldModelName(featureClass, currField, ModelNames.OverheadClass)) { _class = GenerateClass(poleFeature.get_Value(i), currField.AliasName); hasClassModelName = true; } else if (modelNameManager.ContainsFieldModelName(featureClass, currField, ModelNames.OverheadMaterial)) { IField materialField = currField; int materialFieldIndex = poleFeature.Class.FindField(materialField.Name); object materialFieldValue = poleFeature.get_Value(materialFieldIndex); if (_subtypeDomain != null) { for (int j = 0; j < _subtypeDomain.CodeCount; j++) { if (_subtypeDomain.get_Value(j).Equals(materialFieldValue)) { _material = _subtypeDomain.get_Name(j); } } } hasMaterialModelName = true; } else if (modelNameManager.ContainsFieldModelName(featureClass, currField, ModelNames.AssetId)) { _assetId = poleFeature.get_Value(i).ToString(); hasAssetId = true; } } //if (_log.IsDebugEnabled) //{ if (!hasHeightModelName) { _log.Debug("Feature Class: <" + featureClass.AliasName + "> does not have the <" + ModelNames.OverheadHeight + "> Field Model Name on any field"); } if (!hasClassModelName) { _log.Debug("Feature Class: <" + featureClass.AliasName + "> does not have the <" + ModelNames.OverheadClass + "> Field Model Name on any field"); } if (!hasMaterialModelName) { _log.Debug("Feature Class: <" + featureClass.AliasName + "> does not have the <" + ModelNames.OverheadMaterial + "> Field Model Name on any field"); } if (!hasAssetId) { _log.Debug("Feature Class: <" + featureClass.AliasName + "> does not have the <" + ModelNames.AssetId + "> Field Model Name on any field"); } } //} AddAssemblies(poleFeature); } } private void AddAssemblies(ESRI.ArcGIS.Geodatabase.IFeature poleFeature) { IMMModelNameManager modelNameManager = ModelNameManager.Instance; IEnumRelationshipClass enumRelationships = poleFeature.Class.RelationshipClasses[esriRelRole.esriRelRoleAny]; enumRelationships.Reset(); IRelationshipClass relationshipClass = enumRelationships.Next(); bool hasAssemblyModelName = false; while (relationshipClass != null) { if (modelNameManager.ContainsClassModelName(relationshipClass.DestinationClass, ModelNames.Assembly)) { hasAssemblyModelName = true; break; } else if (modelNameManager.ContainsClassModelName(relationshipClass.OriginClass, ModelNames.Assembly)) { hasAssemblyModelName = true; break; } relationshipClass = enumRelationships.Next(); } if (!hasAssemblyModelName) { if (_log.IsDebugEnabled) { _log.Debug("Unable to add assemblies to Feature class: <" + poleFeature.Class.AliasName + "> because no <" + ModelNames.Assembly + "> Model name was found on a related class."); } } if (relationshipClass != null) { ISet relatedObjects = relationshipClass.GetObjectsRelatedToObject(poleFeature); relatedObjects.Reset(); object relatedObject = relatedObjects.Next(); while (relatedObject != null) { IObject assemblyObject = relatedObject as IObject; AssembliesFromPole.Add(assemblyObject); relatedObject = relatedObjects.Next(); } AssembliesFromPole.Sort(delegate(IObject p1, IObject p2) { return p1.OID.CompareTo(p2.OID); }); } } /// <summary> /// This method will attempt to extract the x, y, and z of the poleFeature /// provided. /// </summary> /// <param name="poleFeature">IFeature object used to determine location.</param> private void FindLocation(ESRI.ArcGIS.Geodatabase.IFeature poleFeature) { ESRI.ArcGIS.Geometry.Point poleShape = poleFeature.Shape as ESRI.ArcGIS.Geometry.Point; if (poleShape != null) { double conversionFactor = FindConversionFactor(poleShape); _x = poleShape.X * conversionFactor; _y = poleShape.Y * conversionFactor; ESRI.ArcGIS.Geometry.IZAware zAwarePoint = poleShape as ESRI.ArcGIS.Geometry.IZAware; if (zAwarePoint != null) { if (zAwarePoint.ZAware) { _z = poleShape.Z * conversionFactor; } } } } /// <summary> /// This method will determine the conversion factor of the provided IGeometry's spatial reference, used /// to convert this IGeometry object to meters. /// </summary> /// <param name="poleShape">The IGeometry object who's conversion factor will be found.</param> /// <returns></returns> private double FindConversionFactor(IGeometry poleShape) { double conversionFactor = 1d; ILinearUnit shapeCoordinateUnit = GetCoordinateUnit(poleShape); if (shapeCoordinateUnit != null) { conversionFactor = shapeCoordinateUnit.ConversionFactor; } return conversionFactor; } private ILinearUnit GetCoordinateUnit(IGeometry poleShape) { if (poleShape == null) { throw new ArgumentNullException("poleShape"); } ISpatialReference shapeSpatialReference = poleShape.SpatialReference; if (shapeSpatialReference != null) { IProjectedCoordinateSystem shapeCoordinateSystem = shapeSpatialReference as IProjectedCoordinateSystem; if (shapeCoordinateSystem != null) { ILinearUnit shapeCoordinateUnit = shapeCoordinateSystem.CoordinateUnit; return shapeCoordinateUnit; } } return null; } private double GenerateHeight(object value, string fieldName) { return GetValueAsDouble(value, fieldName); } private static double GetValueAsDouble(object value, string fieldName) { try { string valueAsString = value.ToString(); return double.Parse(valueAsString); } catch (FormatException e) { _log.Warn("Convert class to int failed. Check Field <" + fieldName + ">.", e); return -1; } catch (OverflowException e) { _log.Warn("Convert class to int failed. Check Field <" + fieldName + ">.", e); return -1; } catch (Exception e) { _log.Error("Convert class to int failed. Check Field <" + fieldName + ">.", e); return -1; } } private int GenerateClass(object value, string fieldName) { return GetValueAsInt(value, fieldName); } private static int GetValueAsInt(object value, string fieldName) { try { string valueAsString = value.ToString(); return Convert.ToInt32(valueAsString); } catch (FormatException e) { _log.Warn("Convert class to int failed. Check Field <" + fieldName + ">.", e); return -1; } catch (OverflowException e) { _log.Warn("Convert class to int failed. Check Field <" + fieldName + ">.", e); return -1; } catch (Exception e) { _log.Error("Convert class to int failed. Check Field <" + fieldName + ">.", e); return -1; } } private string GenerateMaterial(object value, string fieldName) { return GetValueAsString(value, fieldName); } private static string GetValueAsString(object value, string fieldName) { try { return value.ToString(); } catch (FormatException e) { _log.Warn("Convert class to string failed. Check Field <" + fieldName + ">.", e); return null; } catch (OverflowException e) { _log.Warn("Convert class to string failed. Check Field <" + fieldName + ">.", e); return null; } catch (Exception e) { _log.Error("Convert class to string failed. Check Field <" + fieldName + ">.", e); return null; } } #region IGISPoleModel Members public ICollection<IObject> GetAssociatedAssemblies() { return AssembliesFromPole; } #endregion } } |