#Geo - Basic Spatial Intersections

Comments

8 comments

  • Avatar
    Brant

    I have a need for something similar to this, but am not well versed with coding or PageLevel JS.  Would it be possible to get a sample of the code that you input into the PageLevel JS of your form to make this work?

    I basically want to populate a value for County name, based on coordinates from the location widget.  For Washington State Only.  I accomplished this in the past with the Google Maps API, but that solution is finicky and doesn't work without internet connection.  Here's a GeoJSON I was thinking I could use for this as well:  https://raw.githubusercontent.com/deldersveld/topojson/master/countries/us-states/WA-53-washington-counties.json

    Thanks for any help you can provide!

    0
    Comment actions Permalink
  • Avatar
    Bill DeVoe (Edited )

    Hi Brant - Are you with WDFW? Did not realize the link I had provided above was dead - I edited it to the code on my Gist page: https://gist.github.com/bdevoe/bc2637105b59ef0599b291f0941f215b

    The example uses some zone lines encoded as a GeoJSON. The GeoJSON was built by exporting the zone polygons from ArcGIS as a GeoJSON, after first removing unneeded attributes and then simplifying areas of the polygons that contained numerous vertices (ie, shorelines were simplified to have fewer vertices). This is necessary because you can store a maximum of 2 ^ 16 characters in Page Level JavaScript, so the resulting GeoJSON needs to be short enough to fit. Also notice in the example provided, the JSON is inserted as one line with no carriage returns (as opposed to a "pretty" JSON), as this would increase the character count. The projection was also set to WGS84 (EPSG: 4326) to match the lat/lon coordinates put out by the Location widget.

    The example you have provided is not actually a GeoJSON, but is a TopoJSON - an extension of GeoJSON that supports topology. This is a much more efficient way of representing something with colinear edges like counties, but would not work with the code I had provided. It is also not in the same projection as used by iFormBuilder (EPSG:4326). Using TopoJSONs for this is an intriguing idea though, as you could fit many more vertices within the form - maybe I will look into this at some point.

    So to get this to work in your case with the code I provided you would get a ShapeFile of Washington counties (the source for the TopoJSON you provided is here), load it into your GIS of choice, and either simplify the vertice count (which I would think would be essential giving the complexity of the WA coast), or more simply using a county boundary layer that extends past the shoreline to the limits of state waters.

    Once you have this to a small enough size to fit in the form, you add the PointInPolygon function from RPI and then edit the WhatZone function to iterate over each polygon and determine if the lat/lon provided is within the polygon - and if it is, add the attribute value of choice to the output list. The way I have it configured in the provided example will work with overlapping polygons, but this would not be required for counties.

    Note this is not a true spatial intersection as you would get with GIS software. You are intersecting lat/lon coordinates that are not projected, basically treating them as Euclidean x/y coordinates even though they are angular (same idea as how a Mercator projection distorts distance/area), but it seems to work well enough for the accuracy required. Also as noted this does not work with "donut hole" features or features with indentations wherein a ray cannot be cast without intersecting the polygon, but it will work with multi-part features. Given that municipal boundaries typically do not have these geometry types I would not expect this to be a problem.

    0
    Comment actions Permalink
  • Avatar
    Brant

    Bill,

    Thanks for the prompt, (and detailed!) response.  Also appreciate the updated link and explanations.  I actually work with WSDA, but I know WDFW has been a heavy iForm user for a few years now as well.

    I was able to simplify, reproject, and export out a GeoJSON of WA counties that is around 43K characters.  I went in and gave the JS a whirl as well, but I've not been successful with getting it to work in my form. 

    Not sure if my coding is off or if maybe I'm just not calling on the function correctly.  Any chance you could glance over my script?: https://gist.github.com/bcarman/22baadbaa3c7a821dd626d98ae4e6b16

    To extract a value from this in my form I assumed that I needed to set {WhatCounty(point)} as a dynamic value in the element to be populated with a county name.  'point' being the DCN of an element that I am populating with "longitude,latitude" from my location widget. Is this right?

    I'm somewhat of a novice when it comes to JS and iForm's PageLevel JS, so sorry for all the questions.  I really appreciate any help on this, and everything you've provided so far.

    Thanks again.

     

    0
    Comment actions Permalink
  • Avatar
    Bill DeVoe

    You got it 99.5% right - remove the equal sign on line 35:

    for (x in county=.features)

    to

    for (x in county.features)

    Then, call the function by passing your point as an x, y array - for example:

    WhatCounty([-120.929806, 46.457982]);

    I tried this on jsfiddle.net and it worked. In iFormBuilder, for your dynamic value you would call the function from Page Level Javascript in the same manner, either passing the DCN of the lon and lat fields, or by accessing the Location widget directly - say you have a Location Widget with a DCN of 'my_location' - the Dynamic Value would be:

    WhatCounty([my_location.longitude, my_location.latitude]);

    If it does not work remove the semicolon, I can't seem to figure out when iFormBuilder wants or does not want semicolons in Dynamic Values and Conditional Statements.

    0
    Comment actions Permalink
  • Avatar
    Jonathan Hsu

    Hi Bill I just wanted to acknowledge the level of detail and thoughtfulness in your responses over the past few days. Happy to have you as a part of the Zerion and iFormBuilder community.

    0
    Comment actions Permalink
  • Avatar
    Bill DeVoe

    Thanks Jon!

    Actually while I've got your attention you might be able to help me something given what I've seen of your JS posts -

    Do you know if there is anyway to access the entire JSON of a lookup table from a SmartTable Search field? The entire table is obviously stored locally on the device, but I can only access the JSON of the record that is selected in the SmartTable Search field, not the entire table.

    Reason I am asking - I have a use case for a field sampler to input their current location, then show the nearest sampling station, as well as validate that they are within a certain distance of the station. I could do this with the workflow outlined above, storing the sampling stations as a JSON in the page level JS and iterating over them with the Haversine equation to find the closest, but this is a pain if something changes (a station is added for example.) It would be much more robust if there was a way to pass the JSON data for a lookup table into a user-defined function.

    0
    Comment actions Permalink
  • Avatar
    Brant (Edited )

    After those tweaks, it is working perfectly in my form!  This will be a huge improvement over the Google Maps API solution that I was using before, since many of our users go in and out of cell coverage frequently. 

    The detail level in your responses is beyond awesome.  Thanks again for the fast responses and answering my questions so clearly.

     

    I will also be very interested to hear of any progress you make with using TopoJSONs in a similar fashion.  Please keep us posted here if you ever give that a try!

    0
    Comment actions Permalink
  • Avatar
    Bill DeVoe

    Your welcome, glad to hear you got it working. The existence of a TopoJSON specification was news to me, so I'm not sure if/how this would be worked - most likely would be a function to convert the TopoJSON to a regular GeoJSON or arrays of polygon outlines to plug into the current code.

    0
    Comment actions Permalink

Please sign in to leave a comment.

Powered by Zendesk