337
6
05-08-2023 06:53 AM
Occasional Contributor

Working on the attribute rules in the address data management solution v2. The address point rule "Create Site Address Point" is giving me an error about indexing that it difficult to troubleshoot. It seems like this rule is looking for the addressptid created in the Address Point ID rule but not finding it. Any suggestions on getting one rule to initiate before another? Anyone else seen this error?

Here is the rule.

// This rule will create a new site address point when an address point is created along a road
// The site address point will be offset from the road by the distance and direction defined in the address point feature template

// Define the Address Points fields
var offdist_field = "offdist";
var offdir_field = "offdir";
var numpoints_field = "numpoints";
var incrementval_field = "incrementval";
var capturemeth_field = "capturemeth";

// Define the Site Addresses fields
var status_field = "status";
var defaultstatus = "Pending";

// Define the Road Centerline fields
var fullname_field = "fullname";

// This function will return the new point offset perpendicularly from a 2-point line segment at a specified distance
// Positive distance is to the left of the line. Negative distance is to the right of the line
function offsetPoint(firstPoint, secondPoint, fromPoint, dist) {
var x1 = firstPoint.x;
var y1 = firstPoint.y;
var x2 = secondPoint.x;
var y2 = secondPoint.y;
var x3 = fromPoint.x;
var y3 = fromPoint.y;

var a = y1 - y2;
var b = x2 - x1;

var norm = Sqrt(a*a + b*b);
a = a / norm;
b = b / norm;

return [x3 + a * dist, y3 + b * dist]
}

// This function will find the closest point on line_feature from point_feature
function closestPointInfo(point_feature, line_feature) {
var vertices = line_feature["paths"]
var x = point_feature["x"];
var y = point_feature["y"];

// Loop through each part of the geometry and each segment, tracking the shortest distance
var shortest = [1e10];
for (var i in vertices) {
var part = vertices[i];
var previous = part[0];
for (var j = 1; j < Count(part); j++) {
var current = part[j];
var result = pDistance(x, y, previous["x"], previous["y"], current["x"], current["y"]);
if (result[0] < shortest[0]) shortest = result
previous = current;
}

}

// Couldn't find anything
if (Count(shortest) == 1) return null

return {"distance": shortest[0],
"coordinates": shortest[1],
"isVertex": shortest[2],
"lineSide": shortest[3]}
}

// This function will get distance between 2 points
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 = true;
if (param < 0) {
xx = x1;
yy = y1;
}
else if (param > 1) {
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, sideOfLine(x,y,x1,y1,x2,y2)];
}

// This function will get side of line segment that a point (x, y) is on based on the direction of segment [[x1, y1], [x2, y2]]
function sideOfLine(x, y, x1, y1, x2, y2) {

var d = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1)
if (d < 0) {
return 'left'
} else if (d > 0) {
return 'right'
} else {
return null
}
}

// This function will create point geometry from coordinates [x, y]
function createPoint(coordinates, spatial_ref) {
return Point({"x": coordinates[0], "y": coordinates[1], "z" : 0, "spatialReference": spatial_ref})
}

// This function will return the segment intersected and the distance along the line
function intersectDistanceAlong(sourceGeometry, interestedLine){
var distanceAlongLine = 0;
// Loop through the segments of the line. Handle multipart geometries
for (var part in Geometry(interestedLine).paths) {
var segment = Geometry(interestedLine).paths[part];

// Loop through the points in the segment
for (var i in segment) {
if (i == 0) continue;

// Construct a 2-point line segment from the current and previous point
var firstPoint = segment[i-1];
var secondPoint = segment[i]
var twoPointLine = Polyline({ 'paths' : [[[firstPoint.x, firstPoint.y], [secondPoint.x, secondPoint.y]]], 'spatialReference' : firstPoint.spatialReference});

// Test if the point intersects the 2-point line segment
if (Intersects(sourceGeometry, twoPointLine)) {
// Construct a 2-point line segment using the previous point and the address point
var lastSegment = Polyline({ 'paths' : [[[firstPoint.x, firstPoint.y], [sourceGeometry.x, sourceGeometry.y]]], 'spatialReference' : firstPoint.spatialReference});
// Add to the total distance along the line and break the loop
distanceAlongLine += Length(lastSegment);
return [twoPointLine, distanceAlongLine]
}
// Add to the toal distance along the line
distanceAlongLine += Length(twoPointLine);
}
}
return null;
}

// This function will return the address number of the new site address point
// It determines this based on the from and to address range on the intersecting road and the direction of the offset
if (Lower(dir) == 'right') {
}
if (from == null || to == null) return null;
var val = percentAlong * (to - from);

if ((Floor(val) % 2) == 0) addrNum = Floor(val);
else if ((Ceil(val) % 2) == 0) addrNum = Ceil(val);
else addrNum = Floor(val) - 1;

}

var id = \$feature[id_field];

// Get the geometry of the feature
var geom = Geometry(\$feature);

// Get the distance and direction defined in the address point feature template/
// If none specified defaults to 0 and Left
var dist = 0;
if (\$feature[offdist_field] != null) dist = \$feature[offdist_field];
var dir = 'left';
if (\$feature[offdir_field] != null) dir = \$feature[offdir_field];
if (Lower(dir) == 'right') dist *= -1

// Get the number of site address points and increment value from the address point feature template
// Defaults to 1 and 0 respectively
var numpoints = 1;
if (\$feature[numpoints_field] != null) numpoints = \$feature[numpoints_field];
var increment = 0;
if (\$feature[incrementval_field] != null) increment = \$feature[incrementval_field];

// If not creating any site addresses return
if (numpoints < 1) return;

// If no roads intersect, buffer the point to handle cases where point isn't exactly snapped to line and try again
// If no roads intersect the the buffer return an error message and prevent the address point from being created
var intersectingRoads = Intersects(FeatureSetByName(\$datastore, "CenterlinesMSD", [fullname_field, fromleft_field, toleft_field, fromright_field, toright_field], true), geom);
intersectingRoads = Intersects(FeatureSetByName(\$datastore, "CenterlinesMSD", [fullname_field, fromleft_field, toleft_field, fromright_field, toright_field], true), Buffer(geom, 5));
if (Count(intersectingRoads) == 0) return { "errorMessage": "Address Point must intersect at least one Road Centerline" }
}

// Snap the point to the closest place along the line and find the segment it intersects and the distance along the line
var closest_point = createPoint(data["coordinates"], Geometry(\$feature)["spatialReference"])
var twoPtSegment = results[0];
var distanceAlongLine = results[1];

// Construct a new point geometry offset perpendicularly from the road
var xy = offsetPoint(twoPtSegment.paths[0][0], twoPtSegment.paths[0][1], geom, dist)
var newPoint = Point({ 'x' : xy[0], 'y' : xy[1], 'z' : 0, 'spatialReference' : geom.spatialReference });

// Get the new address number of the site address point based on the distance along the road and direction of the offset
var percentAlong = distanceAlongLine / Length(intersectingRoad);

// Create an array of 1 or more new site address point as specified
// Store the related address point id, the calculated address number, the intersecting road name and set the status to Pending
for(var i=0; i<numpoints; i++) {
'attributes': Dictionary(id_field, id, status_field, defaultstatus,
'geometry': newPoint
})
}

// Create new site address points
return {
'edit': [{
}]
}

1 Solution

Accepted Solutions
by
Esri Regular Contributor

@JamesBurton1, I see the issue. There is a bug in my script that we don't typically encounter because in the default schema we have the same field name for the addressptid in both the AddressPoint feature class and the SiteAddressPoint feature class. Looking at your script you have a different name:

// Define the Address Points fields
var offdist_field = "offdist";
var offdir_field = "offdir";
var numpoints_field = "numpoints";
var incrementval_field = "incrementval";
var capturemeth_field = "capturemeth";

// Define the Site Addresses fields

The issue occurs later in the expression when we attempt to create a new SiteAddressPoint, I am referencing the id_field variable from the AddressPoint feature class rather than the addressptid variable for the SiteAddressPoint feature class:

'attributes': Dictionary(id_field, id, status_field, defaultstatus,
'geometry': newPoint
})

This is why it is saying the index addressptid doesn't exist, because that field doesn't exist in the SiteAddressPoint feature class. If you change that section of code to below, it should work:

'geometry': newPoint
})

6 Replies
Esri Contributor

I suspect that you need to include an Expects declaration at the top of the attribute rule since fields are being called from \$feature via bracket notation.

``Expects(\$feature, "addressptid", "offdist", "offdir", "numpoints", "incrementval", "capturemeth")``

And this to "Address Point ID"

``Expects(\$feature, "addressptid")``

Occasional Contributor

Thanks for the reply @TedHoward2. I tried adding these to both rules but I'm still getting the same indexing error.

Occasional Contributor

@ChrisFox have you seen this indexing error before?

by
Esri Regular Contributor

@JamesBurton1, I see the issue. There is a bug in my script that we don't typically encounter because in the default schema we have the same field name for the addressptid in both the AddressPoint feature class and the SiteAddressPoint feature class. Looking at your script you have a different name:

// Define the Address Points fields
var offdist_field = "offdist";
var offdir_field = "offdir";
var numpoints_field = "numpoints";
var incrementval_field = "incrementval";
var capturemeth_field = "capturemeth";

// Define the Site Addresses fields

The issue occurs later in the expression when we attempt to create a new SiteAddressPoint, I am referencing the id_field variable from the AddressPoint feature class rather than the addressptid variable for the SiteAddressPoint feature class:

'attributes': Dictionary(id_field, id, status_field, defaultstatus,
'geometry': newPoint
})

This is why it is saying the index addressptid doesn't exist, because that field doesn't exist in the SiteAddressPoint feature class. If you change that section of code to below, it should work:

'geometry': newPoint
})

Occasional Contributor

You're the man @ChrisFox, that solved my indexing error. Thanks!

by
Esri Regular Contributor

@JamesBurton1, I see the issue. There is a bug in my script that we don't typically encounter because in the default schema we have the same field name for the addressptid in both the AddressPoint feature class and the SiteAddressPoint feature class. Looking at your script you have a different name:

// Define the Address Points fields
var offdist_field = "offdist";
var offdir_field = "offdir";
var numpoints_field = "numpoints";
var incrementval_field = "incrementval";
var capturemeth_field = "capturemeth";

// Define the Site Addresses fields

The issue occurs later in the expression when we attempt to create a new SiteAddressPoint, I am referencing the id_field variable from the AddressPoint feature class rather than the addressptid variable for the SiteAddressPoint feature class:

'attributes': Dictionary(id_field, id, status_field, defaultstatus,