Invalid z-axis geometry when creating features

343
2
Jump to solution
04-06-2022 06:34 AM
by Anonymous User
Not applicable

I have an issue when trying to create features with z-values for sewers using the Utility Network. In this case, I am trying to create sanitary sewer manholes from the Structure Junction > Vault group. I set the elevation in the elevation group of the edit tab. If I put in a whole number (e.g. 620), it will create the feature without problems. It will also take 1/4 values (e.g. 620.25, 620.5, 620.75).  When I try to set it to a number with any other decimal value (e.g. 620.37), I get an error:

Failed to create Manhole.

Invalid Geometry [

Rule name: StructureJunction - Manhole

Elevation Attributes,

Triggering event: Insert,

Class name: StructureJunction

I have checked the Attribute Rules for Structure Junctions and the only apparent rule for the z-value is Round z to 2 sigfigs. I also did not have this issue with the stormwater manholes of the structure junction group, which use the same data type (double) for elevation.

0 Kudos
1 Solution

Accepted Solutions
MikeMillerGIS
Esri Frequent Contributor

It appears to be a change in the Text representation of a geometry.  The M used to be reported as NaN and we were filtering these as the Point constructor fails with a NaN M.  The M is not being returned as Null, so I had to extend the filter logic to also pop null Ms.

 

Line 71 is the only change in case you just want to add that to your code.

 

// Assigned To: StructureJunction
// Type: Calculation
// Name: StructureJunction - Manhole Elevation Attributes
// Description: Set rim elevation, invert elevation, and depth on Sewer Storm Vault - Manhole from the Z value. Update Manhole Channel content feature z value if needed.
// Subtypes: Sewer Storm Vault
// Field:
// Trigger: Insert, Update
// Exclude From Client: True
// Disable: False

// Related Rules: Some rules rely on additional rules for execution. If this rule works in conjunction with another, they are listed below:
//    - None

// Duplicated in: This rule may be implemented on other classes, they are listed here to aid you in adjusting those rules when a code change is required.
//    - None

// *************       User Variables       *************
// This section has the functions and variables that need to be adjusted based on your implementation

// Limit the rule to valid asset types
// ** Implementation Note: Instead of recreating this rule for each asset type, this rules uses a list of domains and exits if not valid
var asset_type = $feature.assettype;
var valid_asset_types = [9];

// The rim elevation, invert elevation and depth field names
var rimelev_fld = "rimelev";
var invertelev_fld = "invertelev";
var depth_fld = "depth";
var depth = $feature.depth;

// The class names of the Manhole Channels
// ** Implementation Note: These are just the class/table name and should not be fully qualified.
var device_class = "SewerDevice";

// Sewer Device - Manhole Channel sql clause
// ** Implementation Note: Sql expression used to find content Manhole Channels to update z value with Invert Elevation value
var manhole_chan_sql = 'AssetGroup in (32) and AssetType in (301, 302)';

// ************* End User Variables Section *************

// *************       Functions            *************

// monikerize FeatureSetByName function
var get_features_switch_yard = FeatureSetByName;

function get_content_manhole_chan() {
    // find Manhole Channel globalid that is content of $feature
    var associations = FeatureSetByAssociation($feature, 'content');
    var filtered = Filter(associations, "className = @device_class");
    var associated_ids = [];
    for (var row in filtered) {
        push(associated_ids, row.globalId)
    }
    if (Count(associated_ids) < 1) return null;
    var device_fs = get_features_switch_yard($datastore, device_class, ["globalid", "assetgroup", 'assettype'], true);
    var content_man_chan = First(Filter(device_fs, "GLOBALID in @associated_ids and " + manhole_chan_sql));
    return iif(IsEmpty(content_man_chan), null, content_man_chan)
}

function update_geom(geo, new_z) {
    // Set z on point to new value
    var geo_dict = Dictionary(Text(geo));
    geo_dict['z'] = new_z;
    return Point(drop_nans(geo_dict))
}

function drop_nans(dict_with_nans) {
    // drop any keys with a value of NaN
    var new_dict = {};
    for (var k in dict_with_nans) {
        if (!IsNan(dict_with_nans[k]) && dict_with_nans[k] !=null ) {
            new_dict[k] = dict_with_nans[k]
        }
    }
    return new_dict
}

// ************* End Functions Section ******************

// Limit the rule to valid asset types
if (!Includes(valid_asset_types, asset_type)) {
    return;
}

// Round z to 2 sigfigs
var geo_z = Geometry($feature).z;
geo_z = Round(geo_z, 2);

// build payload to update rim elevation, invert elevation, depth
if (IsEmpty(depth)) depth = 0;
var res = {"attributes": Dictionary(rimelev_fld, geo_z, invertelev_fld, geo_z - depth, depth_fld, depth)};
var ret = {"result": res};

// Get manhole channel and update z to invertelev
var man_chan = get_content_manhole_chan();
if (!IsEmpty(man_chan)) {
    // if invertelev of Manhole does not match Z of Manhole Channel, update the Manhole Channel
    if (Geometry(man_chan).z != res["attributes"][invertelev_fld]){
        var update_manhole_chan = {
            "globalid": man_chan.globalid,
            'geometry': update_geom(Geometry(man_chan), res["attributes"][invertelev_fld])
        };
        var edit_payload = [{
            'className': device_class,
            'updates': [update_manhole_chan]
        }];
        ret["edit"] = edit_payload
    }
}

return ret;

 

View solution in original post

2 Replies
MikeMillerGIS
Esri Frequent Contributor

It appears to be a change in the Text representation of a geometry.  The M used to be reported as NaN and we were filtering these as the Point constructor fails with a NaN M.  The M is not being returned as Null, so I had to extend the filter logic to also pop null Ms.

 

Line 71 is the only change in case you just want to add that to your code.

 

// Assigned To: StructureJunction
// Type: Calculation
// Name: StructureJunction - Manhole Elevation Attributes
// Description: Set rim elevation, invert elevation, and depth on Sewer Storm Vault - Manhole from the Z value. Update Manhole Channel content feature z value if needed.
// Subtypes: Sewer Storm Vault
// Field:
// Trigger: Insert, Update
// Exclude From Client: True
// Disable: False

// Related Rules: Some rules rely on additional rules for execution. If this rule works in conjunction with another, they are listed below:
//    - None

// Duplicated in: This rule may be implemented on other classes, they are listed here to aid you in adjusting those rules when a code change is required.
//    - None

// *************       User Variables       *************
// This section has the functions and variables that need to be adjusted based on your implementation

// Limit the rule to valid asset types
// ** Implementation Note: Instead of recreating this rule for each asset type, this rules uses a list of domains and exits if not valid
var asset_type = $feature.assettype;
var valid_asset_types = [9];

// The rim elevation, invert elevation and depth field names
var rimelev_fld = "rimelev";
var invertelev_fld = "invertelev";
var depth_fld = "depth";
var depth = $feature.depth;

// The class names of the Manhole Channels
// ** Implementation Note: These are just the class/table name and should not be fully qualified.
var device_class = "SewerDevice";

// Sewer Device - Manhole Channel sql clause
// ** Implementation Note: Sql expression used to find content Manhole Channels to update z value with Invert Elevation value
var manhole_chan_sql = 'AssetGroup in (32) and AssetType in (301, 302)';

// ************* End User Variables Section *************

// *************       Functions            *************

// monikerize FeatureSetByName function
var get_features_switch_yard = FeatureSetByName;

function get_content_manhole_chan() {
    // find Manhole Channel globalid that is content of $feature
    var associations = FeatureSetByAssociation($feature, 'content');
    var filtered = Filter(associations, "className = @device_class");
    var associated_ids = [];
    for (var row in filtered) {
        push(associated_ids, row.globalId)
    }
    if (Count(associated_ids) < 1) return null;
    var device_fs = get_features_switch_yard($datastore, device_class, ["globalid", "assetgroup", 'assettype'], true);
    var content_man_chan = First(Filter(device_fs, "GLOBALID in @associated_ids and " + manhole_chan_sql));
    return iif(IsEmpty(content_man_chan), null, content_man_chan)
}

function update_geom(geo, new_z) {
    // Set z on point to new value
    var geo_dict = Dictionary(Text(geo));
    geo_dict['z'] = new_z;
    return Point(drop_nans(geo_dict))
}

function drop_nans(dict_with_nans) {
    // drop any keys with a value of NaN
    var new_dict = {};
    for (var k in dict_with_nans) {
        if (!IsNan(dict_with_nans[k]) && dict_with_nans[k] !=null ) {
            new_dict[k] = dict_with_nans[k]
        }
    }
    return new_dict
}

// ************* End Functions Section ******************

// Limit the rule to valid asset types
if (!Includes(valid_asset_types, asset_type)) {
    return;
}

// Round z to 2 sigfigs
var geo_z = Geometry($feature).z;
geo_z = Round(geo_z, 2);

// build payload to update rim elevation, invert elevation, depth
if (IsEmpty(depth)) depth = 0;
var res = {"attributes": Dictionary(rimelev_fld, geo_z, invertelev_fld, geo_z - depth, depth_fld, depth)};
var ret = {"result": res};

// Get manhole channel and update z to invertelev
var man_chan = get_content_manhole_chan();
if (!IsEmpty(man_chan)) {
    // if invertelev of Manhole does not match Z of Manhole Channel, update the Manhole Channel
    if (Geometry(man_chan).z != res["attributes"][invertelev_fld]){
        var update_manhole_chan = {
            "globalid": man_chan.globalid,
            'geometry': update_geom(Geometry(man_chan), res["attributes"][invertelev_fld])
        };
        var edit_payload = [{
            'className': device_class,
            'updates': [update_manhole_chan]
        }];
        ret["edit"] = edit_payload
    }
}

return ret;

 

by Anonymous User
Not applicable

Thank you! I made this change and it has fixed the issue.

0 Kudos