Select to view content in your preferred language

checking for array containment

1006
6
Jump to solution
04-26-2023 04:54 AM
StefanAngerer
Regular Contributor

Hey Esri community!

I'm hoping someone can help me out with a little problem I'm having. I'm trying to create an attribute rule that only allows certain assets to be created if they're either at the start or end of a line, or not on a line at all.

To do this, I need to check an array of arrays to see if another freshly built array is contained within it. Is this even possible?

If anyone has any suggestions or solutions, I'd be really grateful! Thanks in advance for any help you can give.

This is the code i currently have:

// Define target asset groups and types as touples
var tagt = [
[3, 957], // asset 1
[900, 901], // asset 2
[910, 911], // asset 3
[950, 951], // asset 4
[13, 710] // asset 5
];

// Create touple of feature asset group and type
var fagt = [$feature.assetgroup, $feature.assettype]

// Check if current feature triggers attribute rule
if (Includes(tagt, fagt)){

// Get pipeline features from datastore
var pipelines = FeatureSetByName($datastore, "PipelineLine", ["globalId"], false);

// Get all intersecting pipeline features
var intersectingPipes = Intersects(pipelines, $feature);

// If no line is intersected, allow edit process
if (isEmpty(intersectingPipes)){
return true;
} else {
// Else, iterate over inersecting pipeline features
for (var pipe in intersectingPipes) {
// Get start and endpoint of intersected line feature
var endPoint = Geometry(pipe).paths[-1][-1];
var startPoint = Geometry(pipe).paths[0][0];

// Check if the current feature intersects start or endpoint of line
if (Intersects(endPoint, $feature)) {
// If yes, allow edit process
return true;
} else if (Intersects(startPoint, $feature)) {
// If yes, allow edit process
return true;
}
}
// Else, hinder edit process
return false;
}
} else {
return true;
}

0 Kudos
1 Solution

Accepted Solutions
StefanAngerer
Regular Contributor

Hi all,

in the end this code managed to do what i want.

// Define target asset groups and types as touples
var tagt = [
			[3, 957],		
			[900, 901],		
			[910, 911],		
			[950, 951],		
			[13, 710]		
		];
		
// Create touple of feature asset group and type 
var fagt = [$feature.assetgroup, $feature.assettype]

// Function to check if an array is contained in an array of arrays
function arrayIsInArray(arrayToCheck, arrayContainingArrays)
{
	for(var i in arrayContainingArrays)
	{
		var currentArray = arrayContainingArrays[i]
		if(Count(currentArray) == Count(arrayToCheck))
		{
			var allValuesMatch = true; 
			for(var j in arrayToCheck)
			{
				if(currentArray[j] != arrayToCheck[j])
				{
					allValuesMatch = false; 
					break
				}
			}
			if(allValuesMatch)
            	{
               		return true;
            	}
		}
	}
	return false;
}

// Check if current feature triggers attribute rule
if (arrayIsInArray(fagt, tagt)){

	// Get pipeline features from datastore
	var pipelines = FeatureSetByName($datastore, "PipelineLine", ["*"], true);
		
	// Get all intersecting pipeline features
	var intersectingPipes = Intersects(pipelines, $feature);

	// If no line is intersected, allow edit process
	if (count(intersects(pipelines, geometry($feature))) == 0){
		return true;
	} else {
		// Else, iterate over intersecting pipeline features
		for (var pipe in intersectingPipes) {
			// Get start and endpoint of intersected line feature
			var endPoint = Geometry(pipe).paths[-1][-1];
			var startPoint = Geometry(pipe).paths[0][0];

			// Check if the current feature intersects start or endpoint of line
			if (Intersects(endPoint, $feature)) {
				// If yes, allow edit process
				return true;
			} else if (Intersects(startPoint, $feature)) {
				// If yes, allow edit process
				return true; 
			}
		}
		// Else, hinder edit process
		return false; 
	}	
} else {
	return true; 
}

 

Some rather interessting remarks:

-it seems like that the geometry parameter at featuresetbyname hasnt any impact if intersections are possible to detect or not. i tried it with false and with true, both times it worked just fine.

-the only way to actually detect an intersect was with line 50. all other methods with e.g. (if(Intersects(pipelines, $feature))) wouldnt work for whatever reason 

PS: has anybody a idea where to console messages actually go to? I cant find any terminal in arcpro which makes debugging a real pain.

View solution in original post

0 Kudos
6 Replies
JohannesLindner
MVP Alum

To post code:

JohannesLindner_0-1677736512957.png

JohannesLindner_1-1677736529803.png

 

function ArrayEquals(arr_1, arr_2) {
    if(Count(arr_1) != Count(arr_2)) { return false }
    arr_1 = Sort(arr_1)
    arr_2 = Sort(arr_2)
    for(var i in arr_1) {
        if(arr_1[i] != arr_2[i]) { return false }
    }
    return true
}
function IncludesArray(outer, inner) {
    for(var i in outer) {
        if(ArrayEquals(outer[i], inner)) { return true }
    }
    return false
}


if (IncludesArray(tagt, fagt)){
//...

Have a great day!
Johannes
MikeMillerGIS
Esri Frequent Contributor

It is hard to follow posted as text, but it looks pretty good.  The only change I see is that your FSByName is not returning geometry, which is probably why any downstream intersect fails

 

change:

var pipelines = FeatureSetByName($datastore, "PipelineLine", ["globalId"], false);

to

var pipelines = FeatureSetByName($datastore, "PipelineLine", ["globalId"], true);

0 Kudos
JohannesLindner
MVP Alum

Yes, the geometry has to be included in this case.

But Stefan's code didn't even get to that point, because the Includes function doesn't work for inner array:

JohannesLindner_0-1682517086698.png

 


Have a great day!
Johannes
0 Kudos
StefanAngerer
Regular Contributor

Thanks for the tip with inserting code @JohannesLindner ! And also thanks for mentioning the Geometry Bug @MikeMillerGIS . Is there any way to check the containment of inner arrays? or do i have to implement this myself?

Greets
Stefan!

0 Kudos
StefanAngerer
Regular Contributor

Hi all,

in the end this code managed to do what i want.

// Define target asset groups and types as touples
var tagt = [
			[3, 957],		
			[900, 901],		
			[910, 911],		
			[950, 951],		
			[13, 710]		
		];
		
// Create touple of feature asset group and type 
var fagt = [$feature.assetgroup, $feature.assettype]

// Function to check if an array is contained in an array of arrays
function arrayIsInArray(arrayToCheck, arrayContainingArrays)
{
	for(var i in arrayContainingArrays)
	{
		var currentArray = arrayContainingArrays[i]
		if(Count(currentArray) == Count(arrayToCheck))
		{
			var allValuesMatch = true; 
			for(var j in arrayToCheck)
			{
				if(currentArray[j] != arrayToCheck[j])
				{
					allValuesMatch = false; 
					break
				}
			}
			if(allValuesMatch)
            	{
               		return true;
            	}
		}
	}
	return false;
}

// Check if current feature triggers attribute rule
if (arrayIsInArray(fagt, tagt)){

	// Get pipeline features from datastore
	var pipelines = FeatureSetByName($datastore, "PipelineLine", ["*"], true);
		
	// Get all intersecting pipeline features
	var intersectingPipes = Intersects(pipelines, $feature);

	// If no line is intersected, allow edit process
	if (count(intersects(pipelines, geometry($feature))) == 0){
		return true;
	} else {
		// Else, iterate over intersecting pipeline features
		for (var pipe in intersectingPipes) {
			// Get start and endpoint of intersected line feature
			var endPoint = Geometry(pipe).paths[-1][-1];
			var startPoint = Geometry(pipe).paths[0][0];

			// Check if the current feature intersects start or endpoint of line
			if (Intersects(endPoint, $feature)) {
				// If yes, allow edit process
				return true;
			} else if (Intersects(startPoint, $feature)) {
				// If yes, allow edit process
				return true; 
			}
		}
		// Else, hinder edit process
		return false; 
	}	
} else {
	return true; 
}

 

Some rather interessting remarks:

-it seems like that the geometry parameter at featuresetbyname hasnt any impact if intersections are possible to detect or not. i tried it with false and with true, both times it worked just fine.

-the only way to actually detect an intersect was with line 50. all other methods with e.g. (if(Intersects(pipelines, $feature))) wouldnt work for whatever reason 

PS: has anybody a idea where to console messages actually go to? I cant find any terminal in arcpro which makes debugging a real pain.

0 Kudos
MikeMillerGIS
Esri Frequent Contributor

At 3.1, the FSByName geometry parameter is required to be set correctly, before that, I believe it was ignored or it did not matter for intersect, but it does now.

 

It is expensive performance wise to call count on a featureset and then loop over it.  Best to just loop over it and do nothing if there are no iterations.

 

This is better

// Get pipeline features from datastore
var pipelines = FeatureSetByName($datastore, "PipelineLine", ["*"], true);
    
// Get all intersecting pipeline features
var intersectingPipes = Intersects(pipelines, $feature);
var no_intersect = true
// Else, iterate over intersecting pipeline features
for (var pipe in intersectingPipes) {
    no_intersect = false
    // Get start and endpoint of intersected line feature
    var endPoint = Geometry(pipe).paths[-1][-1];
    var startPoint = Geometry(pipe).paths[0][0];

    // Check if the current feature intersects start or endpoint of line
    if (Intersects(endPoint, $feature)) {
        // If yes, allow edit process
        return true;
    } else if (Intersects(startPoint, $feature)) {
        // If yes, allow edit process
        return true; 
    }
}
// Else, hinder edit process
return no_intersect; 
}