Hi everybody,
I prepared an attribute rule (batch) that will transfer the attributes in the "OutrunNumber" field in the Device layer to the "OutrunNumber" field in the Electric Line layer. It transfers this information to the line that intersects with the device layer. But the line consists of more than one piece. How can I transfer this information to the following parts?
I want to transfer this information to the green line and the following lines in the screenshot, how can I do this.
var fc_OutRunNumber = FeatureSetByName($datastore, "main.ElectricDevice", ["OutrunNumber"] ,false)
var fc_MVS = Filter(fc_OutRunNumber,"ASSETGROUP in (37)")
var fc_Line_Intersect = Intersects(fc_MVS,$feature)
var fc_Outrun = First(fc_Line_Intersect)
if (fc_Outrun == null) return {"errorMessege": "OutrunNumber Not Found"}
return fc_Outrun.OutrunNumber
Solved! Go to Solution.
Ah, OK. For that, you need 2 rules (you should be able to do it in one, but I couldn't get it to work correctly, and it doesn't really matter).
The first rule is a variation of the rule in my previous answer. Instead of only calculating the OutrunNumber for Medium Voltage conductors, it will calculate for all conductor types (but it will skip connectors, banks, etc). And instead of traversing a line, it will traverse a network.
// Batch Calculation Attribute rule on ElectricLine
// field: OutrunNumber
// subtype: empty
// exclude from application evaluation
// Not a conductor? -> abort
if(!Includes([6, 9, 2], $feature.ASSETGROUP)) { return $feature.OutrunNumber }
// load all conductors and devices (split into switches and others)
// 6: Low, 9: Medium, 2: High voltage conductor
var conductors = Filter($featureset, "ASSETGROUP IN (6, 9, 2)")
// 23: Low, 37: Medium, 10: High voltage switch
var devices = FeatureSetByName($datastore, "ElectricDevice", ["OutrunNumber", "GlobalID"], false)
var switches = Filter(devices, "ASSETGROUP IN (23, 37, 10)")
var other_devices = Filter(devices, "ASSETGROUP NOT IN (23, 37, 10)")
// get the touching switch
var out_switch = First(Intersects(switches, $feature))
// no intersecting switch? -> abort
// the OutrunNumber will be supplied by the Feature that touches a mv switch
if(out_switch == null || IsEmpty(out_switch.OutrunNumber)) { return $feature.OutrunNumber }
// traverse the conductor network
var c_to_do = [$feature] // conductor features that need to be processed
var c_globalids = [] // GlobalIDs of already processed conductors
for(var i = 0; i < 9999; i++) {
var current_conductor = Pop(c_to_do)
Push(c_globalids, current_conductor.GlobalID)
for(var next_conductor in Touches(conductors, current_conductor)) {
if(!Includes(c_globalids, next_conductor.GlobalID)) {
Push(c_to_do, next_conductor)
}
}
if(Count(c_to_do) == 0) { break }
}
var conductor_updates = []
//var device_updates = []
var new_att = {OutrunNumber: out_switch.OutrunNumber}
for(var i in c_globalids) {
Push(conductor_updates, {globalID: c_globalids[i], attributes: new_att})
}
return {
result: out_switch.OutrunNumber,
edit: [{
className: "ElectricLine",
updates: conductor_updates
}]
}
The second rule copies the OutrunNumber from an ElectricLine feature to all intersecting ElectricDevice features.
// Batch Calculation Attribute Rule on ElectricLine
// field: OutrunNumber
// subtype: empty
// exclude from application evaluation
// Not a conductor? -> abort
if(!Includes([6, 9, 2], $feature.ASSETGROUP)) { return $feature.OutrunNumber }
// load all devices, filter out switches
var devices = FeatureSetByName($datastore, "ElectricDevice", ["GlobalID"], true)
devices = Filter(devices, "ASSETGROUP NOT IN (23, 37, 10)")
var device_updates = []
for(var device in Intersects(devices, $feature)) {
var update = {globalID: device.GlobalID, attributes: {OutrunNumber: $feature.OutrunNumber}}
Push(device_updates, update)
}
return {
result: $feature.OutrunNumber,
edit: [{
className: "ElectricDevice",
updates: device_updates
}]
}
The order of these rules is important! First, the OutrunNumber has to be calculated for the Lines, then it has to be copied to the Devices.
Be sure to not select a subtype.
How do you get the other lines? Do they have a common attribute?
Yes OutrunNumber field is common attribute. My goal is to calculate the OutrunNumber attributes written in the Device feature to the entire all line.
Thank you,
Hmm, so you can't use OutrunNumber to get the other line parts.
In that case you need to use the geometries, which will be more complicated. If you could upload a part of your two feature classes (either here or in a private message), that would be helpful.
Does this come close to what you want to do?
@GIS_Solutions sent me an excerpt of their data. For context:
// Batch Calculation Attribute Rule
// feature class: "ElectricalLine"
// subtype: "Medium Voltage Conductor"
// field: "OutrunNumber"
// exlude from application evaluation
// load the medium voltage switches
var devices = FeatureSetByName($datastore, "ElectricDevice", ["OutrunNumber"], false)
var mv_switches = Filter(devices, "ASSETGROUP = 37")
// get the touching switch
var mv_switch = First(Intersects(mv_switches, $feature))
// no intersecting switch? -> abort
// the OutrunNumber will be supplied by the Feature that touches a mv switch
if(mv_switch == null || IsEmpty(mv_switch.OutrunNumber)) { return $feature.OutrunNumber }
// load all medium voltage conductors
var mv_conductors = Filter($featureset, "ASSETGROUP = 9")
// traverse the line, get all GlobalIDs
var globalids = []
var current_conductor = $feature
for(var i = 0; i < 9999; i++) { // Arcade has no while loop, so we have to fake it with a loooong for loop and a break
// get the next mv conductor
// conditions: it touches the current test feature and hasn't been tested yet
Push(globalids, current_conductor.GlobalID)
var touching_conductors = Touches(mv_conductors, current_conductor)
current_conductor = null
for(var next_conductor in touching_conductors) {
if(!Includes(globalids, next_conductor.GlobalID)) {
current_conductor = next_conductor
break
}
}
if(current_conductor == null) { break }
}
// construct the update instruction
var updates = []
for(var i in globalids) {
var update = {globalID: globalids[i], attributes: {OutrunNumber: mv_switch.OutrunNumber}}
Push(updates, update)
}
return {
result: mv_switch.OutrunNumber,
edit: [{
className: "ElectricLine",
updates: updates
}]
}
The data you sent me was in a FGDB, but your code suggests an EGDB. Change the table names in lines 10 & 52 to match your database schema.
I have absolutely no idea why, but this rule will only work once (at least in the FGDB you sent me, maybe it's corrupted or this is expected behavior for batch rules). To run it again, follow these steps:
Really thank you so much. I tried the code you gave, it worked very well.
I want to transfer the OutrunNumer attribute on all spatial connected feature. There may be many more feature like this, so any advice you can give me? My goal is to transfer the value in the mv_switch.OutrunNumber (Device Feature) feature to all the feature on the cable that are spatially connected to it.
Ah, OK. For that, you need 2 rules (you should be able to do it in one, but I couldn't get it to work correctly, and it doesn't really matter).
The first rule is a variation of the rule in my previous answer. Instead of only calculating the OutrunNumber for Medium Voltage conductors, it will calculate for all conductor types (but it will skip connectors, banks, etc). And instead of traversing a line, it will traverse a network.
// Batch Calculation Attribute rule on ElectricLine
// field: OutrunNumber
// subtype: empty
// exclude from application evaluation
// Not a conductor? -> abort
if(!Includes([6, 9, 2], $feature.ASSETGROUP)) { return $feature.OutrunNumber }
// load all conductors and devices (split into switches and others)
// 6: Low, 9: Medium, 2: High voltage conductor
var conductors = Filter($featureset, "ASSETGROUP IN (6, 9, 2)")
// 23: Low, 37: Medium, 10: High voltage switch
var devices = FeatureSetByName($datastore, "ElectricDevice", ["OutrunNumber", "GlobalID"], false)
var switches = Filter(devices, "ASSETGROUP IN (23, 37, 10)")
var other_devices = Filter(devices, "ASSETGROUP NOT IN (23, 37, 10)")
// get the touching switch
var out_switch = First(Intersects(switches, $feature))
// no intersecting switch? -> abort
// the OutrunNumber will be supplied by the Feature that touches a mv switch
if(out_switch == null || IsEmpty(out_switch.OutrunNumber)) { return $feature.OutrunNumber }
// traverse the conductor network
var c_to_do = [$feature] // conductor features that need to be processed
var c_globalids = [] // GlobalIDs of already processed conductors
for(var i = 0; i < 9999; i++) {
var current_conductor = Pop(c_to_do)
Push(c_globalids, current_conductor.GlobalID)
for(var next_conductor in Touches(conductors, current_conductor)) {
if(!Includes(c_globalids, next_conductor.GlobalID)) {
Push(c_to_do, next_conductor)
}
}
if(Count(c_to_do) == 0) { break }
}
var conductor_updates = []
//var device_updates = []
var new_att = {OutrunNumber: out_switch.OutrunNumber}
for(var i in c_globalids) {
Push(conductor_updates, {globalID: c_globalids[i], attributes: new_att})
}
return {
result: out_switch.OutrunNumber,
edit: [{
className: "ElectricLine",
updates: conductor_updates
}]
}
The second rule copies the OutrunNumber from an ElectricLine feature to all intersecting ElectricDevice features.
// Batch Calculation Attribute Rule on ElectricLine
// field: OutrunNumber
// subtype: empty
// exclude from application evaluation
// Not a conductor? -> abort
if(!Includes([6, 9, 2], $feature.ASSETGROUP)) { return $feature.OutrunNumber }
// load all devices, filter out switches
var devices = FeatureSetByName($datastore, "ElectricDevice", ["GlobalID"], true)
devices = Filter(devices, "ASSETGROUP NOT IN (23, 37, 10)")
var device_updates = []
for(var device in Intersects(devices, $feature)) {
var update = {globalID: device.GlobalID, attributes: {OutrunNumber: $feature.OutrunNumber}}
Push(device_updates, update)
}
return {
result: $feature.OutrunNumber,
edit: [{
className: "ElectricDevice",
updates: device_updates
}]
}
The order of these rules is important! First, the OutrunNumber has to be calculated for the Lines, then it has to be copied to the Devices.
Be sure to not select a subtype.
Codes works fine, thank you for your support @JohannesLindner
As far as I understand, it is necessary to determine which entities the attribute should be transferred to with the filter function.
Correct.
In the first rule in line 13, I specify that the OutrunNumber should only be copied to conductors. If you want other line assets to have the OutrunNumber, too, include them in that Filter().
In the second rule in line 12, I exclude switches from the targets, because that's where the OutrunNumber comes from. We don't want to overwrite that... If you want to exclude other point assets (or only want to include certain asset types), do it in that Filter().