// ValidateDataModel - This sample is hard-wired to a particular version of the Naperville data model. // This routine checks to make sure we are using the correct one private bool ValidateDataModel(UtilityNetwork utilityNetwork) { bool dataModelIsValid = false; try { using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) using (NetworkSource transformerBankNetworkSource = GetNetworkSource(utilityNetworkDefinition, AssemblyNetworkSourceName)) using (AssetGroup transformerBankAssetGroup = transformerBankNetworkSource.GetAssetGroup(TransformerBankAssetGroupName)) using (AssetType transformerBankAssetType = transformerBankAssetGroup.GetAssetType(TransformerBankAssetTypeName)) // Transformer using (NetworkSource deviceNetworkSource = GetNetworkSource(utilityNetworkDefinition, DeviceNetworkSourceName)) using (AssetGroup transformerAssetGroup = deviceNetworkSource.GetAssetGroup(TransformerAssetGroupName)) using (AssetType transformerAssetType = transformerAssetGroup.GetAssetType(TransformerAssetTypeName)) // Arrester using (AssetGroup arresterAssetGroup = deviceNetworkSource.GetAssetGroup(ArresterAssetGroupName)) using (AssetType arresterAssetType = arresterAssetGroup.GetAssetType(ArresterAssetTypeName)) // Fuse using (AssetGroup fuseAssetGroup = deviceNetworkSource.GetAssetGroup(FuseAssetGroupName)) using (AssetType fuseAssetType = fuseAssetGroup.GetAssetType(FuseAssetTypeName)) { // Find the upstream terminal on the transformer TerminalConfiguration terminalConfiguration = transformerAssetType.GetTerminalConfiguration(); Terminal upstreamTerminal = null; foreach (Terminal terminal in terminalConfiguration.Terminals) { if (terminal.IsUpstreamTerminal) { upstreamTerminal = terminal; break; } } // Find the terminal on the fuse Terminal fuseTerminal = fuseAssetType.GetTerminalConfiguration().Terminals[0]; // Find the terminal on the arrester Terminal arresterTerminal = arresterAssetType.GetTerminalConfiguration().Terminals[0]; // All of our asset groups and asset types exist. Now we have to check for rules. IReadOnlyList <Rule> rules = utilityNetworkDefinition.GetRules(); if (ContainmentRuleExists(rules, transformerBankAssetType, transformerAssetType) && ContainmentRuleExists(rules, transformerBankAssetType, fuseAssetType) && ContainmentRuleExists(rules, transformerBankAssetType, arresterAssetType) && ConnectivityRuleExists(rules, transformerAssetType, upstreamTerminal, fuseAssetType, fuseTerminal) && ConnectivityRuleExists(rules, fuseAssetType, fuseTerminal, arresterAssetType, arresterTerminal)) { dataModelIsValid = true; } } } catch { } return(dataModelIsValid); }
/// <summary> /// Get the Un Schema version /// </summary> /// <param name="diagram">NetworkDiagram</param> /// <returns>string</returns> /// <remarks>UN Version 3 and earlier use only Subnetwork name /// UN Version 4 and later use Supported subnetwork name for container /// UN Version 5 and later use Supporting subnetwork name for structure</remarks> internal static int GetSchemaVersion(NetworkDiagram diagram) { DiagramManager diagramManager = diagram.DiagramManager; UtilityNetwork utilityNetwork = diagramManager.GetNetwork <UtilityNetwork>(); UtilityNetworkDefinition unDefinition = utilityNetwork.GetDefinition(); return(Convert.ToInt32(unDefinition.GetSchemaVersion())); }
protected override async void OnClick() { try { string unLayerName = "Electric Utility Network"; Layer unLayer = await GetLayerByName(MapView.Active.Map, unLayerName); UtilityNetwork utilityNetwork = await GetUNByLayer(unLayer); QueuedTask.Run(() => { UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition(); /* Uncomment to print out the network attributes in the utlity network * IReadOnlyList<NetworkAttribute> networkAttributes = utilityNetworkDefinition.GetNetworkAttributes(); * string attributesMessage = "Network attributes: " + Environment.NewLine; * foreach (var networkAttribute in networkAttributes) * { * attributesMessage += networkAttribute.Name + Environment.NewLine; * } * MessageBox.Show(attributesMessage); */ /* Uncomment to print out the categories in the utlity network * IReadOnlyList<string> categories = utilityNetworkDefinition.GetAvailableCategories(); * string categoriesMsg = "Categories: " + Environment.NewLine; * foreach (var category in categories) * { * categoriesMsg += category + Environment.NewLine; * } * MessageBox.Show(categoriesMsg); */ string result = $"Domain Networks: {Environment.NewLine}"; IReadOnlyList <DomainNetwork> domainNetworks = utilityNetworkDefinition.GetDomainNetworks(); if (domainNetworks != null) { foreach (DomainNetwork domainNetwork in domainNetworks) { result += $"{domainNetwork.Name}{Environment.NewLine}"; } } else { result += "No domain networks found"; } MessageBox.Show(result); }).Wait(); } catch (Exception ex) { MessageBox.Show($"An exception occurred: {ex.Message}"); } }
/// <summary> /// This method makes sure /// 1. The Mapview is Active /// 2. There is at least one layer selected /// 3. That layer is either /// a. A utility network layer /// b. A feature layer whose feature class belongs to a utility network /// c. A subtype group layer whose feature class belongs to a utility network /// /// If all of these hold true, we populate the combo box with the list of categories that are registered with this utility network /// </summary> private async void UpdateCategoryList(MapViewEventArgs mapViewEventArgs) { // Verify that the map view is active and at least one layer is selected if (MapView.Active == null || mapViewEventArgs.MapView.GetSelectedLayers().Count < 1) { Enabled = false; return; } // Verify that we have the correct kind of layer Layer selectedLayer = mapViewEventArgs.MapView.GetSelectedLayers()[0]; if (!(selectedLayer is UtilityNetworkLayer) && !(selectedLayer is FeatureLayer) && !(selectedLayer is SubtypeGroupLayer)) { Enabled = false; return; } // Switch to the MCT to access the geodatabase await QueuedTask.Run(() => { // Get the utility network from the layer. // It's possible that the layer is a FeatureLayer or SubtypeGroupLayer that doesn't refer to a utility network at all. using (UtilityNetwork utilityNetwork = UtilityNetworkUtils.GetUtilityNetworkFromLayer(selectedLayer)) { if (utilityNetwork == null) { Enabled = false; return; } // Enable the combo box and clear out its contents Enabled = true; Clear(); // Fill the combo box with all of the categories in the utility network using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) { IReadOnlyList <string> categories = utilityNetworkDefinition.GetAvailableCategories(); foreach (string category in categories) { Add(new ComboBoxItem(category)); } } } }); // Store the layer if (Enabled) { myLayer = selectedLayer; } }
void FindATierFromDomainNetworkNameAndTierName(UtilityNetwork utilityNetwork, string domainNetworkName, string tierName) { #region Find a Tier given a Domain Network name and Tier name using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) { DomainNetwork domainNetwork = utilityNetworkDefinition.GetDomainNetwork(domainNetworkName); Tier tier = domainNetwork.GetTier(tierName); } #endregion }
protected override async void OnClick() { try { string unLayerName = "Electric Utility Network"; string domainNetworkName = "ElectricTransmission"; string tierName = "AC High Voltage"; Layer unLayer = await GetLayerByName(MapView.Active.Map, unLayerName); UtilityNetwork utilityNetwork = await GetUNByLayer(unLayer); await QueuedTask.Run(() => { using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) { DomainNetwork domainNetwork = utilityNetworkDefinition.GetDomainNetwork(domainNetworkName); Tier tier = domainNetwork.GetTier(tierName); using (SubnetworkManager subnetworkManager = utilityNetwork.GetSubnetworkManager()) { Subnetwork dirtySubnetwork = subnetworkManager.GetSubnetworks(tier, SubnetworkStates.Dirty).FirstOrDefault(); try { if (dirtySubnetwork != null) { SubnetworkController subnetworkController = dirtySubnetwork.GetControllers().First(); subnetworkManager.DisableControllerInEditOperation(subnetworkController.Element); utilityNetwork.ValidateNetworkTopologyInEditOperation(); dirtySubnetwork.Update(); // Redraw map and clear cache MapView.Active.Redraw(true); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } // utilityNetwork.ValidateNetworkTopology(); }); } catch (Exception ex) { MessageBox.Show($"An exception occurred: {ex.Message}"); } }
/// <summary> /// This routine validates the utility network schema matches what we are expecting /// </summary> /// <param name="utilityNetwork"></param> /// <returns>true if the data model has all of the correct schema</returns> private bool ValidateDataModel(UtilityNetwork utilityNetwork) { bool dataModelIsValid = false; using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) { try { DomainNetwork electricDomainNetwork = utilityNetworkDefinition.GetDomainNetwork(ElectricDomainNetwork); Tier mediumVoltageTier = electricDomainNetwork.GetTier(MediumVoltageTier); NetworkAttribute phaseNetworkAttribute = utilityNetworkDefinition.GetNetworkAttribute(PhaseAttributeName); NetworkAttribute loadNetworkAttribute = utilityNetworkDefinition.GetNetworkAttribute(LoadAttributeName); if (utilityNetworkDefinition.GetAvailableCategories().Contains(ServicePointCategory)) { dataModelIsValid = true; } } catch (Exception) { }; } return(dataModelIsValid); }
private static void ExecuteTrace(Guid traceStartGuid, string geodatabasePath) { using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(geodatabasePath)))) { IReadOnlyList <UtilityNetworkDefinition> utilityNetworkDefinitions = geodatabase.GetDefinitions <UtilityNetworkDefinition>(); string utilityNetworkName = string.Empty; if (utilityNetworkDefinitions.Count < 0 || utilityNetworkDefinitions.Count > 1) { return; } // Get utility network name from the dataset foreach (UtilityNetworkDefinition definition in utilityNetworkDefinitions) { utilityNetworkName = definition.GetName(); Console.WriteLine($"Utility network name: {utilityNetworkName}"); definition.Dispose(); } // Open utility network using (UtilityNetwork utilityNetwork = geodatabase.OpenDataset <UtilityNetwork>(utilityNetworkName)) using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) { using (NetworkSource networkSource = utilityNetworkDefinition.GetNetworkSource("ElectricDevice")) using (AssetGroup assetGroup = networkSource.GetAssetGroup("Medium Voltage Transformer")) using (AssetType assetType = assetGroup.GetAssetType("Overhead Single Phase")) { DomainNetwork domainNetwork = utilityNetworkDefinition.GetDomainNetwork("Electric"); Tier sourceTier = domainNetwork.GetTier("Electric Distribution"); TraceConfiguration traceConfiguration = sourceTier.GetTraceConfiguration(); // Get downstream side of the terminal Terminal terminal = null; if (assetType.IsTerminalConfigurationSupported()) { TerminalConfiguration terminalConfiguration = assetType.GetTerminalConfiguration(); IReadOnlyList <Terminal> terminals = terminalConfiguration.Terminals; terminal = terminals.First(t => !t.IsUpstreamTerminal); } // Create an element to begin a trace Element startingPointElement = utilityNetwork.CreateElement(assetType, traceStartGuid, terminal); List <Element> startingPoints = new List <Element>(); startingPoints.Add(startingPointElement); // Get trace manager using (TraceManager traceManager = utilityNetwork.GetTraceManager()) { // Set trace configurations TraceArgument traceArgument = new TraceArgument(startingPoints); traceArgument.Configuration = traceConfiguration; // Get downstream tracer Tracer tracer = traceManager.GetTracer <DownstreamTracer>(); // Execuate downstream trace IReadOnlyList <Result> traceResults = tracer.Trace(traceArgument); // Display trace results in console foreach (Result result in traceResults) { if (result is ElementResult) { ElementResult elementResult = result as ElementResult; IReadOnlyList <Element> elements = elementResult.Elements; Console.WriteLine("Trace result elements:"); foreach (Element element in elements) { Console.WriteLine($"\t OID: {element.ObjectID}, Name:{element.AssetType.Name}"); } } else if (result is FunctionOutputResult) { FunctionOutputResult functionResult = result as FunctionOutputResult; IReadOnlyList <FunctionOutput> functionOutputs = functionResult.FunctionOutputs; Console.WriteLine("Trace result function outputs:"); foreach (FunctionOutput functionOut in functionOutputs) { Console.WriteLine($"\t Function result:{functionOut.Value}, name: {functionOut.Function}"); } } else if (result is AggregatedGeometryResult) { AggregatedGeometryResult aggResults = result as AggregatedGeometryResult; Polyline aggregatedLine = aggResults.Line as Polyline; Multipoint aggregatedPoint = aggResults.Point as Multipoint; Polygon aggregatedPolygon = aggResults.Polygon as Polygon; } } } } } } }
/// <summary> /// GenerateReport /// /// This routine takes a feature layer that references a feature class that participates in a utility network. /// It returns a set of data to display on the UI thread. /// /// /// </summary> public LoadTraceResults GenerateReport(Layer selectedLayer) { // Create a new results object. We use this class to pass back a set of data from the worker thread to the UI thread LoadTraceResults results = new LoadTraceResults(); // Initialize a number of geodatabase objects using (UtilityNetwork utilityNetwork = UtilityNetworkUtils.GetUtilityNetworkFromLayer(selectedLayer)) { if (utilityNetwork == null) { results.Message = "Please select a utility network layer."; results.Success = false; } else { using (Geodatabase utilityNetworkGeodatabase = utilityNetwork.GetDatastore() as Geodatabase) using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) using (Geodatabase defaultGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath)))) using (TraceManager traceManager = utilityNetwork.GetTraceManager()) { // First check to make sure we have a feature service workspace. Utility Network functionality requires this. if (utilityNetworkGeodatabase.GetGeodatabaseType() != GeodatabaseType.Service) { results.Message = "A feature service workspace connection is required."; results.Success = false; return(results); } // Get a row from the starting points table in the default project workspace. This table is created the first time the user creates a starting point // If the table is missing or empty, a null row is returned using (Row startingPointRow = GetStartingPointRow(defaultGeodatabase, ref results)) { if (startingPointRow != null) { // Convert starting point row into network element Element startingPointElement = GetElementFromPointRow(startingPointRow, utilityNetwork, utilityNetworkDefinition); // Obtain a tracer object DownstreamTracer downstreamTracer = traceManager.GetTracer <DownstreamTracer>(); // Get the network attributes that we will use in our trace using (NetworkAttribute phasesNetworkAttribute = GetAttribute(utilityNetworkDefinition, PhaseAttributeNames)) using (NetworkAttribute loadNetworkAttribute = GetAttribute(utilityNetworkDefinition, LoadAttributeNames)) using (NetworkAttribute deviceStatusNetworkAttribute = GetAttribute(utilityNetworkDefinition, DeviceStatusAttributeNames)) { if (phasesNetworkAttribute == null || loadNetworkAttribute == null || deviceStatusNetworkAttribute == null) { results.Success = false; results.Message = "This add-in requires network attributes for phase, service load, and device status.\n"; return(results); } // Get the Tier for Medium Voltage Radial DomainNetwork electricDomainNetwork = utilityNetworkDefinition.GetDomainNetwork(ElectricDomainNetwork); Tier mediumVoltageTier = electricDomainNetwork.GetTier(MediumVoltageTier); // Set up the trace configuration TraceConfiguration traceConfiguration = new TraceConfiguration(); // Configure the trace to use the electric domain network traceConfiguration.DomainNetwork = electricDomainNetwork; // Take the default TraceConfiguration from the Tier for Traversability Traversability tierTraceTraversability = mediumVoltageTier.TraceConfiguration.Traversability; traceConfiguration.Traversability.FunctionBarriers = tierTraceTraversability.FunctionBarriers; traceConfiguration.IncludeBarriersWithResults = mediumVoltageTier.TraceConfiguration.IncludeBarriersWithResults; traceConfiguration.Traversability.Scope = tierTraceTraversability.Scope; ConditionalExpression baseCondition = tierTraceTraversability.Barriers as ConditionalExpression; // Create a condition to only return features that have the service point category ConditionalExpression servicePointCategoryCondition = new CategoryComparison(CategoryOperator.IsEqual, ServicePointCategory); // Create function to sum loads on service points where phase = A ConditionalExpression aPhaseCondition = new NetworkAttributeComparison(phasesNetworkAttribute, Operator.DoesNotIncludeTheValues, APhase); Add aPhaseLoad = new Add(loadNetworkAttribute, servicePointCategoryCondition); // Create function to sum loads on service points where phase = B ConditionalExpression bPhaseCondition = new NetworkAttributeComparison(phasesNetworkAttribute, Operator.DoesNotIncludeTheValues, BPhase); Add bPhaseLoad = new Add(loadNetworkAttribute, servicePointCategoryCondition); // Create function to sum loads on service points where phase = C ConditionalExpression cPhaseCondition = new NetworkAttributeComparison(phasesNetworkAttribute, Operator.DoesNotIncludeTheValues, CPhase); Add cPhaseLoad = new Add(loadNetworkAttribute, servicePointCategoryCondition); // Set the output condition to only return features that have the service point category traceConfiguration.OutputCondition = servicePointCategoryCondition; // Create starting point list and trace argument object List <Element> startingPointList = new List <Element>() { startingPointElement }; TraceArgument traceArgument = new TraceArgument(startingPointList); traceArgument.Configuration = traceConfiguration; // Trace on the A phase traceConfiguration.Traversability.Barriers = new Or(baseCondition, aPhaseCondition); traceConfiguration.Functions = new List <Function>() { aPhaseLoad }; traceArgument.Configuration = traceConfiguration; try { IReadOnlyList <Result> resultsA = downstreamTracer.Trace(traceArgument); ElementResult elementResult = resultsA.OfType <ElementResult>().First(); results.NumberServicePointsA = elementResult.Elements.Count; FunctionOutputResult functionOutputResult = resultsA.OfType <FunctionOutputResult>().First(); results.TotalLoadA = (double)functionOutputResult.FunctionOutputs.First().Value; } catch (ArcGIS.Core.Data.GeodatabaseUtilityNetworkException e) { //No A phase connectivity to source if (!e.Message.Equals("No subnetwork source was discovered.")) { results.Success = false; results.Message += e.Message; } } // Trace on the B phase traceConfiguration.Traversability.Barriers = new Or(baseCondition, bPhaseCondition); traceConfiguration.Functions = new List <Function>() { bPhaseLoad }; traceArgument.Configuration = traceConfiguration; try { IReadOnlyList <Result> resultsB = downstreamTracer.Trace(traceArgument); ElementResult elementResult = resultsB.OfType <ElementResult>().First(); results.NumberServicePointsB = elementResult.Elements.Count; FunctionOutputResult functionOutputResult = resultsB.OfType <FunctionOutputResult>().First(); results.TotalLoadB = (double)functionOutputResult.FunctionOutputs.First().Value; } catch (ArcGIS.Core.Data.GeodatabaseUtilityNetworkException e) { // No B phase connectivity to source if (!e.Message.Equals("No subnetwork source was discovered.")) { results.Success = false; results.Message += e.Message; } } // Trace on the C phase traceConfiguration.Traversability.Barriers = new Or(baseCondition, cPhaseCondition); traceConfiguration.Functions = new List <Function>() { cPhaseLoad }; traceArgument.Configuration = traceConfiguration; try { IReadOnlyList <Result> resultsC = downstreamTracer.Trace(traceArgument); ElementResult elementResult = resultsC.OfType <ElementResult>().First(); results.NumberServicePointsC = elementResult.Elements.Count; FunctionOutputResult functionOutputResult = resultsC.OfType <FunctionOutputResult>().First(); results.TotalLoadC = (double)functionOutputResult.FunctionOutputs.First().Value; } catch (ArcGIS.Core.Data.GeodatabaseUtilityNetworkException e) { // No C phase connectivity to source if (!e.Message.Equals("No subnetwork source was discovered.")) { results.Success = false; results.Message += e.Message; } } } // append success message to the output string results.Message += "Trace successful."; results.Success = true; } } } } } return(results); }
/// <summary> /// The on comboBox selection change event. This creates a new table that lists the assignments for the specified category. This table is added to the map, selected in the TOC, and opened. /// </summary> /// <param name="item">The newly selected combo box item</param> protected override async void OnSelectionChange(ComboBoxItem item) { if (item == null) { return; } if (string.IsNullOrEmpty(item.Text)) { return; } if (myLayer == null) { return; } //Construct the name of our table for the category assignment report string baseCategoryReportTableName = "CategoryAssignments_" + item.Text; string categoryReportTableName = baseCategoryReportTableName.Replace(" ", "_"); bool needToCreateTable = true; bool needToAddStandaloneTable = true; // Switch to the MCT to access the geodatabase await QueuedTask.Run(() => { // Check if the table exists using (Geodatabase projectWorkspace = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath)))) { try { using (Table categoryReportTable = projectWorkspace.OpenDataset <Table>(categoryReportTableName)) { // Table exists, we do not need to create it... needToCreateTable = false; // .. but we should delete the existing contents categoryReportTable.DeleteRows(new QueryFilter()); // Check to see if a Standalone table exists in the map bool standaloneTableFound = false; ReadOnlyObservableCollection <StandaloneTable> initialStandaloneTables = MapView.Active.Map.StandaloneTables; foreach (StandaloneTable standaloneTable in initialStandaloneTables) { if (standaloneTable.Name == categoryReportTableName) { standaloneTableFound = true; } } // Since there is already a StandaloneTable that references our category table in the map, we don't need to add it needToAddStandaloneTable = !standaloneTableFound; } } catch { //Table doesn't exist. Not an error, but we will have to create it } } }); // Create the category report table if (needToCreateTable) { // Create table IReadOnlyList <string> createParams = Geoprocessing.MakeValueArray(new object[] { Project.Current.DefaultGeodatabasePath, categoryReportTableName, null, null }); IGPResult result = await Geoprocessing.ExecuteToolAsync("management.CreateTable", createParams); if (result.IsFailed) { MessageBox.Show("Unable to create category assignment table in project workspace", "Category Assignments"); return; } // Add field for feature class alias IReadOnlyList <string> addFieldParams = Geoprocessing.MakeValueArray(new object[] { categoryReportTableName, "FeatureClassAlias", "TEXT", null, null, 32, "Feature Class", "NULLABLE", "NON_REQUIRED", null }); result = await Geoprocessing.ExecuteToolAsync("management.AddField", addFieldParams); if (result.IsFailed) { MessageBox.Show("Unable to modify schema of category assignment table in project workspace", "Category Assignments"); return; } // Add field for Asset Group name addFieldParams = Geoprocessing.MakeValueArray(new object[] { categoryReportTableName, "AssetGroupName", "TEXT", null, null, 256, "Asset Group Name", "NULLABLE", "NON_REQUIRED", null }); result = await Geoprocessing.ExecuteToolAsync("management.AddField", addFieldParams); if (result.IsFailed) { MessageBox.Show("Unable to modify schema of category assignment table in project workspace", "Category Assignments"); return; } // Add field for Asset Type name addFieldParams = Geoprocessing.MakeValueArray(new object[] { categoryReportTableName, "AssetTypeName", "TEXT", null, null, 256, "Asset Type Name", "NULLABLE", "NON_REQUIRED", null }); result = await Geoprocessing.ExecuteToolAsync("management.AddField", addFieldParams); if (result.IsFailed) { MessageBox.Show("Unable to modify schema of category assignment table in project workspace", "Category Assignments"); return; } needToAddStandaloneTable = false; //creating a table automatically adds it to the map } // Populate table // Again, we need to switch to the MCT to execute geodatabase and utility network code await QueuedTask.Run(() => { using (Geodatabase projectWorkspace = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath)))) using (Table categoryReportTable = projectWorkspace.OpenDataset <Table>(categoryReportTableName)) using (UtilityNetwork utilityNetwork = UtilityNetworkSamples.UtilityNetworkUtils.GetUtilityNetworkFromLayer(myLayer)) using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) { IReadOnlyList <NetworkSource> networkSources = utilityNetworkDefinition.GetNetworkSources(); // Step through each NetworkSource foreach (NetworkSource networkSource in networkSources) { IReadOnlyList <AssetGroup> assetGroups = networkSource.GetAssetGroups(); // Step through each AssetGroup foreach (AssetGroup assetGroup in assetGroups) { IReadOnlyList <AssetType> assetTypes = assetGroup.GetAssetTypes(); // Step through each AssetType foreach (AssetType assetType in assetTypes) { // Check to see if this AssetType is assigned the Category we are looking for IReadOnlyList <string> assignedCategoryList = assetType.CategoryList; foreach (string assignedCategory in assignedCategoryList) { if (assignedCategory == item.Text) { // Our Category is assigned to this AssetType. Create a row to store in the category report table using (FeatureClass networkSourceFeatureClass = utilityNetwork.GetTable(networkSource) as FeatureClass) using (FeatureClassDefinition networkSourceFeatureClassDefinition = networkSourceFeatureClass.GetDefinition()) using (RowBuffer rowBuffer = categoryReportTable.CreateRowBuffer()) { rowBuffer["FeatureClassAlias"] = networkSourceFeatureClassDefinition.GetAliasName(); rowBuffer["AssetGroupName"] = assetGroup.Name; rowBuffer["AssetTypeName"] = assetType.Name; categoryReportTable.CreateRow(rowBuffer).Dispose(); } } } } } } // If necessary, add our category report table to the map as a standalone table if (needToAddStandaloneTable) { IStandaloneTableFactory tableFactory = StandaloneTableFactory.Instance; tableFactory.CreateStandaloneTable(categoryReportTable, MapView.Active.Map); } } }); // Open category report stand alone table into a window ReadOnlyObservableCollection <StandaloneTable> standaloneTables = MapView.Active.Map.StandaloneTables; foreach (StandaloneTable standaloneTable in standaloneTables) { if (standaloneTable.Name == categoryReportTableName) { FrameworkApplication.Panes.OpenTablePane(standaloneTable, TableViewMode.eAllRecords); } } }
/// <summary> /// Called when the sketch finishes. This is where we will create the sketch operation and then execute it. /// </summary> /// <param name="geometry">The geometry created by the sketch.</param> /// <returns>A Task returning a Boolean indicating if the sketch complete event was successfully handled.</returns> protected override async Task <bool> OnSketchCompleteAsync(Geometry geometry) { if (geometry == null) { return(false); } // Create an edit operation var createOperation = new EditOperation(); createOperation.Name = "Create Transformer Bank"; createOperation.SelectNewFeatures = true; bool success = false; string errorMessage = ""; await QueuedTask.Run(() => { Map map = GetMap(); using (UtilityNetwork utilityNetwork = GetUtilityNetwork()) { if (utilityNetwork == null) { errorMessage = "Please select a layer that participates in a utility network."; } else { using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) // Get the NetworkSource, AssetGroup, and AssetTypes for all of the features we want to create // If this was production code, you would want to check the return values to make sure that these asset groups and asset types existed. // TransformerBank using (NetworkSource transformerBankNetworkSource = utilityNetworkDefinition.GetNetworkSource(AssemblyNetworkSourceName)) using (AssetGroup transformerBankAssetGroup = transformerBankNetworkSource.GetAssetGroup(TransformerBankAssetGroupName)) using (AssetType transformerBankAssetType = transformerBankAssetGroup.GetAssetType(TransformerBankAssetTypeName)) // Transformer using (NetworkSource deviceNetworkSource = utilityNetworkDefinition.GetNetworkSource(DeviceNetworkSourceName)) using (AssetGroup transformerAssetGroup = deviceNetworkSource.GetAssetGroup(TransformerAssetGroupName)) using (AssetType transformerAssetType = transformerAssetGroup.GetAssetType(TransformerAssetTypeName)) // Arrester using (AssetGroup arresterAssetGroup = deviceNetworkSource.GetAssetGroup(ArresterAssetGroupName)) using (AssetType arresterAssetType = arresterAssetGroup.GetAssetType(ArresterAssetTypeName)) // Fuse using (AssetGroup fuseAssetGroup = deviceNetworkSource.GetAssetGroup(FuseAssetGroupName)) using (AssetType fuseAssetType = fuseAssetGroup.GetAssetType(FuseAssetTypeName)) { MapPoint clickPoint = geometry as MapPoint; // Create a transformer bank Layer transformerBankLayer = GetLayerForEdit(map, AssemblyNetworkSourceName, TransformerBankAssetGroupName); RowToken token = createOperation.CreateEx(transformerBankLayer, CreateAttributes(transformerBankAssetGroup, transformerBankAssetType, clickPoint)); RowHandle transformerBankHandle = new RowHandle(token); // Create three transformers, one for each phase Layer transformerLayer = GetLayerForEdit(map, DeviceNetworkSourceName, TransformerAssetGroupName); MapPoint transformerPointA = CreateOffsetMapPoint(clickPoint, -1 * XOffset, YOffset); token = createOperation.CreateEx(transformerLayer, CreateDeviceAttributes(transformerAssetGroup, transformerAssetType, transformerPointA, APhase)); RowHandle transformerHandleA = new RowHandle(token); MapPoint transformerPointB = CreateOffsetMapPoint(clickPoint, 0, YOffset); token = createOperation.CreateEx(transformerLayer, CreateDeviceAttributes(transformerAssetGroup, transformerAssetType, transformerPointB, BPhase)); RowHandle transformerHandleB = new RowHandle(token); MapPoint transformerPointC = CreateOffsetMapPoint(clickPoint, XOffset, YOffset); token = createOperation.CreateEx(transformerLayer, CreateDeviceAttributes(transformerAssetGroup, transformerAssetType, transformerPointC, CPhase)); RowHandle transformerHandleC = new RowHandle(token); // Create containment associations between the bank and the transformers ContainmentAssociationDescription containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, transformerHandleA, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, transformerHandleB, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, transformerHandleC, false); createOperation.Create(containmentAssociationDescription); // Create three arresters, one for each phase Layer arresterLayer = GetLayerForEdit(map, DeviceNetworkSourceName, ArresterAssetGroupName); MapPoint arresterPointA = CreateOffsetMapPoint(clickPoint, -1 * XOffset, 2 * YOffset); token = createOperation.CreateEx(arresterLayer, CreateDeviceAttributes(arresterAssetGroup, arresterAssetType, arresterPointA, APhase)); RowHandle arresterHandlA = new RowHandle(token); MapPoint arresterPointB = CreateOffsetMapPoint(clickPoint, 0, 2 * YOffset); token = createOperation.CreateEx(arresterLayer, CreateDeviceAttributes(arresterAssetGroup, arresterAssetType, arresterPointB, BPhase)); RowHandle arresterHandleB = new RowHandle(token); MapPoint arresterPointC = CreateOffsetMapPoint(clickPoint, XOffset, 2 * YOffset); token = createOperation.CreateEx(arresterLayer, CreateDeviceAttributes(arresterAssetGroup, arresterAssetType, arresterPointC, CPhase)); RowHandle arresterHandleC = new RowHandle(token); // Create containment associations between the bank and the arresters containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, arresterHandlA, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, arresterHandleB, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, arresterHandleC, false); createOperation.Create(containmentAssociationDescription); // Find the high-side terminal for transformers TerminalConfiguration transformerTerminalConfiguration = transformerAssetType.GetTerminalConfiguration(); IReadOnlyList <Terminal> terminals = transformerTerminalConfiguration.Terminals; Terminal highSideTerminal = terminals.First(x => x.IsUpstreamTerminal == true); long highSideTerminalID = highSideTerminal.ID; // Connect the high-side transformer terminals to the arresters (connect the A-phase transformer to the A-phase arrester, and so on) ConnectivityAssociationDescription connectivityAssociationDescription = new ConnectivityAssociationDescription(transformerHandleA, highSideTerminalID, arresterHandlA); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new ConnectivityAssociationDescription(transformerHandleB, highSideTerminalID, arresterHandleB); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new ConnectivityAssociationDescription(transformerHandleC, highSideTerminalID, arresterHandleC); createOperation.Create(connectivityAssociationDescription); // Create three fuses, one for each phase Layer fuseLayer = GetLayerForEdit(map, DeviceNetworkSourceName, FuseAssetGroupName); MapPoint fusePointA = CreateOffsetMapPoint(clickPoint, -1 * XOffset, 3 * YOffset); token = createOperation.CreateEx(fuseLayer, CreateDeviceAttributes(fuseAssetGroup, fuseAssetType, fusePointA, APhase)); RowHandle fuseHandleA = new RowHandle(token); MapPoint fusePointB = CreateOffsetMapPoint(clickPoint, 0, 3 * YOffset); token = createOperation.CreateEx(fuseLayer, CreateDeviceAttributes(fuseAssetGroup, fuseAssetType, fusePointB, BPhase)); RowHandle fuseHandleB = new RowHandle(token); MapPoint fusePointC = CreateOffsetMapPoint(clickPoint, XOffset, 3 * YOffset); token = createOperation.CreateEx(fuseLayer, CreateDeviceAttributes(fuseAssetGroup, fuseAssetType, fusePointC, CPhase)); RowHandle fuseHandleC = new RowHandle(token); // Create containment associations between the bank and the fuses containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, fuseHandleA, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, fuseHandleB, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new ContainmentAssociationDescription(transformerBankHandle, fuseHandleC, false); createOperation.Create(containmentAssociationDescription); // Create connectivity associations between the fuses and the arresters (connect the A-phase fuse the A-phase arrester, and so on) connectivityAssociationDescription = new ConnectivityAssociationDescription(fuseHandleA, arresterHandlA); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new ConnectivityAssociationDescription(fuseHandleB, arresterHandleB); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new ConnectivityAssociationDescription(fuseHandleC, arresterHandleC); createOperation.Create(connectivityAssociationDescription); // Execute the edit operation, which creates all of the rows and associations success = createOperation.Execute(); if (!success) { errorMessage = createOperation.ErrorMessage; } } } } }); if (!success) { MessageBox.Show(errorMessage, "Create Transformer Bank Tool"); } return(success); }
/// <summary> /// Called when the sketch finishes. This is where we will create the sketch operation and then execute it. /// </summary> /// <param name="geometry">The geometry created by the sketch.</param> /// <returns>A Task returning a Boolean indicating if the sketch complete event was successfully handled.</returns> protected override async Task <bool> OnSketchCompleteAsync(Geometry geometry) { if (geometry == null) { return(false); } // Create an edit operation var createOperation = new EditOperation() { Name = "Create Transformer Bank", SelectNewFeatures = true }; bool success = false; string errorMessage = ""; await QueuedTask.Run(() => { Map map = GetMap(); using (UtilityNetwork utilityNetwork = GetUtilityNetwork()) { if (utilityNetwork == null) { errorMessage = "Please select a layer that participates in a utility network."; } else { if (!ValidateDataModel(utilityNetwork)) { errorMessage = "This sample is designed for a different utility network data model"; } else { using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition()) // Get the NetworkSource, FeatureClass, AssetGroup, and AssetTypes for all of the features we want to create // The existence of these values has already been confirmed in the ValidateDataModel() routine // TransformerBank using (NetworkSource transformerBankNetworkSource = GetNetworkSource(utilityNetworkDefinition, AssemblyNetworkSourceName)) using (FeatureClass transformerBankFeatureClass = utilityNetwork.GetTable(transformerBankNetworkSource) as FeatureClass) using (AssetGroup transformerBankAssetGroup = transformerBankNetworkSource.GetAssetGroup(TransformerBankAssetGroupName)) using (AssetType transformerBankAssetType = transformerBankAssetGroup.GetAssetType(TransformerBankAssetTypeName)) // Transformer using (NetworkSource deviceNetworkSource = GetNetworkSource(utilityNetworkDefinition, DeviceNetworkSourceName)) using (FeatureClass deviceFeatureClass = utilityNetwork.GetTable(deviceNetworkSource) as FeatureClass) using (AssetGroup transformerAssetGroup = deviceNetworkSource.GetAssetGroup(TransformerAssetGroupName)) using (AssetType transformerAssetType = transformerAssetGroup.GetAssetType(TransformerAssetTypeName)) // Arrester using (AssetGroup arresterAssetGroup = deviceNetworkSource.GetAssetGroup(ArresterAssetGroupName)) using (AssetType arresterAssetType = arresterAssetGroup.GetAssetType(ArresterAssetTypeName)) // Fuse using (AssetGroup fuseAssetGroup = deviceNetworkSource.GetAssetGroup(FuseAssetGroupName)) using (AssetType fuseAssetType = fuseAssetGroup.GetAssetType(FuseAssetTypeName)) { MapPoint clickPoint = geometry as MapPoint; // Create a transformer bank RowToken token = createOperation.CreateEx(transformerBankFeatureClass, CreateAttributes(transformerBankAssetGroup, transformerBankAssetType, clickPoint)); RowHandle transformerBankHandle = new RowHandle(token); // Create three transformers, one for each phase MapPoint transformerPointA = CreateOffsetMapPoint(clickPoint, -1 * XOffset, YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(transformerAssetGroup, transformerAssetType, transformerPointA, APhase)); RowHandle transformerHandleA = new RowHandle(token); MapPoint transformerPointB = CreateOffsetMapPoint(clickPoint, 0, YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(transformerAssetGroup, transformerAssetType, transformerPointB, BPhase)); RowHandle transformerHandleB = new RowHandle(token); MapPoint transformerPointC = CreateOffsetMapPoint(clickPoint, XOffset, YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(transformerAssetGroup, transformerAssetType, transformerPointC, CPhase)); RowHandle transformerHandleC = new RowHandle(token); // Create containment associations between the bank and the transformers AssociationDescription containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, transformerHandleA, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, transformerHandleB, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, transformerHandleC, false); createOperation.Create(containmentAssociationDescription); // Find the high-side terminal for transformers TerminalConfiguration transformerTerminalConfiguration = transformerAssetType.GetTerminalConfiguration(); IReadOnlyList <Terminal> terminals = transformerTerminalConfiguration.Terminals; Terminal highSideTerminal = terminals.First(x => x.IsUpstreamTerminal == true); long highSideTerminalID = highSideTerminal.ID; // Create three fuses, one for each phase MapPoint fusePointA = CreateOffsetMapPoint(clickPoint, -1 * XOffset, 2 * YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(fuseAssetGroup, fuseAssetType, fusePointA, APhase)); RowHandle fuseHandleA = new RowHandle(token); MapPoint fusePointB = CreateOffsetMapPoint(clickPoint, 0, 2 * YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(fuseAssetGroup, fuseAssetType, fusePointB, BPhase)); RowHandle fuseHandleB = new RowHandle(token); MapPoint fusePointC = CreateOffsetMapPoint(clickPoint, XOffset, 2 * YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(fuseAssetGroup, fuseAssetType, fusePointC, CPhase)); RowHandle fuseHandleC = new RowHandle(token); // Create containment associations between the bank and the fuses containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, fuseHandleA, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, fuseHandleB, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, fuseHandleC, false); createOperation.Create(containmentAssociationDescription); // Connect the high-side transformer terminals to the fuses (connect the A-phase transformer to the A-phase fuse, and so on) AssociationDescription connectivityAssociationDescription = new AssociationDescription(AssociationType.JunctionJunctionConnectivity, transformerHandleA, highSideTerminalID, fuseHandleA); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new AssociationDescription(AssociationType.JunctionJunctionConnectivity, transformerHandleB, highSideTerminalID, fuseHandleB); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new AssociationDescription(AssociationType.JunctionJunctionConnectivity, transformerHandleC, highSideTerminalID, fuseHandleC); createOperation.Create(connectivityAssociationDescription); // Create three arresters, one for each phase MapPoint arresterPointA = CreateOffsetMapPoint(clickPoint, -1 * XOffset, 3 * YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(arresterAssetGroup, arresterAssetType, arresterPointA, APhase)); RowHandle arresterHandleA = new RowHandle(token); MapPoint arresterPointB = CreateOffsetMapPoint(clickPoint, 0, 3 * YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(arresterAssetGroup, arresterAssetType, arresterPointB, BPhase)); RowHandle arresterHandleB = new RowHandle(token); MapPoint arresterPointC = CreateOffsetMapPoint(clickPoint, XOffset, 3 * YOffset); token = createOperation.CreateEx(deviceFeatureClass, CreateDeviceAttributes(arresterAssetGroup, arresterAssetType, arresterPointC, CPhase)); RowHandle arresterHandleC = new RowHandle(token); // Create containment associations between the bank and the arresters containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, arresterHandleA, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, arresterHandleB, false); createOperation.Create(containmentAssociationDescription); containmentAssociationDescription = new AssociationDescription(AssociationType.Containment, transformerBankHandle, arresterHandleC, false); createOperation.Create(containmentAssociationDescription); // Create connectivity associations between the fuses and the arresters (connect the A-phase fuse the A-phase arrester, and so on) connectivityAssociationDescription = new AssociationDescription(AssociationType.JunctionJunctionConnectivity, fuseHandleA, arresterHandleA); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new AssociationDescription(AssociationType.JunctionJunctionConnectivity, fuseHandleB, arresterHandleB); createOperation.Create(connectivityAssociationDescription); connectivityAssociationDescription = new AssociationDescription(AssociationType.JunctionJunctionConnectivity, fuseHandleC, arresterHandleC); createOperation.Create(connectivityAssociationDescription); // Execute the edit operation, which creates all of the rows and associations success = createOperation.Execute(); if (!success) { errorMessage = createOperation.ErrorMessage; } } } } } }); if (!success) { MessageBox.Show(errorMessage, "Create Transformer Bank Tool"); } return(success); }
/// <summary> /// Execute the layout on the Diagram /// </summary> /// <param name="diagram"></param> internal void Execute(NetworkDiagram diagram) { _graphModel.Initialize(diagram); var junctions = _graphModel.Junctions; if (!junctions.Any()) { return; } int maxColorCount = 12; var containerIDs = new HashSet <int>(); UtilityNetwork un = diagram.DiagramManager?.GetNetwork <UtilityNetwork>(); IReadOnlyList <NetworkSource> theSources = un.GetDefinition().GetNetworkSources(); if (!_graphModel.Containers.Any() || !_graphModel.Edges.Any()) { return; } Dictionary <int, Dictionary <int, Dictionary <string, string> > > attributesBySourceID = new Dictionary <int, Dictionary <int, Dictionary <string, string> > >(); foreach (var jsonContainer in _graphModel.Containers) { int sourceID = jsonContainer.Element.AssociatedSourceID; if (sourceID != 9) // Communications Device source ID { continue; } if (!attributesBySourceID.TryGetValue(sourceID, out Dictionary <int, Dictionary <string, string> > AttributesByEID)) { AttributesByEID = FillSources(Diagram: diagram, theSources: theSources, SourceID: sourceID); attributesBySourceID.Add(sourceID, AttributesByEID); } if (AttributesByEID.TryGetValue(jsonContainer.ID, out Dictionary <string, string> IdProperties)) { jsonContainer.AssetGroup = IdProperties["Asset group"]; jsonContainer.AssetType = IdProperties["Asset type"]; } } foreach (var jsonEdge in _graphModel.Edges) { int sourceID = jsonEdge.Element.AssociatedSourceID; if (sourceID != 15) // Communications Edge Object source ID { continue; } if (!attributesBySourceID.TryGetValue(sourceID, out Dictionary <int, Dictionary <string, string> > AttributesByEID)) { AttributesByEID = FillSources(Diagram: diagram, theSources: theSources, SourceID: sourceID, IsEdge: true); attributesBySourceID.Add(sourceID, AttributesByEID); } if (AttributesByEID.TryGetValue(jsonEdge.ID, out Dictionary <string, string> IdProperties)) { string assetGroup = IdProperties["Asset group"]; string assetType = IdProperties["Asset type"]; if (assetGroup != "Strand" || assetType != "Fiber") { continue; } string groupColor = IdProperties["Strand Group Color"].ToString(); string color = IdProperties["Strand Color"].ToString(); int groupColorRank = GetColorRank(groupColor); int colorRank = GetColorRank(color); if (groupColorRank < 0 || colorRank < 0) { continue; } int rank = maxColorCount * groupColorRank + colorRank; int fromID = jsonEdge.Element.FromID; int toID = jsonEdge.Element.ToID; int fromContainerID = 0; int toContainerID = 0; var fromJunction = _graphModel.GetJunction(fromID); fromJunction.Rank = rank; fromContainerID = fromJunction.Element.ContainerID; if (fromContainerID > 0) { containerIDs.Add(fromContainerID); } var toJunction = _graphModel.GetJunction(toID); toJunction.Rank = rank; toContainerID = toJunction.Element.ContainerID; if (toContainerID > 0) { containerIDs.Add(toContainerID); } if (fromContainerID > 0 && toContainerID > 0) { var fromContainer = _graphModel.GetContainer(fromContainerID); fromContainer.ToContainers.Add(toContainerID); fromContainer.HasOutputFibers = true; var toContainer = _graphModel.GetContainer(toContainerID); toContainer.FromContainers.Add(fromContainerID); toContainer.HasInputFibers = true; if (fromJunction.Rank < toContainer.FromJunctionRankMin) { toContainer.FromJunctionRankMin = fromJunction.Rank; } } } } attributesBySourceID = null; foreach (var junction in junctions) { if (junction.Element.ContainerID < 1) { continue; } if (junction.Rank >= 0) { continue; } _graphModel.GetConnectedJunctions(junction.Element.ID, out IList <int> connectedJunctions); int fromRank = -1; int toRank = -1; CustomContainer fromContainer = null; CustomContainer toContainer = null; int count = Math.Min(connectedJunctions.Count, 2); for (int i = 0; i < count; i++) { var connectedJunction = _graphModel.GetJunction(connectedJunctions[i]); var container = _graphModel.GetContainer(connectedJunction.Element.ContainerID); if (container.HasInputFibers) { fromRank = connectedJunction.Rank; fromContainer = container; } else if (container.HasOutputFibers) { toRank = connectedJunction.Rank; toContainer = container; } } if (fromRank >= 0 || toRank >= 0) { junction.Rank = fromRank >= 0 ? fromRank : toRank; var container = _graphModel.GetContainer(junction.Element.ContainerID); containerIDs.Add(container.Element.ID); if (fromContainer != null) { container.FromContainers.Add(fromContainer.Element.ID); fromContainer.ToContainers.Add(container.Element.ID); } if (toContainer != null) { container.ToContainers.Add(toContainer.Element.ID); toContainer.FromContainers.Add(container.Element.ID); if (junction.Rank < toContainer.FromJunctionRankMin) { toContainer.FromJunctionRankMin = junction.Rank; } } } } var diagramInfo = diagram.GetDiagramInfo(); var diagramExtent = diagramInfo.DiagramExtent; double ySpacing = diagramInfo.ContainerMargin; double xSpacingMin = diagramInfo.ContainerMargin * 15; var startContainers = new List <CustomContainer>(); foreach (var containerID in containerIDs) { var container = _graphModel.GetContainer(containerID); if (!(container is null) && (container.FromContainers.Count > 0 || container.ToContainers.Count < 1)) { continue; } if (container.Element is null) { continue; } var parent = _graphModel.GetContainer(container.Element.ContainerID); if (parent == null) { continue; } if (parent.AssetType != "Hub Terminator" && parent.AssetType != "Mid Cable Splice Enclosure") { continue; } startContainers.Add(container); } double startY = diagramExtent.YMax; foreach (var startContainer in startContainers) { if (startContainer.FromContainerOrder != Int32.MaxValue) { continue; } var toContainerIDs = new HashSet <int>(); foreach (var toContainerID in startContainer.ToContainers) { toContainerIDs.Add(toContainerID); } double startX = diagramExtent.XMin; startContainer.X = startX; startContainer.Y = startY; while (toContainerIDs.Count > 0) { double y = startY; bool first = true; var toContainers = new List <CustomContainer>(); foreach (var containerID in toContainerIDs) { var toContainer = _graphModel.GetContainer(containerID); if (startContainer.FromContainerOrder == Int32.MaxValue) { toContainers.Add(toContainer); } } var sortedContainers = toContainers.OrderBy(cntr => cntr.FromContainerOrder + 0.001 * cntr.FromJunctionRankMin); int vertivalOrder = 0; foreach (var container in sortedContainers) { int containerID = container.Element.ID; container.Y = y; y -= (_graphModel.GetContainedElements(containerID).Count() * ySpacing + 7 * diagramInfo.ContainerMargin); if (first) { first = false; container.X = startX + xSpacingMin; startX = container.X; } else { container.X = startX; } foreach (var toContainerID in container.ToContainers) { var toContainer = _graphModel.GetContainer(toContainerID); if (toContainer.FromContainerOrder == Int32.MaxValue) { toContainer.FromContainerOrder = vertivalOrder; toContainerIDs.Add(toContainerID); } } vertivalOrder++; toContainerIDs.Remove(containerID); } } startY -= (_graphModel.GetContainedElements(startContainer.Element.ID).Count() * ySpacing + 4 * diagramInfo.ContainerMargin); } IList <DiagramJunctionElement> junctionsToSave = new List <DiagramJunctionElement>(); SpatialReference spatialRef = diagramInfo.DiagramExtent.SpatialReference; MapPointBuilder mapPointBuilder = new MapPointBuilder(spatialRef) { Z = 0 }; foreach (var containerID in containerIDs) { var container = _graphModel.GetContainer(containerID); if (container == null) { continue; } int rankCount = maxColorCount * maxColorCount; BitArray isEmpty = new BitArray(rankCount, true); double yTop = container.Y; var containedJunctions = _graphModel.GetContainedElements(containerID); var unconnectedJunctions = new Stack <int>(); foreach (var junctionID in containedJunctions) { var junction = _graphModel.GetJunction(junctionID); if (junction == null) { continue; } if (junction.Rank < 0) { unconnectedJunctions.Push(junction.Element.ID); continue; } isEmpty[junction.Rank] = false; mapPointBuilder.X = container.X; mapPointBuilder.Y = yTop - junction.Rank * ySpacing; junction.Element.Shape = mapPointBuilder.ToGeometry(); junctionsToSave.Add(junction.Element); } int rank = 0; while (unconnectedJunctions.Count > 0 && rank < rankCount) { if (isEmpty[rank]) { var junction = _graphModel.GetJunction(unconnectedJunctions.Pop()); if (junction != null) { mapPointBuilder.X = container.X; mapPointBuilder.Y = yTop - rank * ySpacing; junction.Element.Shape = mapPointBuilder.ToGeometry(); junctionsToSave.Add(junction.Element); } } rank++; } } if (junctionsToSave.Count > 0) { NetworkDiagramSubset nds = new NetworkDiagramSubset { DiagramJunctionElements = junctionsToSave }; diagram.SaveLayout(nds, true); } }