|
POST
|
OK for the "m", but the null check really should not work. Curious... Anyway, here is one way to solve your problem: // load the two (or more) feature classes
var featuresets = [
FeaturesetByName($datastore, "TestLines"),
FeaturesetByName($datastore, "TestPolygons"),
]
// get the id of the closest feature in a 1 meter radius
var f_buffer = Buffer($feature, 1, "meters")
var smallest_distance = 1000
var id = null
for(var i in featuresets) {
var i_fs = Intersects(featuresets[i], f_buffer)
for(var f in i_fs) {
var d = Distance(f, $feature, "meters")
if(d >= smallest_distance) { continue }
smallest_distance = d
id = f.id
}
}
return id Basically, this adds another for loop around your lines 11-23 to take care of different featuresets. Personally, I like to write out custom Sort()s in a for loop (that is what happens under the hood in your code anyway) because then I can see what's happening all in one place. Plus, because I set the output variable to default to null (line 9), I can eliminate the null check at the end.
... View more
01-24-2023
06:38 AM
|
0
|
1
|
2286
|
|
POST
|
In which table do you want to create the validation rule?
... View more
01-24-2023
04:12 AM
|
0
|
0
|
1635
|
|
POST
|
It's possible, just a little more complicated. Instead of getting the First() intersecting feature, you need to get all of them, and then get the one with the greatest intersection length / area. // load the other featureset
var fs = FeatureSetByName($datastore, "Highways.HIGHWAYMGR.ElectoralDivisions")
// get all features from fs that intersect the current $feature
var i_fs = Intersects(fs, $feature)
// find the ElectDiv of the feature with the greatest intersection with $feature
var greatest = 0
var electdiv = null
for(var i_f in i_fs) {
var current = Length(Intersection($feature, i_f))
if(current <= greatest) { continue }
greatest = current
electdiv = i_f.ElectDiv
}
return electdiv If both featuresets ($featureset and fs) are polygon fcs, you should use Area() instead of Length() in line 9.
... View more
01-24-2023
02:44 AM
|
0
|
2
|
1483
|
|
POST
|
How should the extraced value look? Do you want the id of the closest feature, no matter if it's a point or line? Or do you want something like "closestpoint.id, closestline.id" Things I noticed at a first glance: GYinspIntersection and GYfeaturesWithDistances are not defined Buffer and Distance have a unit attribute that takes the following values: feet | kilometers | miles | nautical-miles | meters | yards. You supply "m". I haven't tested if that works as replacement for "meters", but it's best to avoid undocumented features. Your null check is the wrong way around. Either check for !IsEmpty(...) (is not empty) or swap lines 37 and 40.
... View more
01-24-2023
02:23 AM
|
0
|
1
|
2314
|
|
POST
|
To post code: Overlaps takes two geometries/features as arguments. You are trying to run it with two featuresets. You have to get the intersecting features first, then loop over those features and test if they overlap the current $feature. // get all polygons that are intersected by the current feature
var fs_polygons = FeaturesetByName($datastore, "HydrographySrf", ["*"], true)
var i_polygons = Intersects($feature, fs_polygons)
// loop over those polygons
for(var i_poly in i_polygons) {
// if the polygon overlaps the current feature
if(Overlaps($feature, i_poly)) {
return false
}
}
return true
... View more
01-23-2023
11:45 PM
|
0
|
0
|
1642
|
|
POST
|
Oh wow, I somehow never knew about this... Time to break some apps while trying to fix some insignificant details...
... View more
01-23-2023
02:21 PM
|
0
|
0
|
1295
|
|
POST
|
Arcade is your friend here. // extract the line's start and end points
var start_point = Geometry($feature).paths[0][0]
var end_point = Geometry($feature).paths[-1][-1]
// load the point fc
var point_fc = FeaturesetByName($datastore, "TestPoints", ["TextField"], false)
// get the intersecting points' names
var i_start = First(Intersects(start_point, point_fc))
var i_end = First(Intersects(end_point, point_fc))
var names = [
IIf(i_start == null, "", i_start.TextField),
IIf(i_end == null, "", i_end.TextField),
]
// concatenate and return
return Concatenate(names, "") Change the names of the point fc and the name field in lines 6, 12, and 13. You can use this expression in the field calculator (switch to Arcade) or in an Attribute Rule.
... View more
01-23-2023
11:51 AM
|
1
|
0
|
1230
|
|
POST
|
Hey, welcome to the Community! What product are you working with? ArcGIS Pro? Is this a one-time operation or do you need that to calculate automatically?
... View more
01-23-2023
11:03 AM
|
0
|
1
|
1253
|
|
POST
|
Ah, I somehow missed the part where you say that you want to update the domain. In ArcGIS, domains are handled differently from tables. Notably here, the arcpy.da.*Cursor classes only work on tables/feature classes, not on domains. To work with domains, you need the tools from the Data management/Domains toolset. Something like this should work: import arcpy
import csv
# set the variables
csv_path = r"G:\ArcGIS\data\streetname.csv"
gdb = r"G:\ArcGIS\projects\Test\Test.gdb"
domain_name = "TestDomain"
# start the csv reader and skip header
with open(csv_path, "r") as csv_file:
reader = csv.reader(csv_file)
next(reader)
# loop over the csv rows and write the values into the domain
for code, description in reader:
arcpy.management.AddCodedValueToDomain(gdb, domain_name, code, description)
... View more
01-23-2023
10:23 AM
|
1
|
1
|
5188
|
|
POST
|
You iterate over the csv file, but arcpy expects you to iterate over the UpdateCursor. Are you sure UpdateCursor is what you need? It seems like you could actually want InsertCursor.
... View more
01-23-2023
08:55 AM
|
0
|
3
|
5220
|
|
POST
|
Hmm, the way I see it, there are at least 2 options. Option 1: Don't use batching, use multivalue parameters. class SomeTool:
label = "SomeTool"
def getParameterInfo(self):
return [
arcpy.Parameter(name="raster", displayName="Raster", datatype="DERasterDataset", parameterType="Required", direction="Input", multiValue=True),
arcpy.Parameter(name="csv", displayName="Output CSV", datatype="DEFile", parameterType="Required", direction="Output"),
]
def execute(self, parameters, messages):
par = {p.name: p for p in parameters}
rasters = str(par["raster"].value).split(";")
with open(str(par["csv"].value), "w") as csv_file:
csv_file.write("Header line\n")
for raster in rasters:
# extract and write for each raster
csv_file.write(str(raster) + "\n") Option 2, if you really want to batch: Check if the output csv exists. If not, create it and write the header line. Then use append mode to write the extracted raster values.
... View more
01-22-2023
11:14 PM
|
1
|
0
|
1296
|
|
POST
|
Copy/paste this script into the Python Window, change the name of the layer, execute river_id = 0
with arcpy.da.UpdateCursor("NameOfTheLayer", ["segmentInd", "RiverID"]) as cursor:
for row in cursor:
if row[0] == 0:
river_id += 1
cursor.updateRow([row[0], river_id])
... View more
01-20-2023
05:03 AM
|
2
|
1
|
3268
|
|
POST
|
Manual linebreaks You can insert linebreaks into a text field by pressing Shift + Enter. Automatic linebreaks Using Arcade, you can automatically insert linebreaks. You can use these expressions in popups (somehow it does not work in the Pro popup...), in attribute rules, or in the field calculator. Option 1: line break after certain symbols var symbols = [".", ";"]
var t = $feature.TextField
for(var i in symbols) {
var s = symbols[i]
var lbs = s + "\n"
t = Replace(t, lbs, s) // remove manual breaks to avoid empty lines
t = Concatenate(Split(t, s), lbs)
}
return t Option 2: line break after a certain length var words = Split($feature.TextField, " ")
var max_length = 20
var t = ""
var l = 0
for(var i in words) {
var word = words[i] + " "
l += Count(word)
if(l <= max_length) {
t += word
} else {
t += TextFormatting.NewLine + word
l = 0
}
}
return t Here's how the two options look in a MapViewer popup:
... View more
01-20-2023
04:26 AM
|
2
|
1
|
2618
|
|
POST
|
While you won't get around doing things manually, you can at least make it easier. Label your features with the area That way you don't have to switch tools. The label won't update while you modify vertices, so you still have to complete the edit before seeing the new area. Use a label expression like this: Round(Area($feature, "square-meters"), 2) + " m²" Use Attribute Rules Create a new double field in you polygon feature class. This field will store the target area. Create an Attribute Rule for your polygon feature class. Use this expression (use the new field's name in line 7!): // Calculation Attribute Rule
// field: Shape
// Triggers: Insert, Update
// if you did not specify a target area, return the current geometry
var target_area = $feature.DoubleField
if(target_area == null) { return Geometry($feature) }
// these two parameters specify how close the rule will get to your target area
// the rule will keep on trying to get to your target area until one condition is met:
// either the relative error (target-current)/target drops below max_rel_error
// or the number of tries goes above max_iter.
// at that point, the rule returns the current try.
// decreasing max_rel_error and increasing max_iter returns better results, but it takes much more time.
var max_rel_error = 0.001
var max_iter = 200
var current_geometry = Geometry($feature)
var rel_error = (target_area - Area(current_geometry, "square-meters")) / target_area
for(var iter = 0; iter < max_iter; iter++) {
current_geometry = Buffer(current_geometry, rel_error, "meters")
rel_error = (target_area - Area(current_geometry, "square-meters")) / target_area
if(Abs(rel_error) <= max_rel_error) { break }
}
return current_geometry The workflow would be something like this: create a rough outline of where you want the trees to be Change the value of your target area field (DoubleField in my test data). The rule triggers and tries to get the polygon as close to the target area as possible. Delete the target area value. That hinders the rule from constantly changing you polygon in the next step. Use the Edit Vertices tool to iteratively change vertices until you hit your target area. Remember, the label isn't updated while you drag a vertex, so you will have to complete the edit to see the new area.
... View more
01-20-2023
03:21 AM
|
0
|
1
|
6319
|
|
POST
|
OK, so using the geometries to do this turns out to be a bit more complicated than Touches()... A line completely lies on a polygon's boundary if each vertex of the line touches the polygon there are no polygon vertices that do not touch the line inbetween vertices that do Maybe it can be done easier, but that's the way it worked for my test cases... // get all intersecting polygons
var polygons = FeaturesetByName($datastore, "TestPolygons")
var i_polygons = Intersects(polygons, $feature)
for(var i_poly in i_polygons) {
// check if each vertex of $feature is on boundary
// if not, go to the next i_poly
var vertices = Geometry($feature).paths[0]
var vertices_on_boundary = true
for(var v in vertices) {
if(!Touches(vertices[v], i_poly)) {
vertices_on_boundary = false
break
}
}
if(!vertices_on_boundary) { continue }
// check if there are polygon vertices that do not touch the line inbetween vertices that do
// if not, the line coincides with the polygon boundary
var vertices = Geometry(i_poly).rings[0]
var status = "not touching"
for(var v in vertices) {
if(Intersects(vertices[v], $feature)) {
if(status == "not touching") { status = "touching" }
if(status == "not touching anymore") { status = "error"; break }
} else {
if(status == "touching") { status = "not touching anymore" }
}
}
if(status != "error") { return 1 }
}
return 0 But it can be done much, muuuuch easier with @MikeMillerGIS 's suggestion of Relate. The DE-9IM model is completely new to me, but I found the right expression quite fast by drawing the matrix. var polygons = FeaturesetByName($datastore, "TestPolygons")
var i_polygons = Intersects(polygons, $feature)
for(var i_poly in i_polygons) {
if(Relate(i_poly, $feature, "FF*TT*FF*")) { return 1 }
}
return 0
... View more
01-20-2023
01:43 AM
|
1
|
0
|
2333
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 01-30-2023 09:57 AM | |
| 1 | 05-18-2023 12:51 AM | |
| 1 | 03-05-2023 12:46 PM | |
| 1 | 12-07-2022 07:01 AM | |
| 1 | 06-21-2022 08:27 AM |
| Online Status |
Offline
|
| Date Last Visited |
02-03-2024
06:14 PM
|