Query Demographics
DockWindow.vb
' Copyright 2011 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions.
' 

' Copyright 2010 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions at <your ArcGIS Explorer install location>/DeveloperKit/userestrictions.txt.
' 

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms

Imports ESRI.ArcGISExplorer
Imports ESRI.ArcGISExplorer.Application
Imports ESRI.ArcGISExplorer.Mapping
Imports ESRI.ArcGISExplorer.Geometry
Imports ESRI.ArcGISExplorer.Data
Imports ESRI.ArcGISExplorer.Threading

Public Class DockWindow
    Inherits ESRI.ArcGISExplorer.Application.DockWindow

    Public Sub New()
        InitializeComponent()
    End Sub

    Private _mapDisp As MapDisplay = ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay

    Private Sub txtLocation_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles txtLocation.DragDrop
        'Make sure we have a treenode being dropped
        If Not e.Data.GetDataPresent(GetType(TreeNode)) Then
            Return
        End If

        'From the node, grab the text to display and then save the note for use later
        Dim node As TreeNode = TryCast(DirectCast(e.Data.GetData(GetType(TreeNode)), TreeNode).Clone(), TreeNode)
        txtLocation.Text = node.Text
        txtLocation.Tag = node.Tag
    End Sub

    Private Sub txtLocation_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) Handles txtLocation.DragOver
        e.Effect = DragDropEffects.None

        'make sure that we only allow point data from notes
        Dim node As TreeNode = TryCast(DirectCast(e.Data.GetData(GetType(TreeNode)), TreeNode).Clone(), TreeNode)

        Dim result As ESRI.ArcGISExplorer.Mapping.Note = TryCast(node.Tag, Note)
        If result IsNot Nothing Then
            If result.Graphic.Geometry.[GetType]() Is GetType(ESRI.ArcGISExplorer.Geometry.Point) Then
                e.Effect = DragDropEffects.Move
                Return
            End If
        End If

        Return
    End Sub

    Private Sub btnExecute_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnExecute.Click
        'Make sure we have values in the location and distance boxes.
        If txtDistance.Text = "" OrElse txtLocation.Text = "" Then
            Return
        End If

        'Make sure the value in the distance box is numeric
        If Not IsNumeric(txtDistance.Text) Then
            MessageBox.Show("Distance value must be numeric!!", "Bad Value")
            Return
        End If

        'Make sure distance value is less than 10 miles
        If System.Convert.ToDouble(txtDistance.Text) > 10 Then
            MessageBox.Show("Distance value must be less than 10 miles!!", "Bad Value")
            Return
        End If

        'Get the point geometry out of the tag on the Location textbox
        Dim queryPt As ESRI.ArcGISExplorer.Geometry.Point = Nothing
        If txtLocation.Tag.[GetType]() Is GetType(Note) Then
            Dim result As ESRI.ArcGISExplorer.Mapping.Note = TryCast(txtLocation.Tag, Note)
            queryPt = TryCast(result.Graphic.Geometry, ESRI.ArcGISExplorer.Geometry.Point)
        Else
            queryPt = TryCast(txtLocation.Tag, ESRI.ArcGISExplorer.Geometry.Point)
        End If
        If queryPt Is Nothing Then
            Return
        End If

        'Execute the query against the Demographics data
        QueryDemographics(queryPt, System.Convert.ToDouble(txtDistance.Text))
    End Sub

    Private Sub QueryDemographics(ByVal queryPt As ESRI.ArcGISExplorer.Geometry.Point, ByVal dist As Double)
        'Open up ProgressHelper to show are progress.
        Dim help As ProgressHelper = New ProgressHelper("Query Progress", "Calculating Demographics in the area", "Forming query polygon ...")
        help.Show()


        'Create a square polygon to pass to the service for query purposes based on the location
        Dim pts As New List(Of ESRI.ArcGISExplorer.Geometry.Point)()
    pts.Add(TryCast(GeometryOperations.Move(queryPt, dist, dist, Unit.Linear.MilesStatute), ESRI.ArcGISExplorer.Geometry.Point))
    pts.Add(TryCast(GeometryOperations.Move(queryPt, dist, (dist * -1), Unit.Linear.MilesStatute), ESRI.ArcGISExplorer.Geometry.Point))
    pts.Add(TryCast(GeometryOperations.Move(queryPt, (dist * -1), (dist * -1), Unit.Linear.MilesStatute), ESRI.ArcGISExplorer.Geometry.Point))
    pts.Add(TryCast(GeometryOperations.Move(queryPt, (dist * -1), dist, Unit.Linear.MilesStatute), ESRI.ArcGISExplorer.Geometry.Point))
        Dim searchPoly As New Polygon(pts, queryPt.CoordinateSystem)
        searchPoly.Close()
        searchPoly = GeometryOperations.Project(searchPoly, CoordinateSystem.GeographicCoordinateSystems.NorthAmerica.NAD1983)
        help.UpdateMessage("Executing SOAP call to ArcGIS Online ...")

        'Make the connection to the server we will use for retrieving demographic information
        Dim mapServer As New censusServer.ESRI_Census_USA_MapServer()
        mapServer.Url = "http://sampleserver1.arcgisonline.com/ArcGIS/services/Demographics/ESRI_Census_USA/MapServer"

        'Call the Census service to calculate the demographic information for the polygon.
        Dim spf As New censusServer.SpatialFilter()
        spf.FilterGeometry = SoapConverter.GeometryToSoap(Of Polygon, censusServer.PolygonN)(searchPoly)
    spf.SpatialRel = censusServer.esriSpatialRelEnum.esriSpatialRelIntersects
        spf.SubFields = "AGE_UNDER5, AGE_5_17, AGE_18_21, AGE_22_29, AGE_30_39, AGE_40_49, AGE_50_64, AGE_65_UP, MALES, FEMALES"
        Dim temp As String = mapServer.GetDefaultMapName()
        Dim recs As censusServer.RecordSet = mapServer.QueryFeatureData("Layers", 1, spf)

        help.UpdateMessage("Summing results of query ...")

        'Loop through the records that were returned and tally up the demographic data
        Dim males As Integer = 0
        Dim females As Integer = 0
        Dim age_u5 As Integer = 0
        Dim age_5_17 As Integer = 0
        Dim age_18_21 As Integer = 0
        Dim age_22_29 As Integer = 0
        Dim age_30_39 As Integer = 0
        Dim age_40_49 As Integer = 0
        Dim age_50_64 As Integer = 0
        Dim age_65_up As Integer = 0
        For j As Integer = 0 To recs.Records.Length - 1
            Dim censusRec As censusServer.Record = recs.Records(j)
            males += System.Convert.ToInt16(censusRec.Values(9))
            females += System.Convert.ToInt16(censusRec.Values(10))
            age_u5 += System.Convert.ToInt16(censusRec.Values(1))
            age_5_17 += System.Convert.ToInt16(censusRec.Values(2))
            age_18_21 += System.Convert.ToInt16(censusRec.Values(3))
            age_22_29 += System.Convert.ToInt16(censusRec.Values(4))
            age_30_39 += System.Convert.ToInt16(censusRec.Values(5))
            age_40_49 += System.Convert.ToInt16(censusRec.Values(6))
            age_50_64 += System.Convert.ToInt16(censusRec.Values(7))
            age_65_up += System.Convert.ToInt16(censusRec.Values(8))
        Next
        Dim genderTotal As Integer = males + females
        Dim ageTotal As Integer = age_u5 + age_5_17 + age_18_21 + age_22_29 + age_30_39 + age_40_49 + age_50_64 + age_65_up
        Dim dMales As Double = (System.Convert.ToDouble(males) / System.Convert.ToDouble(genderTotal)) * 100
        Dim dFemales As Double = (System.Convert.ToDouble(females) / System.Convert.ToDouble(genderTotal)) * 100
        Dim dage_u5 As Double = (System.Convert.ToDouble(age_u5) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_5_17 As Double = (System.Convert.ToDouble(age_5_17) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_18_21 As Double = (System.Convert.ToDouble(age_18_21) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_22_29 As Double = (System.Convert.ToDouble(age_22_29) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_30_39 As Double = (System.Convert.ToDouble(age_30_39) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_40_49 As Double = (System.Convert.ToDouble(age_40_49) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_50_64 As Double = (System.Convert.ToDouble(age_50_64) / System.Convert.ToDouble(ageTotal)) * 100
        Dim dage_65_up As Double = (System.Convert.ToDouble(age_65_up) / System.Convert.ToDouble(ageTotal)) * 100

        help.UpdateMessage("Creating popup message ...")

        'Figure out the percentage information for males and females, then generate the popup using
        'the Google chart api.
        Dim perc As String = "Males(" & dMales.ToString("###.#") & "%)|Females(" & dFemales.ToString("###.#") & "%)"
        Dim popup As String = "<b><font size='4'>" & "Gender</font></b>" & "<br><img src=""" & "http://chart.apis.google.com/chart?cht=p3&chd=t:" & dMales.ToString() & "," & dFemales.ToString() & "&chs=350x100&chl=" & perc & """ />"
        popup += "<br><br><b><font size='4'>" & "Age</font></b>" & "<br><img src=""" & "http://chart.apis.google.com/chart?cht=p3&chd=t:" & dage_u5.ToString() & "," & dage_5_17.ToString()
        popup += "," & dage_18_21.ToString() & "," & dage_22_29.ToString() & "," & dage_30_39.ToString() & "," & dage_40_49.ToString() & "," & dage_50_64 & "," & dage_65_up & "&chs=350x100&chl=Under 5|5 to 17|18 to 21|22 to 29|30 to 39|40 to 49|50 to 64|over 64" & """ />"

        'Add the polygon to the map as a note or graphic depending on the checkbox
        Dim searchGraphic As New Graphic(searchPoly, Symbol.CreateFill(Color.Orange, Color.Black))
        searchGraphic.Tag = "demographic query polygon"
        If chkResult.Checked Then
            Dim newNote As New Note(txtDistance.Text & " mile demographic query", searchGraphic)
      newNote.Popup.Content = popup
            _mapDisp.Map.ChildItems.Add(newNote)
        Else
            RemovePreviousGraphic()
            _mapDisp.Graphics.Add(searchGraphic)
            btnRemove.Enabled = True
        End If

        'Check extent and make sure we aren't zoomed in too far to show all of search shape
        Dim env As Envelope = GeometryOperations.Scale(searchPoly.GetEnvelope(), 1.25)
        If _mapDisp.Extent.Height < env.Height Or _mapDisp.Extent.Width < env.Width Then _mapDisp.ZoomTo(env)

        'Whether we are adding a graphic or a note, we can still show the popup information (it
        'just won't be stored for the graphic).
    ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay.HidePopups(True)
    Dim tempPopup As Popup = New Popup(ESRI.ArcGISExplorer.Application.Application.ActiveMapDisplay, popup, "Demographic information")
    tempPopup.Activate()

        'Close out the progress window
        help.Close()

        Return
    End Sub

    Private Sub RemovePreviousGraphic()
        If _mapDisp.Graphics.Count = 0 Then
            Return
        End If

        'Loop through the graphics in the map and remove the first one found with the demographic query tag
        Dim graphs As GraphicCollection = _mapDisp.Graphics
        For Each graph As Graphic In graphs
            If DirectCast(graph.Tag, String) = "demographic query polygon" Then
                _mapDisp.Graphics.Remove(graph)
                Return
            End If
        Next
    End Sub

    Private Sub btnLocate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLocate.Click
        'Capture a point from the map
        Dim loc As ESRI.ArcGISExplorer.Geometry.Point = _mapDisp.TrackPoint()
        If loc Is Nothing Then
            Return
        End If

        'If we got a point, then add some text to the location box and the point as the tag
        txtLocation.Text = loc.Y.ToString("###.##") & " " & loc.X.ToString("###.##")
        txtLocation.Tag = TryCast(loc, Object)
    End Sub
    Private Sub btnRemove_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRemove.Click
        'Call the routine to search for a demographic query graphic
        RemovePreviousGraphic()
        btnRemove.Enabled = False
    End Sub
End Class