Source code for generalization.n100.river.unconnected_river_geometry
import arcpy
import multiprocessing
from multiprocessing import Pool, Manager
import config
from env_setup import environment_setup
from input_data import input_n50
from custom_tools.general_tools import custom_arcpy
from file_manager.n100.file_manager_rivers import River_N100
[docs]
def main():
geomotry_search_tolerance = 15
id_field = "orig_ob_id"
dangle_id_field = "dang_id"
cpu_usage_percentage = 0.9
num_cores = int(multiprocessing.cpu_count() * cpu_usage_percentage)
environment_setup.main()
copy_input_features(geomotry_search_tolerance)
# Feature classes
buffer_fc = River_N100.unconnected_river_geometry__river_dangles_buffer__n100.value
line_fc = River_N100.unconnected_river_geometry__unsplit_river_features__n100.value
polygon_fc = (
River_N100.unconnected_river_geometry__water_area_features_selected__n100.value
)
point_fc = River_N100.unconnected_river_geometry__river_dangles__n100.value
# Determine total number of buffers
total_buffers = int(arcpy.GetCount_management(buffer_fc)[0])
# Define the percentage of the dataset to process in each batch (e.g., 25%)
batch_percentage = 0.05
batch_size = int(total_buffers * batch_percentage)
# Prepare arguments for each batch
batch_args = [
(
start,
min(start + batch_size, total_buffers),
line_fc,
polygon_fc,
buffer_fc,
id_field,
dangle_id_field,
)
for start in range(0, total_buffers, batch_size)
]
print("starting processing unconnected river geometry loop...")
with Manager() as manager:
shared_results = manager.list() # Shared list for results
queue = manager.Queue() # Manager Queue for progress tracking
# Include both shared_results and queue in the tuples
args_with_shared_results = [(*arg, shared_results, queue) for arg in batch_args]
with Pool(processes=num_cores) as pool:
pool.starmap(process_batch, args_with_shared_results)
all_problematic_ids = list(shared_results)
print("All problematic IDs:", all_problematic_ids)
try:
resolve_geometry(id_field, dangle_id_field, all_problematic_ids)
except Exception as e:
print("Error in resolve_geometry:", e)
[docs]
def copy_input_features(geomotry_search_tolerance):
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=input_n50.ElvBekk,
overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE.value,
select_features=config.river_sprint_feature,
output_name=River_N100.unconnected_river_geometry__river_area_selection__n100.value,
search_distance="500 Meters",
)
arcpy.UnsplitLine_management(
in_features=River_N100.unconnected_river_geometry__river_area_selection__n100.value,
out_feature_class=River_N100.unconnected_river_geometry__unsplit_river_features__n100.value,
)
print(
f"Created {River_N100.unconnected_river_geometry__unsplit_river_features__n100.value}"
)
id_field = "orig_ob_id"
arcpy.AddField_management(
in_table=River_N100.unconnected_river_geometry__unsplit_river_features__n100.value,
field_name=id_field,
field_type="LONG",
)
arcpy.CalculateField_management(
in_table=River_N100.unconnected_river_geometry__unsplit_river_features__n100.value,
field=id_field,
expression="!OBJECTID!",
)
print(f"Added field orig_ob_id")
sql_expression_water_features = f"OBJTYPE = 'FerskvannTørrfall' Or OBJTYPE = 'Innsjø' Or OBJTYPE = 'InnsjøRegulert' Or OBJTYPE = 'Havflate' Or OBJTYPE = 'ElvBekk'"
custom_arcpy.select_attribute_and_make_permanent_feature(
input_layer=input_n50.ArealdekkeFlate,
expression=sql_expression_water_features,
output_name=River_N100.unconnected_river_geometry__water_area_features__n100.value,
)
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=River_N100.unconnected_river_geometry__water_area_features__n100.value,
overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE.value,
select_features=River_N100.unconnected_river_geometry__unsplit_river_features__n100.value,
output_name=River_N100.unconnected_river_geometry__water_area_features_selected__n100.value,
search_distance=f"{geomotry_search_tolerance} Meters",
)
arcpy.management.FeatureVerticesToPoints(
in_features=River_N100.unconnected_river_geometry__unsplit_river_features__n100.value,
out_feature_class=River_N100.unconnected_river_geometry__river_dangles__n100.value,
point_location="DANGLE",
)
print(f"Created {River_N100.unconnected_river_geometry__river_dangles__n100.value}")
dangle_id_field = "dang_id"
arcpy.AddField_management(
in_table=River_N100.unconnected_river_geometry__river_dangles__n100.value,
field_name=dangle_id_field,
field_type="LONG",
)
arcpy.CalculateField_management(
in_table=River_N100.unconnected_river_geometry__river_dangles__n100.value,
field=dangle_id_field,
expression="!OBJECTID!",
)
print(f"Added field dang_id")
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=River_N100.unconnected_river_geometry__river_dangles__n100.value,
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=River_N100.unconnected_river_geometry__water_area_features_selected__n100.value,
output_name=River_N100.unconnected_river_selected_river_dangles__n100.value,
inverted=True,
)
arcpy.analysis.PairwiseBuffer(
in_features=River_N100.unconnected_river_selected_river_dangles__n100.value,
out_feature_class=River_N100.unconnected_river_geometry__river_dangles_buffer__n100.value,
buffer_distance_or_field=f"{geomotry_search_tolerance} Meters",
)
print(
f"Created {River_N100.unconnected_river_geometry__river_dangles_buffer__n100.value}"
)
# Feature classes
buffer_fc = River_N100.unconnected_river_geometry__river_dangles_buffer__n100.value
line_fc = River_N100.unconnected_river_geometry__unsplit_river_features__n100.value
polygon_fc = (
River_N100.unconnected_river_geometry__water_area_features_selected__n100.value
)
point_fc = River_N100.unconnected_river_selected_river_dangles__n100.value
[docs]
def process_batch(
start,
end,
line_fc,
polygon_fc,
buffer_fc,
id_field,
dangle_id_field,
shared_results,
queue,
):
lines = [
(row[0], row[1]) for row in arcpy.da.SearchCursor(line_fc, [id_field, "SHAPE@"])
]
polygons = [row[0] for row in arcpy.da.SearchCursor(polygon_fc, ["SHAPE@"])]
query = f"OBJECTID >= {start} AND OBJECTID < {end}"
with arcpy.da.SearchCursor(
buffer_fc, [id_field, dangle_id_field, "SHAPE@"], where_clause=query
) as buffer_cursor:
for buffer_row in buffer_cursor:
buffer_id, dangle_id, buffer_geom = buffer_row
line_intersect = any(
line_id != buffer_id
and (
not buffer_geom.disjoint(line_geom)
or buffer_geom.touches(line_geom)
)
for line_id, line_geom in lines
)
polygon_intersect = any(
not buffer_geom.disjoint(poly_geom) or buffer_geom.touches(poly_geom)
for poly_geom in polygons
)
if line_intersect or polygon_intersect:
buffer_id, dangle_id, buffer_geom = buffer_row
shared_results.append((buffer_id, dangle_id))
queue.put(1)
[docs]
def resolve_geometry(
id_field,
dangle_id_field,
all_problematic_ids,
):
# Check if the list is empty
if not all_problematic_ids:
print("No problematic IDs found.")
return
# Separate id_field and dangle_id_field values
line_ids = {item[0] for item in all_problematic_ids} # Extract unique line IDs
dangle_ids = {item[1] for item in all_problematic_ids} # Extract unique dangle IDs
# Convert list of line IDs to a comma-separated string
line_ids_string = ", ".join(map(str, line_ids))
print("Line IDs SQL Query String:", line_ids_string)
# Construct the SQL query for line IDs
sql_line_problematic_ids = f"{id_field} IN ({line_ids_string})"
print("Line IDs SQL Query:", sql_line_problematic_ids)
# Convert list of dangle IDs to a comma-separated string
dangle_ids_string = ", ".join(map(str, dangle_ids))
print("Dangle IDs SQL Query String:", dangle_ids_string)
# Construct the SQL query for dangle IDs
sql_dangle_problematic_ids = f"{dangle_id_field} IN ({dangle_ids_string})"
print("Dangle IDs SQL Query:", sql_dangle_problematic_ids)
# Selection and creation of features for flagged problematic geometry
if line_ids:
custom_arcpy.select_attribute_and_make_permanent_feature(
input_layer=River_N100.unconnected_river_geometry__unsplit_river_features__n100.value,
expression=sql_line_problematic_ids,
output_name=River_N100.unconnected_river_geometry__problematic_river_lines__n100.value,
)
# Proceed with the selection and creation of features for dangles
if dangle_ids:
custom_arcpy.select_attribute_and_make_permanent_feature(
input_layer=River_N100.unconnected_river_geometry__river_dangles__n100.value,
expression=sql_dangle_problematic_ids,
output_name=River_N100.unconnected_river_geometry__problematic_river_dangles__n100.value,
)
if __name__ == "__main__":
main()