Select to view content in your preferred language

Arcade projectAs Geometry Function

6222
27
05-06-2022 12:23 AM
Status: Under Consideration
Labels (1)
JacobFougstrupNicolajsen
New Contributor II

Working primarily with data in UTM projection, I often need ways to convert UTM coordinates to WGS to create deep links to various online services. 

Having to create duplicate datasets, or running python scripts as regular intervals is tedious and time consuming.

And arcade equivalent of the python projectAs method would solve almost all these issues.

 

27 Comments
TomNeer

@DavidColey - Here is the Arcade expression that can return either latitude or longitude. So at first, I thought my code was **bleep** because it was returning slightly different values than Esri's Calculate Geometry tool (even double-checking my transformations), but I ran several test SPC through NGS Coordinate Conversion and Transformation Tool (NCAT) (noaa.gov) and this code is more accurate than Esri's. Go figure...

 

 

// Calculates the latitude or longitude of a State Plane coordinate
// Source: https://community.esri.com/t5/coordinate-reference-systems-questions/formula-for-state-plane-to-lat-lon-conversion/td-p/870543/page/2

// Get Colorado State Plane North (2231) coordinates from geometry
var x = Geometry($feature).x;
var y = Geometry($feature).y;

// Projection Information (this must be changed if you are not using EPSG 2231)
var linear_unit = 0.3048006096012192;
var false_easting = 3000000.000316083;
var false_northing = 999999.999996;
var central_meridian = -105.5;
var sp1 = 39.71666666666667;
var sp2 = 40.78333333333333;
var latitude_of_origin = 39.33333333333334;
var semimajor_axis = 6378137.0;
var semiminor_axis = 6356752.314140356;

function degToRad(deg) {
  return (deg * PI / 180)
}

function radToDeg(rad) {
  return (rad * 180) / PI
}

function tVal(t) {
  return (Tan((PI / 4) - (t / 2)) / Pow((1 - (ecc * Sin(t))) / (1 + (ecc * Sin(t))), (ecc / 2)))
}

// Convert projection information into radians
var lorR = degToRad(latitude_of_origin);
var sp1R = degToRad(sp1);
var sp2R = degToRad(sp2);

// Spherical Trig voodoo
var flat = 1 / (semimajor_axis / (semimajor_axis - semiminor_axis));
var ecc = Sqrt(2 * flat - Pow(flat, 2));
var n = (Log(Cos(sp1R) / Pow((1 - Pow(ecc, 2) * Pow(SIN(sp1R), 2)), 0.5)) - Log(Cos(sp2R) / Pow((1 - Pow(ecc, 2) * Pow(SIN(sp2R), 2)), 0.5))) / (Log(tVal(sp1R)) - Log(tVal(sp2R)))
var f = (Cos(sp1R) / Pow((1 - Pow(ecc, 2) * Pow(SIN(sp1R), 2)), 0.5)) / (n * Pow(tVal(sp1R), n))
var rf = (semimajor_axis * (1 / linear_unit)) * f * Pow(tVal(lorR), n)
var rz = Pow(Pow((x - false_easting), 2) + Pow((rf - (y - false_northing)), 2), 0.5)
var tz = Pow((rz / ((semimajor_axis * (1 / linear_unit)) * f)), (1 / n))
var zz = Atan((x - false_easting) / (rf - (y - false_northing)));

// Latitude iterations in radians
var latTR = (PI / 2) - (2 * Atan(tz))
var lat1R = (PI / 2) - (2 * Atan((tz * Pow((1 - (ecc * Sin(latTR))) / (1 + (ecc * Sin(latTR))), (ecc / 2)))))
var lat2R = (PI / 2) - (2 * Atan((tz * Pow((1 - (ecc * Sin(lat1R))) / (1 + (ecc * Sin(lat1R))), (ecc / 2)))))
var lat3R = (PI / 2) - (2 * Atan((tz * Pow((1 - (ecc * Sin(lat2R))) / (1 + (ecc * Sin(lat2R))), (ecc / 2)))))
var lat4R = (PI / 2) - (2 * Atan((tz * Pow((1 - (ecc * Sin(lat3R))) / (1 + (ecc * Sin(lat3R))), (ecc / 2)))))
var latFR = (PI / 2) - (2 * Atan((tz * Pow((1 - (ecc * Sin(lat4R))) / (1 + (ecc * Sin(lat4R))), (ecc / 2)))))

// Longitude calculations in radians
var lonR = ((zz / n) + degToRad(central_meridian));

// Latitude and Longitude values in degrees
var latitude = radToDeg(latFR)
var longitude = radToDeg(lonR)

// Change me
return longitude;
DavidColey

Way to go @TomNeer  - I am starting to recall from my geomatics days that the longitude conversion is a simpler calc.  Thanks for posting this.... I'll parameterize for Florida State Plane West wkid 2882 and let you know how it goes....

DavidColey

Alas I thought this might be a more-straightforward task, but as State Plane Coordinate systems using a Transverse Mercator projection do not contain parameters for standard parallels (since they're not conformal projections and the false northing is always 0), it is not a simple adjustment to @TomNeer 's Arcade above.... 

TomNeer
That is a limitation of this formula. It is possible, but my spherical
trigonometry is pretty rusty.

Would be easier if Esri just supported projections in Arcade.
DavidColey

Agreed.  I'd have to dig back into old geomatics class work to find my spherical trig, and it has been a while that is for sure.  But, for those out there working in any east-west extent state plane coord systems, your algorithm works well.

Only need to make the adjustments as you indicate. 

In the meantime @TomNeer , I'd say that you have done half of Esri's work for them (as far as state plane conversions go.

MiltonSolano

Team,

+1 here! We capture new trees on the field using Field Maps. Because our trees are 1-2 meters apart, we use our local UTM Zone 17 North projection and to better improve tree geolocation, we developed a local grid reference system.

Having the option to calculate UTM positions directly on Field Maps will be a great functionality, because right now we need to update the UTM fields using ArcGIS Pro or AGOL notebook.

Best,

Mjss25

SeanLyons

Another use case for a built in projection is trying to deal with the difference between the control point actual location and the control point geometry location for the Pro Parcel fabric. This was fine in ArcGIS Desktop as point and the control were separate layers now that they are the same layer we need to show the correct absolute location of the control.

The snag is the fabric is on the fly projected to a UTM Zone but is stored in Albers. This means we can only get the labelling to be correct if it is in Albers. The instant we change the label to albers we get a distance that is giant.  Example below.

Albers

SeanLyons_0-1687898304580.png

UTM Zone 

SeanLyons_1-1687898391139.png

This label was made with some simple arcade for reference.

var point = Geometry($feature)
var x1 = point.x;
var y1 = point.y;
var x2 = $feature.X;
var y2 = $feature.Y;
var offset = round(sqrt(pow(x2-x1,2)+pow(y2-y1,2)),2);
if (offset > 0)
return "(" + offset + ")";

 

shodge_fsu

Seems like a no brainer to add this functionality

My users want to see state plane coordinates.  Florida has (at least for now) three state plane zones and we use the Web Mercator projection for all of the layers in the map.  The strategy for obtaining the Lat / Lon from these coordinates mentioned elsewhere in this thread works great, but now we need to project those coordinates to the appropriate state plane zone.

Hope to see this functionality in 1.13!

Adam_Coburn_NCC

Another +1

This functionality would make such a difference!

Being able to use an out of the box Arcade function to go from 27700 - OSGB36 (BNG) to WGS84 (4236) would allow us to pre-populate Geopoint questions in Survey123 via custom URL parameters.

AlfredBaldenweck

I just got burned with this pretty hard.

I was working on a popup to show where features intersect a set of polygons.

Worked great when the polygons were in an enterprise GDB.

I tested on with the same polygons in a map service, and it gave me several false positives. As it turns out, it was because the spatial references were different. For some reason, the enterprise GDB was able to account for that, but the service was not.

So now I have to have my users reference a specific layer in their map (referencing a file in an eGDB), rather than just pointing to a service (that doesn't even need to be present in the map, period).

Please let us reproject at least a $feature, if not an entire feature set.