[Arcade] Get z-Value from intersecting feature

110
5
11-11-2022 01:38 AM
New Contributor III

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

1 Solution

Accepted Solutions
New Contributor III

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
}

5 Replies
New Contributor III

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
}

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) {
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
var new_point = Point({
"x": feat_geo.x,
"y":feat_geo.y,
"z": new_z,
"spatialReference": feat_geo.spatialReference
});
return new_point``````
New Contributor III

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.

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.

New Contributor III

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