0
\$\begingroup\$

I have an ArcGIS Arcade script that uses JavaScript syntax.

  • The script loops through GIS polylines and updates a coordinate.
  • The coordinate is called an "M" coordinate (aka a "Measure-value"). M coordinates are similar to X and Y coordinates, but are used for specialized linear referencing purposes.

enter image description here

//var geom = Dictionary(Text(Geometry($feature)));
//var paths = geom['paths'];
var paths = [[[0,5,null],[10,10, null],[30,0, null],[50,10, null],[60,10, null]]] //input data for Code Review testing purposes
var geom_updated = false;
var length = 0;

for (var path_idx in paths) {
    for (var vertex_idx in paths[path_idx]) {
        //Set the first vertex's M-value to 0.
        if (vertex_idx == 0) {
            paths[0][0][-1] = 0;
            geom_updated = true;
        //For the rest of the vertices, set the M-value to the cumulative length of the line.
        } else {
            //Set the startpoint and endpoint of the current segment of the polyline.
            //Note: The geometry type, and its subtypes (Point and Polyline) are immutable: https://community.esri.com/t5/arcgis-pro-questions/are-arcade-geometry-subtypes-immutable-i-e-point/m-p/1150097#M52278    
            var startpoint = Point({ 'x': paths[path_idx][vertex_idx - 1][0], 'y': paths[path_idx][vertex_idx - 1][1], 'spatialReference': { 'wkid': 26917 } });
            var endpoint   = Point({ 'x': paths[path_idx][vertex_idx][0],     'y': paths[path_idx][vertex_idx][1],     'spatialReference': { 'wkid': 26917 } });

            //The Distance() function returns the planar distance between two geometries in the given units. This is a planar measurement using Cartesian mathematics. https://developers.arcgis.com/arcade/function-reference/geometry_functions/#distance
            //I think the Pythagorean theorem would produce the same result: https://stackoverflow.com/questions/20916953/get-distance-between-two-points-in-canvas
            length = length + Distance(startpoint, endpoint);
            paths[path_idx][vertex_idx][-1] = length;
            geom_updated = true;
        }
    }
}
if (!geom_updated) {
    return
}
return {
    //"result": {"geometry": Polyline(geom)}
    "result": { "geometry": paths }
};
//Output: [[[0,5,0],[10,10,11.18],[30,0,33.54],[50,10,55.90],[60,10,65.90]]]

Related: ArcGIS Arcade Function Reference

How can the script be improved?

\$\endgroup\$
1
  • \$\begingroup\$ Yes, much better. I tried to run your code, and I get pretty far, but the end: Polyline(geom), makes no sense. Basically geom is not defined. Can I assume you mean paths? Yes, that must be it. \$\endgroup\$ Commented Mar 3, 2022 at 18:35

2 Answers 2

1
\$\begingroup\$

I rewrote your script to the code below:

function pythagoras(x1, y1, x2, y2)
{
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}

//input data for Code Review testing purposes
var paths = [[[0,5,null],[10,10, null],[30,0, null],[50,10, null],[60,10, null]]];

for (const path of paths) {
    let oldX = path[0][0], oldY = path[0][1], length = 0;
    for (const point of path) {
        let newX = point[0], newY = point[1];
        length += pythagoras(oldX, oldY, newX, newY);
        point[2] = length;
        oldX = newX;
        oldY = newY;
    }
}

console.log(paths);

I did away with your Point() and Distance() because I don't have them. I think you can extract something useful from this.

Your code isn't very different. I still use two nested loops, which is inevitable, I think. Some people will try to remove the loops and replace them by array functions, but they do basically the same while hiding the loops. This is more honest. The outer loop, loops over the paths, and the inner loop over the points in each path. As you can see I use two temporary points; The "old" and "new", and compute the distance between them. That is added to an existing "length" and stored with each point.

The output is:

[[[0,   5, 0],
  [10, 10, 11.180339887498949],
  [30,  0, 33.54101966249685],
  [50, 10, 55.90169943749475],
  [60, 10, 65.90169943749476]]]

Instead of working with (x,y) coordinates, I could also work with points, like this:

function pythagoras(p1, p2)
{
    return Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2));
}

//input data for Code Review testing purposes
var paths = [[[0,5,null],[10,10, null],[30,0, null],[50,10, null],[60,10, null]]];

for (const path of paths) {
    let oldPoint = path[0], length = 0;
    for (const newPoint of path) {
        length += pythagoras(oldPoint, newPoint);
        point[2] = length;
        oldPoint = newPoint;
    }
}

console.log(paths);

This is slightly easier to read, but basically does exactly the same.

\$\endgroup\$
0
0
\$\begingroup\$

All of KIKO Software's review applies, but the suggest replacement code doesn't work on the JavaScript implementation being targeted (ArcGIS Arcade), because it doesn't support these keywords:

  • const
  • let
  • for (… of …)

It supports only the keywords mentioned in ArcGIS Arcade - Structure and Logic.


We can modify KIKO Software's code to something compatible:

function pythagoras(x1, y1, x2, y2) {
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}

var paths = [[[0, 5, null], [10, 10, null], [30, 0, null], [50, 10, null], [60, 10, null]]];
var oldX = paths[0][0][0], oldY = paths[0][0][1], length = 0;

for (var path_idx in paths) {
    for (var point_idx in paths[path_idx]) {
        var newX = paths[path_idx][point_idx][0], newY = paths[path_idx][point_idx][1]
        length += pythagoras(oldX, oldY, newX, newY);
        paths[path_idx][point_idx][2] = length;
        oldX = newX;
        oldY = newY;
    }
}  
console.log(JSON.stringify(paths));
//Output: [[[0,5,0],[10,10,11.180339887498949],[30,0,33.54101966249685],[50,10,55.90169943749475],[60,10,65.90169943749476]]]

JSFiddle

I would be happy to hear comments about anything I might have overlooked.


Related:

I have a related question in the ArcGIS Community that has a GIS-specific script: Set polyline M-values to cumulative length of line.

That script is the latest version.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ I've modified your answer so that it's an actual review rather than just a comment on another answer. I appreciate that this is a self-answer; it's still most useful if it sustains the standard expected of all answers. \$\endgroup\$ Commented Mar 12, 2022 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.