Select to view content in your preferred language

Arcade Error: intersection in the same layer

807
2
02-17-2022 07:28 AM
Labels (1)
AhmedElagroudy
New Contributor

I have 2 layers (pipe layer<line>  and  fitting layer<point>) and the 2 layers is empty 
I assigned an attribute rule to the pipe layer,

this Rule manage me to draw new feature in the pipe layer and
if that new feature intersected with an existed feature in the same layer (pipe layer) => new point will be created and inserted into the fitting layer 

Trigger types: insert and update 

Here is the code:

var pipe = FeatureSetByName($datastore, "pipe")
var existed_feature = Intersects(pipe,$feature)
var new_point = Point(Intersection(First(existed_feature), $feature));
  return {  
    "edit": [
     {
       "className": "test_point",
       "adds": [{
         "geometry":new_point,
       }]
     }
   ]  
};

<< I Get " ✓ Expression valid" message on the rule >>
The issue is, When I start drawing new pipe I get an error 

"Failed to create new feature(s)

invalid geometry[rule name: intersection , trigger event: insert, class name: pipe, GlopalID: **** ]
"
Where is the problem, any help ?


Tags (1)
0 Kudos
2 Replies
KimGarbade
Regular Contributor

I have tried it and I can't get it to work.  I hope I'm missing something simple and that I'm wrong here, but I think the problem is that we are assuming that Intersection is going to return a geometry of type point and I'm not sure from the documentation that it does.

The only work around I can think of is to return the path from $feature using something like this:

var pipeGeom = geometry($feature)
var paths = pipeGeom.paths

Then step through each point (vertice) in the "path" to determine if it intersects a pipe other than $feature.  By this I mean you'll have to do something like this to make sure you don't consider the pipe you are currently entering; because of course all the points on that pipe's "path" will be intersected:

var thisPipe = $feature.GlobalID
var pipe = Filter(FeatureSetByName($datastore, "pipe"),'GlobalID <> @thisPipe') 

When/if you find the point/vertice along the path that intersects another pipe, that will be the geometry you use to "edit:" your point layer.

Again, I hope I am wrong and that I'm missing something simple, but the Arcade documentation for Intersection doesn't mention "if you provide two line geometries as inputs a set of intersection points will be returned"....

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi @AhmedElagroudy  and @KimGarbade ,

When creating Attribute Rules you need to be sure to check for anything that could go wrong along the way:

  • For instance, when drawing your first line or any line that does not intersect another line, this will not return anything in the intersection and therefore "First" will fail.
  • The intersection (and this somewhat surprised me) only seems to work on polygons
  • You cannot cast the result of an intersection to a point

And really, you should take a look at this great repository created by Mike Miller with a lot of examples: https://github.com/MikeMillerGIS/arcade-expressions/tree/master/attribute_rule_calculation 

In order to not overcomplicate the expression I did the following: 

  • Query the pipe featureset for all features that are not the current one
  • Count the result of the intersects and if there is no pipe found (no intersection) do not return anything
  • Create a small buffer of the current feature and of each intersecting pipe,
  • Intersect the polygons
  • Extract the centroid of the intersecting polygon
  • Add the result(s) to an array to allow to add multiple points to the points layer

Some more graphical explanations are below.

The initial situation, lines in blue and intersecting points displayed with red crosses:

XanderBakker_0-1645654735171.png

Start drawing the line and create multiple intersections (only 1 per existing line):

XanderBakker_1-1645654849117.png

The intersecting points are added to the points layer:

XanderBakker_2-1645654891201.png

 

Now there are some things you will have to take into account:

  • The points created are close to the intersection but not necessarily on the intersection since we are using a centroid of a polygon! So if you need the exact intersection you will need to explore the examples on Github to create a much more advanced expression to accomplish this.
  • When your new line crosses an existing line it will create a point in the center of the multiple polygon sin the multipart intersection polygon. To avoid this you could convert the multipart to single-part and loop over each part to create the centroid.

The expression used:

var globid = $feature.GlobalID;
var sql = "GLOBALID <> @globid";
var pipes = Filter(FeatureSetByName($datastore, "pipe"), sql);
if (Count(pipes) > 0) {
var intersecting_features = Intersects(pipes, $feature);
var cnt = Count(intersecting_features);

var adds = [];
if (cnt > 0) {
    var polf = Buffer($feature, 0.1, "m");
    for (var pipe in intersecting_features) {
        var poli = Buffer(pipe, 0.1, "m");
        var polint = Intersection(poli, polf);
        var pnt = Centroid(Polygon(polint));
        Push(adds, {"geometry": pnt});
    }
}

// don't try and return anything when there is no intersection!
if (Count(adds) > 0) {
  return {  
    "edit": [
     {"className": "test_point",
       "adds": adds
     }
   ]};
  }
}