Script to record GPS metadata?

6148
4
03-24-2016 11:46 AM
MarkJohnson
New Contributor III

I've been working with Jeff LeProwse's AddXYZ+ applet to record GPS metadata with each point collected. I'm at the point where I'm in over my head as far as figuring out the coding.

I've set up ArcPad 10.2.2 to average 30 seconds of observations per point.

Problems with the script:

1. The applet uses onFeatureAdded which means the GPS metadata is recorded when OK is pressed to create the new point and not when the GPS finishes collecting the coordinates. So if you stand in the road for 30 seconds while the GPS collects the point and then move to the side of the road for 5 minutes filling in forms and press OK the GPS metadata is recorded for wherever you were standing at that moment, not out in the road.

2. For existing points the GPS metadata is updated onFeatureUpdated regardless of whether GPS is used to update the position. If the GPS is enabled and I move a point with the mouse the GPS metadata will update.

To get around this I've gone to calling the applet on GPS onAverageStop, which works when moving existing points, but doesn't for new points because there isn't an existing RecordSet to update(?) so I think populating the open EditForm is the way to go but can't get the code to work.

Summary: I'd like the script to record GPS metadata at the moment the GPS finishes averaging and records the position when adding new points with AddGPSPoint and moving existing points with MovePointToGPS only. Also needs to factor in the possibility of toggling between editing several point layers and a polyline layer with the QuickCapture toolbar.

Some code (which doesn't work):

<?xml version="1.0" encoding="UTF-8"?>

<ArcPad compiled="true">

  <APPLET name="AddXYZ+_RCE_fields">

       <SYSTEMOBJECTS>

            <GPS onAverageStop="Call UpdateGPSFields"/>

       </SYSTEMOBJECTS>

  </APPLET>

<SCRIPT language="VBScript">Option Explicit

Sub UpdateGPSFields

'Define attributes

Dim MyCoordSys, objRS, f, strMessage, fCount, objForm, editPointLayer

'Get current edit point layer

Set editPointLayer = Map.EditLayer(1)

'Get current edit point layer EDITFORM

Set objForm = editPointLayer.Forms("EditForm")

'Check to see if the EDITFORM is open (3)

'If not open, assume Move to GPS operation on selected point

If objForm.Mode = 3 Then

  Application.StatusBar.Text = "EDITFORM is open"

Else

  'Get current coordinate system

  Set MyCoordSys = Application.Map.CoordinateSystem

  'Get the RecordSet of the currently selected feature's layer

  'SelectionLayer returns layer of currently selected feature

  Set objRS = Map.Selectionlayer.Records

  'Bookmark the currently selected record

  objRS.Bookmark = ThisEvent.Bookmark

  'Check if the current shape is a point

  If Right(objRS.Fields.ShapeType, 1) = 1 Then

  'Check what the coordinate system is

  If MyCoordSys.GeographicName = "GCS_WGS_1984" Then

  'Loop through the current layer's fields

       For Each f in objRS.Fields

            Select Case Ucase(f.name)

                 Case "GPS_X"

                    f.Value = GPS.x

                    fCount = fCount + 1

                 Case "GPS_Y"

                    f.Value = GPS.y

                    fCount = fCount + 1

                 Case "GPS_LAT"

                    f.Value = GPS.Latitude

                    fCount = fCount + 1

...

4 Replies
RobBlash
Occasional Contributor III

Were you ever able to come up with a solution?

0 Kudos
RebeccaStrauch__GISP
MVP Emeritus

Have you thought about hitting a button to start the averaging, then another when ready to stop and also have it bring up the form.  You could write the average location to an  Application.UserProperties(“yourTempVariable”) until you finish your form, then write all to the shapefile (or whatever you are writing to).  That is similar to how we mark an animal location from the plane, but allow the biologist to fill in the data afterwords.  We are only collecting the one point, but they could be miles away before they have the form complete.  I capture the point of the click, but you could do something similar with an average, I would assume.  I also have a running average speed which is capture for 60 seconds “before” they hit the button….I’m not sure how easy it would be to do a running average of locations (also have many distance counters, some which reset based on other button action).

MarkJohnson
New Contributor III

Thanks for the replies, I ended up rewriting the script so it checks if a form is open and if it is it writes the GPS data to a custom form page "GPS" which I'm adding to all my edit forms, otherwise it assumes I'm moving an existing point and uses the selected record approach. The code is really inefficient and I ran into some other issues but it's working at a basic level.

Rebecca's reply mentioning Application.UserProperties that I hadn't discovered yet gives me a whole other way to approach this that I'll attempt later when I have some time.

<?xml version="1.0" encoding="UTF-8"?>

<ArcPad compiled="true">

  <APPLET name="GPS_Metadata2">

  <SYSTEMOBJECTS>

  <GPS onAverageStop="Call GPSMetadata"/>

  </SYSTEMOBJECTS>

  </APPLET>

  <SCRIPT language="VBScript">

Option Explicit

Sub GPSMetadata

' Main routine to add GPS metadata from the NMEA string to edit layers configured with GPS attributes.

' Set variables

Dim editPointLayer, editLineLayer

'Get edit layers

Set editPointLayer = Map.EditLayer(1)

Set editLineLayer = Map.EditLayer(2)

'If there is an edit point layer, add/update GPS metadata if EDITFORM open or selected feature

If Not (editPointLayer Is Nothing) Then

' If the EDITFORM is open, assume creating a new point and fill in form and update GPS fields values

  If editPointLayer.Forms("EDITFORM").Mode = 3 Then

  Call FillGPSForm(editPointLayer)

' If EDITFORM is not open but the edit point layer has a feature currently selected update GPS fields values

  ElseIf editPointLayer.Name = Map.SelectionLayer.Name Then

' Application.StatusBar.Text = "The edit point layer matches the selection layer"

  Call UpdateGPSFields(editPointLayer)

  End If

End If

'If there is an edit line layer, add/update GPS metadata if EDITFORM open or selected feature

If Not (editLineLayer Is Nothing) Then

' This won't work because form isn't open until after drawing a new polyline

  If editLineLayer.Forms("EDITFORM").Mode = 3 Then

  Call FillGPSForm(editLineLayer)

' If EDITFORM is not open but the edit line layer has a feature currently selected update GPS fields values

  ElseIf edit LineLayer.Name = Map.SelectionLayer.Name Then

' Application.StatusBar.Text = "The edit line layer matches the selection layer"

  Call UpdateGPSFields(editLineLayer)

  End If

End If

End Sub

Sub FillGPSForm(editLayer)

' Populates GPS attributes values and the open form

' Use when creating a new feature and the EDITFORM is open

' Testing showed values not updating if attributes are on the active form page, hence the overkill with forms and values

' Define variables

Dim f, fCount

For Each f in editLayer.Forms("EDITFORM").Fields

  Select Case Ucase(f.name)

  Case "GPS_QUAL"

' Application.StatusBar.Text = GPS.Properties("QUALITY")

  f.Value = GPS.Properties("QUALITY")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_QUAL").Value = GPS.Properties("QUALITY")

  fCount = fCount + 1

  Case "GPS_SATS"

' Application.StatusBar.Text = GPS.Properties("SATS_USED")

  f.Value = GPS.Properties("SATS_USED")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_SATS").Value = GPS.Properties("SATS_USED")

  fCount = fCount + 1

  Case "GPS_X"

  f.Value = GPS.x

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_X").Value = GPS.x

  fCount = fCount + 1

  Case "GPS_Y"

  f.Value = GPS.y

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_Y").Value = GPS.y

  fCount = fCount + 1

  Case "GPS_Z"

  f.Value = GPS.Z

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_Z").Value = GPS.Z

  fCount = fCount + 1

  Case "GPS_LAT"

  f.Value = GPS.Latitude

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_LAT").Value = GPS.Latitude

  fCount = fCount + 1

  Case "GPS_LONG"

  f.Value = GPS.Longitude

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_LONG").Value = GPS.Longitude

  fCount = fCount + 1

  Case "GPS_ALT"

  f.Value = GPS.Altitude

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_ALT").Value = GPS.Altitude

  fCount = fCount + 1

  Case "GPS_PDOP"

  f.Value = GPS.Properties("PDOP")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_PDOP").Value = GPS.Properties("PDOP")

  fCount = fCount + 1

  Case "GPS_HDOP"

  f.Value = GPS.Properties("HDOP")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_HDOP").Value = GPS.Properties("HDOP")

  fCount = fCount + 1

  Case "GPS_VDOP"

  f.Value = GPS.Properties("VDOP")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_VDOP").Value = GPS.Properties("VDOP")

  fCount = fCount + 1

  Case "GPS_DGPS"

  f.Value = GPS.Properties("DIFF_ID")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_DGPS").Value = GPS.Properties("DIFF_ID")

  fCount = fCount + 1

  Case "GPS_DIFF"

  f.Value = GPS.Properties("DIFF_AGE")

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_DIFF").Value = GPS.Properties("DIFF_AGE")

  fCount = fCount + 1

  Case "GPS_TIME"

  f.Value = FormatDateTime(GPS.Properties  ("UTC"), vbLongTime)

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_TIME").Value = FormatDateTime(GPS.Properties  ("UTC"), vbLongTime)

  fCount = fCount + 1

  Case "GPS_DATE"

  f.Value = FormatDateTime(GPS.Properties  ("UTC"), vbShortDate)

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_DATE").Value = FormatDateTime(GPS.Properties  ("UTC"), vbShortDate)

  fCount = fCount + 1

  Case "GPS_T_LOC"

  f.Value = FormatDateTime(Now, vbLongTime)

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_T_LOC").Value = FormatDateTime(Now, vbLongTime)

  fCount = fCount + 1

  Case "GPS_D_LOC"

  f.Value = FormatDateTime(Now, vbShortDate)

  editLayer.Forms("EDITFORM").Pages.Item("GPS").Controls("txtGPS_D_LOC").Value = FormatDateTime(Now, vbShortDate)

  fCount = fCount + 1

  End Select

Next

End Sub

Sub UpdateGPSFields(selLayer)

' Updates GPS attributes for the selected editable feature

' Use when updating the position of an existing feature with GPS ("move to GPS")

' Define variables

Dim f, fCount, objRS

' Get the currently selected record from the edit layer

Set objRS = selLayer.Records

objRS.Bookmark = Map.SelectionBookmark

For Each f in objRS.Fields

  Select Case Ucase(f.name)

  Case "GPS_QUAL"

' Application.StatusBar.Text = GPS.Properties("QUALITY")

  f.Value = GPS.Properties("QUALITY")

  fCount = fCount + 1

  Case "GPS_SATS"

' Application.StatusBar.Text = GPS.Properties("SATS_USED")

  f.Value = GPS.Properties("SATS_USED")

  fCount = fCount + 1

  Case "GPS_X"

  f.Value = GPS.x

  fCount = fCount + 1

  Case "GPS_Y"

  f.Value = GPS.y

  fCount = fCount + 1

  Case "GPS_Z"

  f.Value = GPS.Z

  fCount = fCount + 1

  Case "GPS_LAT"

  f.Value = GPS.Latitude

  fCount = fCount + 1

  Case "GPS_LONG"

  f.Value = GPS.Longitude

  fCount = fCount + 1

  Case "GPS_ALT"

  f.Value = GPS.Altitude

  fCount = fCount + 1

  Case "GPS_PDOP"

  f.Value = GPS.Properties("PDOP")

  fCount = fCount + 1

  Case "GPS_HDOP"

  f.Value = GPS.Properties("HDOP")

  fCount = fCount + 1

  Case "GPS_VDOP"

  f.Value = GPS.Properties("VDOP")

  fCount = fCount + 1

  Case "GPS_DGPS"

  f.Value = GPS.Properties("DIFF_ID")

  fCount = fCount + 1

  Case "GPS_DIFF"

  f.Value = GPS.Properties("DIFF_AGE")

  fCount = fCount + 1

  Case "GPS_TIME"

  f.Value = FormatDateTime(GPS.Properties  ("UTC"), vbLongTime)

  fCount = fCount + 1

  Case "GPS_DATE"

  f.Value = FormatDateTime(GPS.Properties  ("UTC"), vbShortDate)

  fCount = fCount + 1

  Case "GPS_T_LOC"

  f.Value = FormatDateTime(Now, vbLongTime)

  fCount = fCount + 1

  Case "GPS_D_LOC"

  f.Value = FormatDateTime(Now, vbShortDate)

  fCount = fCount + 1

  End Select

Next

' Update the record

objRS.Update

End Sub

</SCRIPT>

</ArcPad>

0 Kudos
RebeccaStrauch__GISP
MVP Emeritus

Mark, since you were able to resolve this yourself, you may want to close this thread by marking it "assumed answered".

But I've also attached one of my .vbs files for this project that has many of the functions I use to create and populate shapes on the fly (figuratively and literally, since it is an aerial survey).  Reading thru this may give you some additional ideas.  I actually have a set of four .vbs that I call from my .apa file (besides the .vbs for my form)

</APPLET>

    <SCRIPT src="sessionapps.vbs"/>

    <SCRIPT src="transectapps.vbs"/>

    <SCRIPT src="bearapps.vbs"/>

    <SCRIPT src="createshapes.vbs"/>

</ArcPad>

I do this so I can easily separate the different functions for the arcpad session, and creating/populating lines vs point functions.  I'll attach the createshapes.vbs in case it will help.  I renamed it .txt to make it easier to access.  Just fyi.

0 Kudos