Closest Facility Online

This sample demonstrates how to solve the routing problem of finding the closest facility among multiple incidents (i.e. target points to go to). Barriers in the form of points, lines, and polygons, can be placed across the line network to provide alternative optimal routes. A variety of input parameters to modify the routing problem can be adjusted. This is a fairly complex sample that has extensive use of XAML and code-behind to demonstrate the closet facility problem. Some of the main classes used in the sample are SimpleMarkerSymbol.ControlTemplate, Storyboard animation, Editor, GraphicsLayer, RouteTask, RouteClosesFacilityParameters and RouteResult.

To use this sample, click on a button to add facilities, barriers, and incidents. Modify input properties to define closest facility parameters. Click the Solve button to generate results and display them in the map. Hover over route results to see incident and facility ids and travel time.

Download Sample Application
XAML C# VB.NET
<UserControl x:Class="ArcGISWPFSDK.ClosestFacility"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:esri="http://schemas.esri.com/arcgis/client/2009">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.Resources>

            <esri:SimpleMarkerSymbol x:Key="MyFacilitiesSymbol" Style="Square">
                <esri:SimpleMarkerSymbol.ControlTemplate>
                    <ControlTemplate>
                        <Grid>
                            <Rectangle RenderTransformOrigin="0.5,0.5" Fill="LightBlue" 
                        Width="20" Height="20" Stroke="Black" StrokeThickness="1" />
                            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
                        Text="{Binding Attributes[FacilityNumber]}"
                        FontSize="9" Margin="0" FontWeight="Bold" Foreground="Black" />
                        </Grid>
                    </ControlTemplate>
                </esri:SimpleMarkerSymbol.ControlTemplate>
            </esri:SimpleMarkerSymbol>

            <esri:SimpleMarkerSymbol x:Key="MyIncidentsSymbol" Size="20" Style="Circle" Color="LightGreen">
                <esri:SimpleMarkerSymbol.ControlTemplate>
                    <ControlTemplate>
                        <Grid>
                            <Ellipse Fill="{Binding Symbol.Color}" Width="{Binding Symbol.Size}" Height="{Binding Symbol.Size}" 
                    Stroke="Black" StrokeThickness="1" />
                            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
                    Text="{Binding Path=Attributes[IncidentNumber]}"
                    FontSize="9" Margin="0" FontWeight="Bold" Foreground="Black" />
                        </Grid>
                    </ControlTemplate>
                </esri:SimpleMarkerSymbol.ControlTemplate>
            </esri:SimpleMarkerSymbol>

            <esri:SimpleMarkerSymbol x:Key="BarrierMarkerSymbol" Color="Red" Size="12" Style="Circle" />
            <esri:SimpleLineSymbol x:Key="BarrierLineSymbol" Color="Red" Width="2" Style="Solid" />
            <esri:SimpleFillSymbol x:Key="BarrierFillSymbol" Fill="#44FF0000" BorderBrush="#99000000" BorderThickness="1" />

            <esri:SimpleRenderer x:Key="RouteRenderer">
                <esri:SimpleRenderer.Symbol>
                    <esri:LineSymbol>
                        <esri:LineSymbol.ControlTemplate>
                            <ControlTemplate>
                                <Grid>
                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup x:Name="CommonStates">
                                            <VisualState x:Name="Normal">
                                                <Storyboard RepeatBehavior="Forever">
                                                    <DoubleAnimation BeginTime="0:0:0" Storyboard.TargetName="Element" 
                                                                                 Storyboard.TargetProperty="StrokeDashOffset" 
                                                                                 To="1000" Duration="0:3:0" />
                                                </Storyboard>
                                            </VisualState>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>
                                    <!--For polyline and polygon template, a Path 
                                                    element with the name "Element" is required-->
                                    <Path x:Name="Element" StrokeDashArray="2,1" StrokeDashOffset="0"
                                                     Stroke="Green" StrokeThickness="5" />
                                </Grid>
                            </ControlTemplate>
                        </esri:LineSymbol.ControlTemplate>
                    </esri:LineSymbol>
                </esri:SimpleRenderer.Symbol>
            </esri:SimpleRenderer>

            <esri:Editor x:Key="MyBarriersEditor" LayerIDs="MyBarriersGraphicsLayer"/>
            <esri:Editor x:Key="MyFacilitiesEditor" LayerIDs="MyFacilitiesGraphicsLayer"                        
                         SelectionMode="Point" ContinuousMode="True" 
                         EditCompleted="Editor_EditCompleted" />
            <esri:Editor x:Key="MyIncidentsEditor" LayerIDs="MyIncidentsGraphicsLayer"                        
                         SelectionMode="Point" ContinuousMode="True" 
                         EditCompleted="Editor_EditCompleted" />
            <LinearGradientBrush x:Key="PanelGradient" EndPoint="0.5,1" StartPoint="0.5,0">
                <LinearGradientBrush.RelativeTransform>
                    <TransformGroup>
                        <ScaleTransform CenterY="0.5" CenterX="0.5"/>
                        <SkewTransform CenterY="0.5" CenterX="0.5"/>
                        <RotateTransform Angle="176" CenterY="0.5" CenterX="0.5"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </LinearGradientBrush.RelativeTransform>
                <GradientStop Color="#FF145787" Offset="0.16"/>
                <GradientStop Color="#FF3D7FAC" Offset="0.502"/>
                <GradientStop Color="#FF88C5EF" Offset="0.984"/>
            </LinearGradientBrush>

        </Grid.Resources>

        <esri:Map x:Name="MyMap" Background="White" Extent="-117.23,34.03,-117.16,34.08" Loaded="MyMap_Loaded">
            <esri:Map.Layers>
                <esri:ArcGISTiledMapServiceLayer
                      Url="http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
                <esri:GraphicsLayer ID="MyRoutesGraphicsLayer" Renderer="{StaticResource RouteRenderer}" >
                    <esri:GraphicsLayer.MapTip>
                        <Border CornerRadius="10" Background="#DDFFEEEE" BorderThickness="5" BorderBrush="#7700FF00">
                            <StackPanel Orientation="Vertical" HorizontalAlignment="Center" Margin="10">
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="From Incident " FontWeight="Bold" Foreground="#FF0F274E" FontSize="10" VerticalAlignment="Center"/>
                                    <TextBlock Text="{Binding [IncidentID]}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="#FF0F274E"/>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="To Facility " FontWeight="Bold" Foreground="#FF0F274E" FontSize="10" VerticalAlignment="Center"/>
                                    <TextBlock Text="{Binding [FacilityID]}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="#FF0F274E"/>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="Total Time (mins): " FontWeight="Bold" Foreground="#FF0F274E" FontSize="10" VerticalAlignment="Center" />
                                    <TextBlock Text="{Binding [Total_Time], StringFormat=\{0:F\}}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="#FF0F274E"/>
                                </StackPanel>
                            </StackPanel>
                        </Border>
                    </esri:GraphicsLayer.MapTip>
                </esri:GraphicsLayer>
                <esri:GraphicsLayer ID="MyIncidentsGraphicsLayer" />
                <esri:GraphicsLayer ID="MyBarriersGraphicsLayer" />
                <esri:GraphicsLayer ID="MyFacilitiesGraphicsLayer" />
            </esri:Map.Layers>
        </esri:Map>

        <Border Background="{StaticResource PanelGradient}" BorderThickness="1" CornerRadius="5"
                HorizontalAlignment="Right"  VerticalAlignment="Top"
                Margin="20,20,20,30" Padding="10" BorderBrush="Black">
            <Border.Effect>
                <DropShadowEffect/>
            </Border.Effect>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition MinHeight="40"/>
                    <RowDefinition MinHeight="25"/>
                    <RowDefinition MinHeight="100"/>
                </Grid.RowDefinitions>
                <Grid Margin="5" Grid.Row="0">
                    <TextBlock x:Name="ResponseTextBlock" Text="Click on a button to add facilities, barriers, and incidents.  Modify input properties to define closest facility parameters.  Click the Solve button to generate results and display them in the map.  Hover over route results to see incident and facility ids and travel time." 
                       Width="400" Foreground="White" TextAlignment="Left" Margin="0,0,0,5" TextWrapping="Wrap" />
                </Grid>
                <Grid Margin="0" Grid.Row="1" >
                    <StackPanel Orientation="Horizontal" Margin="0">

                        <Button Content="Add Facilities" x:Name="FacilitiesRadioButton" 
                            Foreground="Black" VerticalAlignment="Center" Margin="0,0,5,0"
                            DataContext="{StaticResource MyFacilitiesEditor}"
                            Command="{Binding Add}" CommandParameter="{StaticResource MyFacilitiesSymbol}" 
                                />

                        <Button Content="Add Incidents" x:Name="IncidentsRadioButton"  
                            Foreground="Black" VerticalAlignment="Center" Margin="0,0,5,0" 
                            DataContext="{StaticResource MyIncidentsEditor}"
                            Command="{Binding Add}" CommandParameter="{StaticResource MyIncidentsSymbol}"
                            />

                        <Button x:Name="SolveButton" HorizontalAlignment="Center" VerticalAlignment="Center" 
                            Width="120" Height="40" Click="SolveButton_Click" Content="Solve" IsEnabled="False"  
                            FontSize="14" FontWeight="Bold" Margin="10,0,0,0" />
                    </StackPanel>
                </Grid>

                <StackPanel Orientation="Vertical" Grid.Row="2" Margin="0,0,0,5">
                    <TextBlock Text="Add Barriers:" Foreground="White" VerticalAlignment="Center" Margin="0,0,5,0" />
                    <StackPanel x:Name="BarrierToolsStackPanel" Orientation="Horizontal" 
                                DataContext="{StaticResource MyBarriersEditor}" 
                                Margin="5,0,5,5">
                        <Button x:Name="AddPointButton" Margin="2" 
                                        Content="Point" 
                                        Command="{Binding Add}" 
                                        CommandParameter="{StaticResource BarrierMarkerSymbol}" />
                        <Button x:Name="AddLineButton" Margin="2" 
                                        Content="Line" 
                                        Command="{Binding Add}" 
                                        CommandParameter="{StaticResource BarrierLineSymbol}" />
                        <Button x:Name="AddPolygonButton" Margin="2" 
                                        Content="Polygon"
                                        Command="{Binding Add}"
                                        CommandParameter="{StaticResource BarrierFillSymbol}" />
                    </StackPanel>
                    <Button Content="Clear All Graphics" Click="ClearButton_Click" 
                                    Margin="2,2,0,2" HorizontalAlignment="Left" Width="160" />
                </StackPanel>

                <Border BorderBrush="White" Grid.Row="3" BorderThickness="1" CornerRadius="3" >
                    <ScrollViewer MinHeight="100" BorderThickness="0">
                        <Grid Background="Transparent" Width="328" Margin="12" VerticalAlignment="Center">
                            <Grid.Resources>
                                <Style TargetType="TextBlock">
                                    <Setter Property="Foreground" Value="White"/>
                                    <Setter Property="VerticalAlignment" Value="Center" />
                                </Style>
                                <Style TargetType="CheckBox">
                                    <Setter Property="Foreground" Value="White" />
                                </Style>
                            </Grid.Resources>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="200" />
                                <ColumnDefinition Width="125" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <TextBlock Text="Travel Direction:" Grid.Row="0" Grid.Column="0" />

                            <ComboBox x:Name="TravelDirection2" Grid.Row="0" Grid.Column="1">
                                <ComboBoxItem Content="From Facility" />
                                <ComboBoxItem Content="To Facility" IsSelected="True"/>
                            </ComboBox>

                            <TextBlock Text="Default Cutoff:" Grid.Row="1" Grid.Column="0" />
                            <TextBox x:Name="DefaultCutoff2" Text="10" Grid.Row="1" Grid.Column="1" />

                            <TextBlock Text="Default Target Facility Count:" Grid.Row="2" Grid.Column="0" />
                            <TextBox x:Name="DefaultTargetFacilityCount2" Text="1" Grid.Row="2" Grid.Column="1" />

                            <TextBlock Text="Output Spatial Reference:" Grid.Row="3" Grid.Column="0" />
                            <TextBox x:Name="OutputSpatialReference2" Text="4326" Grid.Row="3" Grid.Column="1" />

                            <TextBlock Text="Accumulate Attribute Names:" Grid.Row="4" Grid.Column="0" />
                            <TextBox x:Name="AccumulateAttributeNames2" Grid.Row="4" Grid.Column="1" />

                            <TextBlock Text="Impedance Attribute Name:" Grid.Row="5" Grid.Column="0" />
                            <TextBox x:Name="ImpedanceAttributeName2" Text="Time" Grid.Row="5" Grid.Column="1" />

                            <TextBlock Text="Restriction Attribute Names:" Grid.Row="6" Grid.Column="0" />
                            <TextBox x:Name="RestrictionAttributeNames2" Text="OneWay,TurnRestriction,Avoid passenger ferries,Non-routeable segments" 
                                        Grid.Row="6" Grid.Column="1" />

                            <TextBlock Text="Attribute Parameter Value:" Grid.Row="7" Grid.Column="0" />
                            <ComboBox x:Name="AttributeParameter2" Grid.Row="7" Grid.Column="1">
                                <ComboBoxItem Content="None" IsSelected="True" />
                                <ComboBoxItem Content="15 MPH" />
                                <ComboBoxItem Content="20 MPH" />
                                <ComboBoxItem Content="25 MPH" />
                                <ComboBoxItem Content="35 MPH" />
                                <ComboBoxItem Content="45 MPH" />
                                <ComboBoxItem Content="50 MPH" />
                                <ComboBoxItem Content="55 MPH" />
                                <ComboBoxItem Content="65 MPH" />
                                <ComboBoxItem Content="Other Roads" />
                            </ComboBox>

                            <TextBlock Text="Restrict U-Turns:" Grid.Row="8" Grid.Column="0" />
                            <ComboBox x:Name="RestrictUTurns2" Grid.Row="8" Grid.Column="1">
                                <ComboBoxItem Content="Allow Backtrack" IsSelected="True" />
                                <ComboBoxItem Content="At Dead Ends Only" />
                                <ComboBoxItem Content="No Backtrack" />
                            </ComboBox>

                            <CheckBox x:Name="UseHierarchy2" Grid.Row="9" Grid.ColumnSpan="2" 
                                              Content="Use Hierarchy" IsChecked="True"/>
                            <CheckBox x:Name="ReturnDirections2" Grid.Row="10" Grid.ColumnSpan="2" 
                                              Content="Return Directions" IsChecked="True"/>
                            <CheckBox x:Name="ReturnRoutes2" Grid.Row="11" Grid.ColumnSpan="2" 
                                              Content="Return Routes" IsChecked="True"/>
                            <CheckBox x:Name="ReturnFacilities2" Grid.Row="12" Grid.ColumnSpan="2" 
                                              Content="Return Facilities" />
                            <CheckBox x:Name="ReturnIncidents2" Grid.Row="13" Grid.ColumnSpan="2" 
                                              Content="Return Incidents" />
                            <CheckBox x:Name="ReturnBarriers2" Grid.Row="14" Grid.ColumnSpan="2" 
                                              Content="Return Barriers"    />
                            <CheckBox x:Name="ReturnPolylineBarriers2" Grid.Row="15" Grid.ColumnSpan="2" 
                                        Content="Return Polyline Barriers" />
                            <CheckBox x:Name="ReturnPolygonBarriers2" Grid.Row="16" Grid.ColumnSpan="2" 
                                        Content="Return Polygon Barriers" />

                            <TextBlock Text="Directions Language:" Grid.Row="17" Grid.Column="0" />
                            <TextBox x:Name="DirectionsLanguage2" Text="en-US" Grid.Row="17" Grid.Column="1" />
                            <TextBlock Text="Output Lines:" Grid.Row="18" Grid.Column="0" />
                            <ComboBox x:Name="OutputLines2" Grid.Row="18" Grid.Column="1">
                                <ComboBoxItem Content="None" />
                                <ComboBoxItem Content="Straight" />
                                <ComboBoxItem Content="True Shape" IsSelected="True" />
                            </ComboBox>
                            <TextBlock Text="Output Geometry Precision:" Grid.Row="19" Grid.Column="0" />
                            <TextBox x:Name="OutputGeometryPrecision2" Grid.Row="19" Grid.Column="1" />
                            <TextBlock Text="Output Geometry Precision Units:" Grid.Row="20" Grid.Column="0" />
                            <ComboBox x:Name="OutputGeometryPrecisionUnits2" Grid.Row="20" Grid.Column="1">
                                <ComboBoxItem Content="Unknown" IsSelected="True" />
                                <ComboBoxItem Content="Decimal Degrees" />
                                <ComboBoxItem Content="Kilometers" />
                                <ComboBoxItem Content="Meters" />
                                <ComboBoxItem Content="Miles" />
                                <ComboBoxItem Content="Nautical Miles" />
                                <ComboBoxItem Content="Inches" />
                                <ComboBoxItem Content="Points" />
                                <ComboBoxItem Content="Feet" />
                                <ComboBoxItem Content="Yards" />
                                <ComboBoxItem Content="Millimeters" />
                                <ComboBoxItem Content="Centimeters" />
                                <ComboBoxItem Content="Decimeters" />
                            </ComboBox>

                            <TextBlock Text="Directions Time Attribute Name:" Grid.Row="21" Grid.Column="0" />
                            <TextBox x:Name="DirectionsTimeAttributeName2" Text="Time" Grid.Row="21" Grid.Column="1" />
                            <TextBlock Text="Directions Length Units:" Grid.Row="22" Grid.Column="0" />
                            <ComboBox x:Name="DirectionsLengthUnits2" Grid.Row="22" Grid.Column="1">
                                <ComboBoxItem Content="Unknown" />
                                <ComboBoxItem Content="Kilometers" />
                                <ComboBoxItem Content="Meters" />
                                <ComboBoxItem Content="Miles" IsSelected="True" />
                                <ComboBoxItem Content="Nautical Miles" />
                            </ComboBox>
                        </Grid>
                    </ScrollViewer>
                </Border>

            </Grid>

        </Border>

    </Grid>

</UserControl>

Sample code usage restrictions
5/16/2014