[Arcade] Get z-Value from intersecting feature

431
5
Jump to solution
11-11-2022 01:38 AM
StefanAngerer
Occasional Contributor

Hi there,

I am yet again standing infront of a problem :') I am currently trying to edit the geometry of $feature by giving it the z-value of an intersecting feature. For this to work I created this code snippet:


var lines = FeatureSetByName($map, "linefeature", ["globalId"], false)

var intersectingLines = Intersects(lines, $feature)
var lines = count(intersectingLines)

if(lines == 1){
var intersectingLine = First(intersectingLines)
var newGeo = Point({
"x": Geometry($feature).x,
"y": Geometry($feature).y,
"z": Geometry(intersectingLine).z,
"spatialReference": Geometry($feature).spatialReference
})
SetGeometry($feature, newGeo)
return true
} else {
return true
}

So far so good, but somehow it won't work. Any Ideas what could be the problem?

Thanks!

Stefan

 

 

0 Kudos
1 Solution

Accepted Solutions
StefanAngerer
Occasional Contributor

I managed to slove it myself. It was a problem with the result statement. This is the snippet that worked for me:

 

var lines = FeatureSetByName($map, "linefeature", ["globalId"], false)

var intersectingLines = Intersects(lines, $feature)
var lines = count(intersectingLines)

if(lines == 1){
var intersectingLine = First(intersectingLines)
var newGeo = Point({
"x": Geometry($feature).x,
"y": Geometry($feature).y,
"z": Geometry(intersectingLine).z,
"spatialReference": Geometry($feature).spatialReference
})
return { "result": { "geometry": newGeo } };
} else {
return true
}

View solution in original post

0 Kudos
5 Replies
StefanAngerer
Occasional Contributor

I managed to slove it myself. It was a problem with the result statement. This is the snippet that worked for me:

 

var lines = FeatureSetByName($map, "linefeature", ["globalId"], false)

var intersectingLines = Intersects(lines, $feature)
var lines = count(intersectingLines)

if(lines == 1){
var intersectingLine = First(intersectingLines)
var newGeo = Point({
"x": Geometry($feature).x,
"y": Geometry($feature).y,
"z": Geometry(intersectingLine).z,
"spatialReference": Geometry($feature).spatialReference
})
return { "result": { "geometry": newGeo } };
} else {
return true
}

0 Kudos
MikeMillerGIS
Esri Frequent Contributor

It is fairly more complex than that.  I have not tested this at all, but this should get you started.

 

// How man decimals to round coordinates to check if identical
// GCS should use a large value, such as 9
// PCS should use a value such as 4
var compare_coordinate_round_value = 2;

// When walking the line to split, a line is created between pairs of vertex
// this value is the distance ito determine if the created point is on that line
// GCS should use a small value, such as 0.0001
// PCS should use a larger value, such as 0.1
var point_on_line_tol = 0.1;

function get_z_at_location(line_geometry, point_geometry) {
    var point_coord = null;
    if (TypeOf(line_geometry) == 'Dictionary') {
        line_shape = line_geometry;
    } else {
        line_shape = Dictionary(Text(line_geometry));
    }

    point_coord = [point_geometry.X, point_geometry.Y];

    var line_path = line_shape['paths'];
    // If the point is at the start or end
    if (compare_coordinate(point_coord[0],point_coord[1], line_path[0][0][0], line_path[0][0][1]))
    {
        return line_path[0][0][2];
    }
    if (compare_coordinate(point_coord[0],point_coord[1], line_path[-1][-1][0],line_path[-1][1])) {
        return line_path[-1][-1][2];
    }

    var min_distance = point_on_line_tol * 2;
    var z_value = null;


    for (var i in line_path) {
        var current_path = line_path[i];
        // Loop over vertex, exit when at last vertex
        for (var j = 0 ; j < Count(current_path) - 1 ; j++) {
            var from_coord = current_path[j];
            var to_coord = current_path[j + 1];
            var shortest = pDistance(point_coord[0], point_coord[1], from_coord[0], from_coord[1], to_coord[0],to_coord[1]);
            var distance =  shortest[0];
	        var coordinates = shortest[1];
	        var isVertex =  shortest[2];
            if (distance <= min_distance) {
                // set the min distance of the current item
                min_distance = distance;
                var to_z = to_coord[2];
                var from_z = from_coord[2];
                // If the Z's are equal, no need to interpolate or check anything else
                if (to_z == from_z){
                    z_value = to_z;
                    continue;
                }
                if (isVertex){
                    if (compare_coordinate(from_coord[0], from_coord[1],coordinates[0],coordinates[1])){
                        z_value = from_z;
                        continue;
                    }
                    else if (compare_coordinate(to_coord[0], to_coord[1],coordinates[0],coordinates[1])){
                        z_value = to_z;
                        continue;
                    }
                }

                // Since the Zs are not equal and we are not at a vertex, we need to interpolate the z at the location
                var dist_to_point = Sqrt( (coordinates[0] - from_coord[0]) * Exp(2) + (coordinates[1] - from_coord[0])* Exp(2))
                var dist_of_seg = Sqrt( (to_coord[0] - from_coord[0]) * Exp(2) + (to_coord[1] - from_coord[0])* Exp(2))
                var percent_along = (dist_to_point/ dist_of_seg)
                var z_dif = Abs(to_z - from_z)
                z_value = z_dif * percent_along
            }
        }
    }
    return z_value
}

function compare_coordinate(x, y, x1, y1) {

    // TODO, probably move to Equals and compare the geometry
    if ((Round(x1, compare_coordinate_round_value) != Round(x, compare_coordinate_round_value)) ||
        (Round(y1, compare_coordinate_round_value) != Round(y, compare_coordinate_round_value)) ){
        return false;
    }
    return true;
    // TODO - Figure out Z
    if (Count(coordinate > 2) && IsEmpty(source_geo.Z) == false) {
        if (Round(coordinate[2], 2) != Round(source_geo.Z, 2)) {
            return false;
        }
    }
    return true;
}

function pDistance(x, y, x1, y1, x2, y2) {
  // adopted from https://stackoverflow.com/a/6853926
  var A = x - x1;
  var B = y - y1;
  var C = x2 - x1;
  var D = y2 - y1;

  var dot = A * C + B * D;
  var len_sq = C * C + D * D;
  var param = -1;
  if (len_sq != 0) //in case of 0 length line
      param = dot / len_sq;

  var xx, yy;

  var is_vertex = false;
  if (compare_coordinate(x, y, x1, y1)) {
       is_vertex = true;
  }
  if (compare_coordinate(x, y, x2, y2)) {
       is_vertex = true;
  }

  if (param < 0) {
   // is_vertex = true;
    xx = x1;
    yy = y1;
  }
  else if (param > 1) {
 //  is_vertex = true;
    xx = x2;
    yy = y2;
  }
  else {
  //  is_vertex = false;
    xx = x1 + param * C;
    yy = y1 + param * D;
  }

  var dx = x - xx;
  var dy = y - yy;
  return [Sqrt(dx * dx + dy * dy), [xx, yy], is_vertex];
}

// Used to check different empty null states, override of core IsEmpty
function IsEmptyButBetter(data) {
    if (IsEmpty(data)) return true;
    for (var x in data) return false;
    return true;
}
var feat_geo = Geometry($feature);
var lines = FeatureSetByName($map, "linefeature", ["globalId"], false)

var intersected_line = First(Intersects(lines, $feature));
if (intersected_line == null ){
    
    return Geometry($feature);
}
var new_z = get_z_at_location(Geometry(intersected_line),feat_geo)
// NOTE: It would be much better to not assign this rule to the Geometry field and leave the field assignment null
// then use the return edits dictionary to only update the geometry when the Z changes.  This save the edit event in
// an update event scenario.  I just did nto have the time to look up the return edit syntax, exercise is left to the 
// reader
var new_point = Point({
    "x": feat_geo.x,
    "y":feat_geo.y,
    "z": new_z,
    "spatialReference": feat_geo.spatialReference
});
return new_point
StefanAngerer
Occasional Contributor

Hmm, strange. Maybe I have the luck that the line features I am intersecting are all on the same hight? Because I actually managed to get my desired results with the simple code from above. Obiously this approach would fail if there where more vertices with different hight properties. Definitly something I have to consider.

0 Kudos
MikeMillerGIS
Esri Frequent Contributor

Correct, if the line has all the same Z's, easypeasy.  But the reality is that a line may have different z's at every vertex.

StefanAngerer
Occasional Contributor

Alright. In this case I will have a look on that as well, for a more functional solution. Thanks for the help!

0 Kudos