Address Data Management Solution; Using Your Schema

3737
8
08-03-2020 03:08 PM
JoeBorgione
MVP Emeritus
2 8 3,737

I've been wrestling with the Address Data Management Solution for some time, and today, I finally got the toughest rule to work with my attributes: Split Intersecting Roads.  This rule is a really powerful editing tool as it will split an existing centerline into two segments when you add a new street that intersects it.  In essence it:

 

  1. Copies attributes from the original existing street to the 'new segment'
  2. Does a proportional division of the address ranges so you don't have to

 

To begin with, you need to  create a list of the attributes you want to copy during the split.  This is done near the top of the script:

The orginal looks like this:

var centerline_field_names = ["rclnguid", "discrpagid", "rangeprefixleft", "fromleft",
 "toleft", "parityleft", "rangeprefixright", "fromright", "toright", "parityright",
 "fullname","fedroute", "fedrtetype", "afedrte", "afedrtetype", "stroute", "strtetype",
 "astrte", "astrtetype", "ctyroute", "onewaydir", "roadlevel", "inwater", "roadclass",
 "countryleft", "countryright", "stateleft", "stateright", "countyleft",
 "countyright","munileft", "muniright", "zipleft", "zipright", "msagleft", "msagright",
 "esnleft", "esnright"]

Mine looks like this:

var centerline_field_names = ["FROMADDR_L","TOADDR_L","FROMADDR_R","TOADDR_R","PREDIR",
"NAME","POSTTYPE","POSTDIR","FULLNAME","AN_NAME","AN_POSTDIR","ALIAS_NAME",
"LABEL","CITYCODE_L","CITYCODE_R","ZIPCODE_L","ZIPCODE_R","INCMUNI_L",
"INCMUNI_R","UNINCCOM_L","UNINCCOM_R","ONEWAY","SPEED_LMT","STATUS",
"CARTOCODE","DOT_RD","DOT_HWYNAM","DOT_SRFTYP","DOT_CLASS","VERT_LEVEL",
"SOURCE","COMMENTS","asset_id","Condition","Year_Installed","Carto_ID",
"Pave_Area","Pave_Width"]
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I used the arcpy.ListFields() function and a little text formatting in python to generate the list.  Something to take note of is the attribute names provided in the solution are all lower case and you can see mine are upper case as well as proper case. More on this further down. 

 

Any reference to the feature class name needs to be adjusted: 

There are two references to the feature class name:

var intersectingRoads = Intersects(FeatureSetByName($datastore, "RoadCenterline"), geom);

and down at the bottom of the script:

'edit': [{'className': 'RoadCenterline', 'adds': adds, 'updates': updates}]

Mine looks like this:

var intersectingRoads = Intersects(FeatureSetByName($datastore, "MSD.SLCOMSD.CenterlinesMSD"), geom);

and

edit': [{'className': 'MSD.SLCOMSD.CenterlinesMSD', 'adds': adds, 'updates': updates}]
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

My lines 11 and 15 show the full feature class name with Owner.Database as part of the name since I'm doing the edits in an Enterprise GBD (aka SDE); if you are using a file gdb, you'll only need the feature class name.

 

About midway down in the script, a series of variables are set to the field names where your address range info is stored:

 

The original references these attributes:


        // Get the address range of the intersecting road
        var fromRight = road.fromright;
        var toRight = road.toright;
        var fromLeft = road.fromleft;
        var toLeft = road.toleft;

While I reference:

        var fromRight = road.FROMADDR_R;
        var toRight = road.TOADDR_R;
        var fromLeft = road.FROMADDR_L;
        var toLeft = road.TOADDR_L;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

A little further down in the script, there are references again to the address range variables that get written to a dictionary:

 

The original:

  var attributes = {}
  if (newToFromRight[0] != null) attributes['toright'] = newToFromRight[0];
  if (newToFromLeft[0] != null) attributes['toleft'] = newToFromLeft[0];

And mine:

  var attributes = {}
  if (newToFromRight[0] != null) attributes['TOADDR_R'] = newToFromRight[0];
  if (newToFromLeft[0] != null) attributes['TOADDR_L'] = newToFromLeft[0];‍‍‍‍‍‍‍‍‍‍‍

 

As mentioned earlier, how you have your attribute names with respect to upper, lower, or proper case is an issue you need to deal with.  If all your field names are lower case, this isn't an issue for you.  But it is for me:

 

The original script uses a Lower() function three times:

        for (var k in featureAttributes) {
            if (Lower(k) == "fromright" && newToFromRight[1] != null) {
                newAttributes['fromright'] = newToFromRight[1];
            } else if (Lower(k) == "fromleft" && newToFromLeft[1] != null) {
                newAttributes['fromleft'] = newToFromLeft[1];
            } else if (IndexOf(centerline_field_names, Lower(k)) > -1 && featureAttributes != null) {
                newAttributes = featureAttributes;
            } else {
    continue;

But the Lower() function trips with my schema, so I just remove them 
while again referencing my address range fields:

        var newAttributes = {};
        for (var k in featureAttributes) {
            if (k == "FROMADDR_R" && newToFromRight[1] != null) {
                newAttributes['FROMADDR_R'] = newToFromRight[1];
            } else if (k == "FROMADDR_L" && newToFromLeft[1] != null) {
                newAttributes['FROMADDR_L'] = newToFromLeft[1];
            } else if (IndexOf(centerline_field_names, k) > -1 && featureAttributes != null) {
                newAttributes = featureAttributes;
            } else {
    continue;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

Finally, I don't have a field called centerlineid but I do have field that is used in a similar fashion called UNIQUE_ID.  In the solution, the centerlines feature class related to the Alias Road Name table through the centerlineid field. And, that centerlineid field is updated with a Database Sequence.  If you plan to use centerlineid in your application, you are just fine.  However, if you are using another field name you'll need to perform a search and replace on centerlineid in the scipt and replace it with your attribute name.  You'll also need to add that attribute name to the Alias Road Name table so the relationship class works.

 

None of this would have been possible without a boat load of help and even more patience from Chris Fox‌.  Thanks Chris!

8 Comments
JoshSaad1
Occasional Contributor II

Have you ever had a situation where you need a new road segment to split an existing road segment in two places?  This has been driving me nuts for a couple of weeks now.  I could swear I was able to do it before, but it's not working now.

I've got a new road segment that intersects an existing road segment in two places.  When I draw it in, it splits at the first intersection, but it won't split the second.

Looking at the attribute rule, it has the following code:

// If the road was created from a split its id will have a prefix of '::'
// Don't process any futher splits to prevent getting in an infinite loop
var id = $feature.centerlineid;
if (Left(id, 2) == "::") return id;

I guess that means it'll only do one split.  I just think it's a little weird because it's not uncommon for a road to intersect another in multiple places.  It's not a big problem, I can just split it myself and adjust the address ranges, but I was hoping this solution would have automated that.

JoeBorgione
MVP Emeritus

I haven't had that issue (yet).  What if you add the new road with only one end intersecting the existing road, save, and then extend the new road to the second intersection?  Or add the new road with one intersection, then add a second new road to the other intersection; then merge the two new roads as one?

Chris Fox

JoshSaad1
Occasional Contributor II

Yeah, that's what I settled on last week. I stopped my line short of the second intersection, added a new line segment, and then merged it in.

Thanks.

JoeBorgione
MVP Emeritus

From your illustration, it looks like that particular subdivision is going to require a bunch of slicing and dicing.

JoshSaad1
Occasional Contributor II

Actually the road segments in the middle weren't a problem because they only intersect each of the other road segments in one place, so they split normally.  It was just the one that split the other in two places that was the issue.  

LeahJones_MSB
New Contributor

@ChrisFox , do you have a thought on @JoshSaad1 and @JoeBorgione's comments above.  We ran into the exact same issue.  We were also wondering along with there recommendations if we could not just copy code from the create new road rule to give the multiple splits a different ID or is there some purposeful reason we would want to keep the same Road Segment of the split lines?  

The example that Josh showed above is exactly our same issue.

Thanks so much!

RichardOwens
New Contributor II

I was also wondering about this as I am currently trying to get this tool to work with our data in a FGD.  I am trying to make sure that it works before I connect it to the SDE Database.

RichardOwens
New Contributor II

I have worked through this code a couple of times and have been unsuccessful it getting it to work with my data.  Is there something else that I am missing that I should be doing.  I have very little experience working with Arcade and I am not sure what I am looking for that I should be doing!

Any Help is appreciated!

About the Author
Started with ArcInfo Version 4.5 on a Unix box, and have the gray hair to show for it. After spending several years in State Government I moved into the 911 dispatch arena. After a 14 year stint as a contract employee, I have returned to the public sector as GIS analyst in a metropolitan county in Utah.
Labels