Skip to content

Commit 1c0f372

Browse files
authored
Perform valve isolation trace: Add filter barriers (#929)
1 parent 99a56b8 commit 1c0f372

File tree

20 files changed

+863
-245
lines changed

20 files changed

+863
-245
lines changed
21.9 KB
Loading
Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,79 @@
1-
<ContentPage
2-
x:Class="ArcGISRuntimeXamarin.Samples.PerformValveIsolationTrace.PerformValveIsolationTrace"
3-
xmlns="http://xamarin.com/schemas/2014/forms"
4-
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
5-
xmlns:esriUI="clr-namespace:Esri.ArcGISRuntime.Xamarin.Forms;assembly=Esri.ArcGISRuntime.Xamarin.Forms"
6-
xmlns:resources="clr-namespace:Forms.Resources;assembly=ArcGISRuntime">
1+
<ContentPage x:Class="ArcGISRuntimeXamarin.Samples.PerformValveIsolationTrace.PerformValveIsolationTrace"
2+
xmlns="http://xamarin.com/schemas/2014/forms"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
xmlns:esriUI="clr-namespace:Esri.ArcGISRuntime.Xamarin.Forms;assembly=Esri.ArcGISRuntime.Xamarin.Forms"
5+
xmlns:resources="clr-namespace:Forms.Resources;assembly=ArcGISRuntime">
76
<RelativeLayout>
8-
<esriUI:MapView
9-
x:Name="MyMapView"
10-
BindingContext="{x:Reference Name=ResponsiveFormContainer}"
11-
Style="{StaticResource MapWithFormStyle}" />
7+
<esriUI:MapView x:Name="MyMapView"
8+
BindingContext="{x:Reference Name=ResponsiveFormContainer}"
9+
GeoViewTapped="OnGeoViewTapped"
10+
Style="{StaticResource MapWithFormStyle}" />
1211
<resources:ResponsiveFormContainer x:Name="ResponsiveFormContainer">
1312
<StackLayout x:Name="FilterOptions" Orientation="Vertical">
14-
<Label
15-
Margin="5"
16-
FontAttributes="Bold"
17-
Text="Choose Category for Filter Barrier:" />
13+
<Label Margin="5"
14+
FontAttributes="Bold"
15+
Text="Choose Category for Filter Barrier:" />
1816
<Grid>
1917
<Grid.ColumnDefinitions>
2018
<ColumnDefinition Width="*" />
2119
<ColumnDefinition Width="auto" />
20+
<ColumnDefinition Width="auto" />
2221
</Grid.ColumnDefinitions>
23-
<Picker
24-
x:Name="CategoryPicker"
25-
Grid.Column="0"
26-
Margin="5"
27-
ItemDisplayBinding="{Binding Name}"
28-
TextColor="Black"
29-
VerticalOptions="CenterAndExpand" />
30-
<Button
31-
Grid.Column="1"
32-
Margin="5"
33-
Clicked="OnTrace"
34-
Text="Trace" />
22+
<Picker x:Name="CategoryPicker"
23+
Grid.Column="0"
24+
Margin="5"
25+
ItemDisplayBinding="{Binding Name}"
26+
TextColor="Black"
27+
VerticalOptions="CenterAndExpand" />
28+
<Button Grid.Column="1"
29+
Margin="5"
30+
Clicked="OnTrace"
31+
Text="Trace" />
32+
<Button Grid.Column="2"
33+
Margin="5"
34+
Clicked="OnReset"
35+
Text="Reset" />
3536
</Grid>
3637
<StackLayout Orientation="Horizontal">
37-
<Switch
38-
x:Name="IncludeIsolatedFeatures"
39-
Margin="5"
40-
IsToggled="False" />
4138
<Label Text="Include Isolated Features" VerticalOptions="Center" />
39+
<Switch x:Name="IncludeIsolatedFeatures"
40+
Margin="5"
41+
IsToggled="False" />
4242
</StackLayout>
4343
</StackLayout>
4444
</resources:ResponsiveFormContainer>
45-
<ActivityIndicator
46-
x:Name="LoadingIndicator"
47-
HorizontalOptions="CenterAndExpand"
48-
IsRunning="True"
49-
IsVisible="True"
50-
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,
51-
Property=Height,
52-
Factor=1}"
53-
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
54-
Property=Width,
55-
Factor=1}"
56-
VerticalOptions="CenterAndExpand" />
45+
<ActivityIndicator x:Name="LoadingIndicator"
46+
HorizontalOptions="CenterAndExpand"
47+
IsRunning="True"
48+
IsVisible="True"
49+
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,
50+
Property=Height,
51+
Factor=1}"
52+
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
53+
Property=Width,
54+
Factor=1}"
55+
VerticalOptions="CenterAndExpand" />
56+
<Grid x:Name="PickerUI"
57+
HorizontalOptions="CenterAndExpand"
58+
IsVisible="False"
59+
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,
60+
Property=Height,
61+
Factor=1}"
62+
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
63+
Property=Width,
64+
Factor=1}"
65+
VerticalOptions="CenterAndExpand">
66+
<Grid.RowDefinitions>
67+
<RowDefinition Height="auto" />
68+
<RowDefinition Height="*" />
69+
</Grid.RowDefinitions>
70+
<Label Grid.Row="0"
71+
Margin="5"
72+
HorizontalTextAlignment="Center"
73+
Text="Choose a terminal for this junction." />
74+
<ListView x:Name="TerminalPicker"
75+
Grid.Row="1"
76+
ItemSelected="Terminal_Selected" />
77+
</Grid>
5778
</RelativeLayout>
58-
</ContentPage>
79+
</ContentPage>

src/Forms/Shared/Samples/Utility network/PerformValveIsolationTrace/PerformValveIsolationTrace.xaml.cs

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020 Esri.
1+
// Copyright 2021 Esri.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
44
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
@@ -13,10 +13,12 @@
1313
using Esri.ArcGISRuntime.Security;
1414
using Esri.ArcGISRuntime.Symbology;
1515
using Esri.ArcGISRuntime.UI;
16+
using Esri.ArcGISRuntime.UI.Controls;
1617
using Esri.ArcGISRuntime.UtilityNetworks;
1718
using System;
1819
using System.Collections.Generic;
1920
using System.Linq;
21+
using System.Threading.Tasks;
2022
using Xamarin.Forms;
2123

2224
namespace ArcGISRuntimeXamarin.Samples.PerformValveIsolationTrace
@@ -25,8 +27,8 @@ namespace ArcGISRuntimeXamarin.Samples.PerformValveIsolationTrace
2527
name: "Perform valve isolation trace",
2628
category: "Utility network",
2729
description: "Run a filtered trace to locate operable features that will isolate an area from the flow of network resources.",
28-
instructions: "Create and set the configuration's filter barriers by selecting a category. Check or uncheck 'Include Isolated Features'. Tap 'Trace' to run a subnetwork-based isolation trace.",
29-
tags: new[] { "category comparison", "condition barriers", "isolated features", "network analysis", "subnetwork trace", "trace configuration", "trace filter", "utility network" })]
30+
instructions: "Tap on one or more features to use as filter barriers or create and set the configuration's filter barriers by selecting a category. Check or uncheck 'Include Isolated Features'. Tap 'Trace' to run a subnetwork-based isolation trace. Tap 'Reset' to clear filter barriers.",
31+
tags: new[] { "category comparison", "condition barriers", "filter barriers", "isolated features", "network analysis", "subnetwork trace", "trace configuration", "trace filter", "utility network" })]
3032
public partial class PerformValveIsolationTrace : ContentPage
3133
{
3234
// Feature service for an electric utility network in Naperville, Illinois.
@@ -47,6 +49,12 @@ public partial class PerformValveIsolationTrace : ContentPage
4749
private const string GlobalId = "{98A06E95-70BE-43E7-91B7-E34C9D3CB9FF}";
4850
private UtilityElement _startingLocation;
4951

52+
private UtilityTraceParameters _parameters;
53+
private GraphicsOverlay _barrierOverlay;
54+
55+
// Task completion source for the user selected terminal.
56+
private TaskCompletionSource<string> _terminalCompletionSource = null;
57+
5058
public PerformValveIsolationTrace()
5159
{
5260
InitializeComponent();
@@ -112,6 +120,13 @@ private async void Initialize()
112120
Graphic graphic = new Graphic(startingLocationGeometry, symbol);
113121
overlay.Graphics.Add(graphic);
114122

123+
// Create a graphics overlay for barriers.
124+
_barrierOverlay = new GraphicsOverlay();
125+
MyMapView.GraphicsOverlays.Add(_barrierOverlay);
126+
127+
// Create the utility trace parameters.
128+
_parameters = new UtilityTraceParameters(UtilityTraceType.Isolation, new[] { _startingLocation });
129+
115130
// Set the starting viewpoint.
116131
await MyMapView.SetViewpointAsync(new Viewpoint(startingLocationGeometry, 3000));
117132

@@ -148,7 +163,7 @@ private async void OnTrace(object sender, EventArgs e)
148163
UtilityCategoryComparison categoryComparison = new UtilityCategoryComparison(category, UtilityCategoryComparisonOperator.Exists);
149164

150165
// Add the filter barrier.
151-
_configuration.Filter.Barriers = categoryComparison;
166+
_configuration.Filter = new UtilityTraceFilter() { Barriers = categoryComparison };
152167
}
153168

154169
// Set the include isolated features property.
@@ -182,5 +197,103 @@ private async void OnTrace(object sender, EventArgs e)
182197
LoadingIndicator.IsVisible = false;
183198
}
184199
}
200+
201+
private void OnReset(object sender, EventArgs e)
202+
{
203+
_parameters.Barriers.Clear();
204+
_barrierOverlay.Graphics.Clear();
205+
foreach (FeatureLayer layer in MyMapView.Map.OperationalLayers.OfType<FeatureLayer>())
206+
{
207+
layer.ClearSelection();
208+
}
209+
}
210+
211+
private async Task<UtilityTerminal> GetTerminalAsync(IEnumerable<UtilityTerminal> terminals)
212+
{
213+
try
214+
{
215+
// Switch the UI for the user choosing the junction.
216+
PickerUI.IsVisible = true;
217+
MyMapView.GeoViewTapped -= OnGeoViewTapped;
218+
219+
// Load the terminals into the UI.
220+
TerminalPicker.ItemsSource = terminals.Select(x => x.Name).ToList();
221+
TerminalPicker.SelectedItem = null;
222+
223+
// Wait for the user to select a terminal.
224+
_terminalCompletionSource = new TaskCompletionSource<string>();
225+
string selectedName = await _terminalCompletionSource.Task;
226+
return terminals.Where(x => x.Name.Equals(selectedName)).FirstOrDefault();
227+
}
228+
finally
229+
{
230+
// Make the main UI visible again.
231+
PickerUI.IsVisible = false;
232+
MyMapView.GeoViewTapped += OnGeoViewTapped;
233+
}
234+
}
235+
236+
private void Terminal_Selected(object sender, EventArgs e)
237+
{
238+
_terminalCompletionSource.TrySetResult(TerminalPicker.SelectedItem as string);
239+
}
240+
241+
private async void OnGeoViewTapped(object sender, Esri.ArcGISRuntime.Xamarin.Forms.GeoViewInputEventArgs e)
242+
{
243+
try
244+
{
245+
LoadingIndicator.IsVisible = true;
246+
247+
// Identify the feature to be used.
248+
IEnumerable<IdentifyLayerResult> identifyResult = await MyMapView.IdentifyLayersAsync(e.Position, 10.0, false);
249+
ArcGISFeature feature = identifyResult?.FirstOrDefault()?.GeoElements?.FirstOrDefault() as ArcGISFeature;
250+
if (feature == null) { return; }
251+
252+
// Create element from the identified feature.
253+
UtilityElement element = _utilityNetwork.CreateElement(feature);
254+
255+
if (element.NetworkSource.SourceType == UtilityNetworkSourceType.Junction)
256+
{
257+
// Select terminal for junction feature.
258+
IEnumerable<UtilityTerminal> terminals = element.AssetType.TerminalConfiguration?.Terminals;
259+
if (terminals?.Count() > 1)
260+
{
261+
element.Terminal = await GetTerminalAsync(terminals);
262+
}
263+
}
264+
else if (element.NetworkSource.SourceType == UtilityNetworkSourceType.Edge)
265+
{
266+
// Compute how far tapped location is along the edge feature.
267+
if (feature.Geometry is Polyline line)
268+
{
269+
// Remove elevation data, FractionAlong only supports 2D lines.
270+
line = GeometryEngine.RemoveZ(line) as Polyline;
271+
double fraction = GeometryEngine.FractionAlong(line, e.Location, -1);
272+
273+
// Check for rare edge case where the fraction is invalid.
274+
if (double.IsNaN(fraction)) { return; }
275+
276+
// Set the fraction of the utility element.
277+
element.FractionAlongEdge = fraction;
278+
}
279+
}
280+
281+
// Check whether starting location or barrier is added to update the right collection and symbology.
282+
_parameters.Barriers.Add(element);
283+
Symbol symbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, System.Drawing.Color.OrangeRed, 25d);
284+
285+
// Add a graphic for the new utility element.
286+
Graphic traceLocationGraphic = new Graphic(feature.Geometry as MapPoint ?? e.Location, symbol);
287+
_barrierOverlay.Graphics.Add(traceLocationGraphic);
288+
}
289+
catch (Exception ex)
290+
{
291+
await Application.Current.MainPage.DisplayAlert(ex.GetType().Name, ex.Message, "OK");
292+
}
293+
finally
294+
{
295+
LoadingIndicator.IsVisible = false;
296+
}
297+
}
185298
}
186299
}

0 commit comments

Comments
 (0)