Hello ESRI Forum,
I hope this message finds you well. I am currently working on an UN project where we need to calculate the actual 3D length of line assets when adding point assets to the map. The aim is to automatically connect the point assets to the line assets by adding a vertex to the intersecting line features at a right angle.
I have encountered an issue with the attribute rule that I'm seeking assistance with. While the rule works fine for insert processes, I am facing challenges when updating existing junction features.
The problem arises when the intersecting line features are at the same height. In such cases, only the last and first vertex of the line features are moved along, resulting in incorrect calculations of line lengths. I have tried various approaches but have been unable to resolve this behavior.
To illustrate the issue, let's consider the following scenarios:
1. When the lines are at different heights:
- The second vertex of the deeper green line and the penultimate vertex of the blue height line are moved along accordingly, maintaining the right angle extension to the point feature.



2. When the lines are at the same height:
- Only the last and first vertex of the line features are moved along, resulting in a 3D pipeline that does not accurately represent the desired right angle extension.


I would greatly appreciate any help or insights you can provide to address this issue. Here is an overview of the attribute rule that I have placed on the point feature:
// get line features in a small radius
var lines = FeaturesetByName($datastore, "PipelineLine", ["GlobalID"], true);
var i_lines = Intersects(lines, $feature);
if (i_lines == null) {
return;
}
// create update variable
var updates = [];
// get distances from start and end point
for (var line in i_lines) {
var line_geo = Geometry(line);
var point_geo = Geometry($feature);
var d_start = Distance(point_geo, line_geo.paths[0][0]);
var d_end = Distance(point_geo, line_geo.paths[-1][-1]);
// get the new point coordinates: x/y from the closest line end point, z from the point
var i = IIf(d_start < d_end, 0, -1);
var v = [line_geo.paths[i][i].x, line_geo.paths[i][i].y, point_geo.z, null];
for (var k = 0; k < Count(line_geo.paths[i]); k++) {
if (line_geo.paths[i][k].x == v[0] && line_geo.paths[i][k].y == v[1] && line_geo.paths[i][k].z == v[2]) {
return;
}
}
// add vertex at start or end of line
var new_line_geo = Dictionary(Text(line_geo));
var j = IIf(i == 0, 0, Count(new_line_geo.paths[0]));
Insert(new_line_geo.paths[0], j, v);
var update = {
"globalID": line.GlobalID,
"geometry": Polyline(new_line_geo)
};
Push(updates, update);
}
return {
edit: [{
"className": "PipelineLine",
"updates": updates
}]
};
And i also have a code that lies on the line feature, so that the vertexes also get added when a enduser inserts a new line:
var junctions = FeaturesetByName($datastore, "PipelineJunction", ["GlobalID"], true);
var assemblies = FeaturesetByName($datastore, "PipelineAssembly", ["GlobalID"], true);
var devices = FeaturesetByName($datastore, "PipelineDevice", ["GlobalID"], true);
var intersectingJunctions = Intersects(junctions, $feature);
var intersectingAssemblies = Intersects(assemblies, $feature);
var intersectingDevices = Intersects(devices, $feature);
var pointGeos = [];
// Add the geometries of all intersecting features to an array
if (!isEmpty(intersectingJunctions)) {
for (var junction in intersectingJunctions) {
var fagt = [junction.assetgroup, junction.assettype]
if(arrayIsInArray(fagt, junctionTargets)){
Push(pointGeos, Geometry(junction));
}
}
}
if (!isEmpty(intersectingAssemblies)) {
for (var assembly in intersectingAssemblies) {
var fagt = [assembly.assetgroup, assembly.assettype]
if(arrayIsInArray(fagt, assemblyTargets)){
Push(pointGeos, Geometry(assembly));
}
}
}
if (!isEmpty(intersectingDevices)) {
for (var device in intersectingDevices) {
var fagt = [device.assetgroup, device.assettype]
if(arrayIsInArray(fagt, deviceTargets)){
Push(pointGeos, Geometry(device));
}
}
}
if(isEmpty(pointGeos)){
return;
}
var lineGeo = Geometry($feature);
// Iterate through all intersecting point geometries
for (var i = 0; i < Count(pointGeos); i++) {
var pointGeo = pointGeos[i];
// Calculate distances from the start and end points of the pipeline to the intersection
var d_start = Distance(pointGeo, lineGeo.paths[0][0]);
var d_end = Distance(pointGeo, lineGeo.paths[-1][-1]);
// Determine whether to add the vertex at the start or end of the line
var index = IIf(d_start < d_end, 0, -1);
// Create the vertex coordinates using the intersection and the current Z-coordinate
var v = [lineGeo.paths[index][index].x, lineGeo.paths[index][index].y, pointGeo.z];
// Check if the vertex already exists in the line geometry
var vertexExists = false;
for (var k = 0; k < Count(lineGeo.paths[index]); k++) {
if (lineGeo.paths[index][k].x == v[0] && lineGeo.paths[index][k].y == v[1] && lineGeo.paths[index][k].z == v[2]) {
vertexExists = true;
break;
}
}
// If the vertex does not exist, add it to the line geometry
if (!vertexExists) {
var newLineGeo = Dictionary(Text(lineGeo));
var j = IIf(index == 0, 0, Count(newLineGeo.paths[0]));
Insert(newLineGeo.paths[0], j, v);
lineGeo = Polyline(newLineGeo);
}
}
// Return the modified polyline geometry with the added vertices
return lineGeo;
Thanks in advance and kind regards,
Stefan
PS: I also needed some assistance when creating those rules. Thats the link to the post i made there:
https://community.esri.com/t5/attribute-rules-questions/need-help-with-calculating-3d-length-of-line/m-p/1292037#M924