import arcpy
import os
from env_setup import environment_setup
from custom_tools.general_tools import custom_arcpy
from file_manager.n100.file_manager_rivers import River_N100
from input_data import input_n50
from custom_tools.general_tools.file_utilities import FeatureClassCreator
[docs]
def main():
environment_setup.main()
prepare_data()
create_collapsed_centerline()
filter_complicated_lakes()
# create_feature_class()
input_water_polygon = River_N100.centerline_pruning_loop__lake_features__n100.value
input_centerline = River_N100.river_centerline__water_feature_collapsed__n100.value
input_rivers = (
River_N100.centerline_pruning_loop__rivers_erased_with_lake_features__n100.value
)
water_polygon = River_N100.centerline_pruning_loop__water_features_processed__n100.value
centerline = River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value
rivers = River_N100.centerline_pruning_loop__river_inlets_erased__n100.value
complex_lakes = River_N100.centerline_pruning_loop__complex_water_features__n100.value
simple_lakes = River_N100.centerline_pruning_loop__simple_water_features__n100.value
river_inlet_nodes = (
River_N100.centerline_pruning_loop__river_inlets_points_merged__n100.value
)
complex_centerlines = (
River_N100.centerline_pruning_loop__complex_centerlines__n100.value
)
simple_centerlines = River_N100.centerline_pruning_loop__simple_centerlines__n100.value
[docs]
def prepare_data():
sql_expression_water_features = "OBJTYPE = 'FerskvannTørrfall' Or OBJTYPE = 'Innsjø' Or OBJTYPE = 'InnsjøRegulert' 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.centerline_pruning_loop__lake_features__n100.value,
)
arcpy.analysis.PairwiseErase(
in_features=River_N100.unconnected_river_geometry__river_area_selection__n100.value,
erase_features=River_N100.centerline_pruning_loop__lake_features__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__rivers_erased_with_lake_features__n100.value,
)
print(
f"Created {River_N100.river_centerline__rivers_near_waterfeatures_erased__n100.value}"
)
arcpy.analysis.PairwiseBuffer(
in_features=input_rivers,
out_feature_class=River_N100.centerline_pruning_loop__study_area__n100.value,
buffer_distance_or_field="5 Kilometers",
dissolve_option="ALL",
)
print("Created study area buffer")
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=input_water_polygon,
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=River_N100.centerline_pruning_loop__study_area__n100.value,
output_name=River_N100.centerline_pruning_loop__water_features_study_area__n100.value,
)
arcpy.gapro.DissolveBoundaries(
input_layer=River_N100.centerline_pruning_loop__water_features_study_area__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__water_features_dissolved__n100.value,
)
print("Dissolved water features boundaries")
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=River_N100.centerline_pruning_loop__water_features_dissolved__n100.value,
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=input_rivers,
output_name=River_N100.centerline_pruning_loop__water_features_dissolved_river_intersect__n100.value,
)
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=input_water_polygon,
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=River_N100.centerline_pruning_loop__water_features_dissolved_river_intersect__n100.value,
output_name=River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value,
)
sql_expression_torrfall = "OBJTYPE = 'FerskvannTørrfall'"
custom_arcpy.select_attribute_and_make_feature_layer(
input_layer=River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value,
expression=sql_expression_torrfall,
output_name=f"{River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value}_torrfall",
)
sql_expression_elvbekk = "OBJTYPE = 'ElvBekk'"
custom_arcpy.select_attribute_and_make_feature_layer(
input_layer=River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value,
expression=sql_expression_elvbekk,
output_name=f"{River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value}_elvbekk",
)
arcpy.topographic.EliminatePolygon(
in_features=f"{River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value}_torrfall",
surrounding_features=f"{River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value}_elvbekk",
)
sql_expression_small_features = "shape_Area <= 100000"
custom_arcpy.select_attribute_and_make_feature_layer(
input_layer=River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value,
expression=sql_expression_small_features,
output_name=f"{River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value}_small_features",
)
arcpy.Eliminate_management(
in_features=f"{River_N100.centerline_pruning_loop__water_features_river_final_selection__n100.value}_small_features",
out_feature_class=River_N100.centerline_pruning_loop__water_features_processed__n100.value,
selection="LENGTH",
)
arcpy.PolygonToLine_management(
in_features=River_N100.centerline_pruning_loop__water_features_processed__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__polygon_to_line__n100.value,
neighbor_option="IDENTIFY_NEIGHBORS",
)
arcpy.management.AddSpatialJoin(
target_features=River_N100.centerline_pruning_loop__polygon_to_line__n100.value,
join_features=River_N100.centerline_pruning_loop__water_features_processed__n100.value,
join_operation=None,
join_type="KEEP_ALL",
match_option="LARGEST_OVERLAP",
permanent_join="PERMANENT_FIELDS",
)
sql_expression_boundaries = "LEFT_FID <> -1 AND RIGHT_FID <> -1"
custom_arcpy.select_attribute_and_make_permanent_feature(
input_layer=River_N100.centerline_pruning_loop__polygon_to_line__n100.value,
expression=sql_expression_boundaries,
output_name=River_N100.centerline_pruning_loop__water_features_shared_boundaries__n100.value,
)
arcpy.management.FeatureVerticesToPoints(
in_features=River_N100.centerline_pruning_loop__water_features_shared_boundaries__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__shared_boundaries_midpoint__n100.value,
point_location="MID",
)
[docs]
def create_collapsed_centerline():
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=input_rivers,
overlap_type=custom_arcpy.OverlapType.BOUNDARY_TOUCHES.value,
select_features=River_N100.centerline_pruning_loop__water_features_processed__n100.value,
output_name=River_N100.centerline_pruning_loop__river_inlets__n100.value,
)
arcpy.analysis.PairwiseErase(
in_features=River_N100.centerline_pruning_loop__river_inlets__n100.value,
erase_features=River_N100.centerline_pruning_loop__water_features_processed__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__river_inlets_erased__n100.value,
)
print(
f"Created {River_N100.river_centerline__rivers_near_waterfeatures_erased__n100.value}"
)
# Copy to rename the file to have less characters in the name since the name needs to fit inside a field in CollapseHydroPolygon
arcpy.management.CopyFeatures(
in_features=River_N100.centerline_pruning_loop__water_features_processed__n100.value,
out_feature_class=River_N100.short_name__water__n100.value,
)
print(f"Created {River_N100.short_name__water__n100.value}")
arcpy.cartography.CollapseHydroPolygon(
in_features=River_N100.short_name__water__n100.value,
out_line_feature_class=River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value,
connecting_features=River_N100.centerline_pruning_loop__river_inlets_erased__n100.value,
merge_adjacent_input_polygons="MERGE_ADJACENT",
)
print(
f"Created {River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value}"
)
arcpy.management.FeatureVerticesToPoints(
in_features=River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__collapsed_hydropolygon_points__n100.value,
point_location="BOTH_ENDS",
)
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=River_N100.centerline_pruning_loop__collapsed_hydropolygon_points__n100.value,
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=River_N100.centerline_pruning_loop__water_features_shared_boundaries__n100.value,
output_name=River_N100.centerline_pruning_loop__collapsed_hydropolygon_points_selected__n100.value,
)
arcpy.edit.Snap(
in_features=River_N100.centerline_pruning_loop__shared_boundaries_midpoint__n100.value,
snap_environment=[
[
River_N100.centerline_pruning_loop__collapsed_hydropolygon_points_selected__n100.value,
"END",
"3000 Meters",
]
],
)
extract_closed_lines(
River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value,
River_N100.centerline_pruning_loop__closed_centerline_lines__n100.value,
)
arcpy.management.FeatureVerticesToPoints(
in_features=River_N100.centerline_pruning_loop__closed_centerline_lines__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__closed_centerline_point__n100.value,
point_location="END",
)
[docs]
def filter_complicated_lakes():
arcpy.management.FeatureVerticesToPoints(
in_features=River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value,
out_feature_class=River_N100.centerline_pruning_loop__centerline_start_end_vertex__n100.value,
point_location="BOTH_ENDS",
)
arcpy.management.DeleteIdentical(
in_dataset=River_N100.centerline_pruning_loop__centerline_start_end_vertex__n100.value,
fields="Shape",
)
arcpy.management.FeatureVerticesToPoints(
in_features=River_N100.centerline_pruning_loop__collapsed_hydropolygon__n100.value,
out_feature_class=f"{River_N100.centerline_pruning_loop__river_inlet_dangles__n100.value}_not_selected",
point_location="DANGLE",
)
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=f"{River_N100.centerline_pruning_loop__river_inlet_dangles__n100.value}_not_selected",
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=River_N100.centerline_pruning_loop__river_inlets_erased__n100.value,
output_name=River_N100.centerline_pruning_loop__river_inlet_dangles__n100.value,
)
arcpy.management.Merge(
inputs=[
River_N100.centerline_pruning_loop__shared_boundaries_midpoint__n100.value,
River_N100.centerline_pruning_loop__river_inlet_dangles__n100.value,
],
output=River_N100.centerline_pruning_loop__river_inlets_points_merged__n100.value,
)
print(
"NB! Need to create a logic to fix missing inlet nodes between interconnected waterfeature polygons"
)
"""
Currently it only makes one node between two water features but some places this would lead to missing node connections
as more nodes are needed.
"""
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=River_N100.centerline_pruning_loop__centerline_start_end_vertex__n100.value,
overlap_type=custom_arcpy.OverlapType.INTERSECT.value,
select_features=River_N100.centerline_pruning_loop__river_inlets_points_merged__n100.value,
output_name=River_N100.centerline_pruning_loop__centerline_intersection_vertex__n100.value,
inverted=True,
)
arcpy.management.Merge(
inputs=[
River_N100.centerline_pruning_loop__centerline_intersection_vertex__n100.value,
River_N100.centerline_pruning_loop__closed_centerline_point__n100.value,
],
output=River_N100.centerline_pruning_loop__intersection_points_merged__n100.value,
)
intersection_field = "intersection"
river_inlet_field = "inlets"
arcpy.AddField_management(
in_table=River_N100.centerline_pruning_loop__intersection_points_merged__n100.value,
field_name=intersection_field,
field_type="LONG",
)
arcpy.CalculateField_management(
in_table=River_N100.centerline_pruning_loop__intersection_points_merged__n100.value,
field=intersection_field,
expression=1,
)
arcpy.AddField_management(
in_table=River_N100.centerline_pruning_loop__river_inlets_points_merged__n100.value,
field_name=river_inlet_field,
field_type="LONG",
)
arcpy.CalculateField_management(
in_table=River_N100.centerline_pruning_loop__river_inlets_points_merged__n100.value,
field=river_inlet_field,
expression=1,
)
target_features = (
River_N100.centerline_pruning_loop__water_features_processed__n100.value
)
join_features_1 = (
River_N100.centerline_pruning_loop__river_inlets_points_merged__n100.value
)
join_features_2 = (
River_N100.centerline_pruning_loop__intersection_points_merged__n100.value
)
# First Spatial Join - Adding river inlet data
field_mappings = arcpy.FieldMappings()
field_mappings.addTable(target_features)
field_mappings.addTable(join_features_1)
# Setup field mapping for river_inlet_field (assuming sum_inlets is the intended outcome)
# Note: Corrected to ensure we're modifying the correct field mapping
inlet_field_index = field_mappings.findFieldMapIndex(river_inlet_field)
if inlet_field_index != -1:
field_map = field_mappings.getFieldMap(inlet_field_index)
field = field_map.outputField
field.name = "sum_inlets"
field.aliasName = "Sum of Inlets"
field_map.outputField = field
field_map.mergeRule = "Sum"
field_mappings.replaceFieldMap(inlet_field_index, field_map)
# Execute the first spatial join
arcpy.analysis.SpatialJoin(
target_features=target_features,
join_features=join_features_1,
out_feature_class=f"{target_features}_add_join_1",
join_operation="JOIN_ONE_TO_ONE",
join_type="KEEP_ALL",
field_mapping=field_mappings,
match_option="INTERSECT",
)
# Second Spatial Join - Adding intersection data
field_mappings_2 = arcpy.FieldMappings()
field_mappings_2.addTable(f"{target_features}_add_join_1")
field_mappings_2.addTable(join_features_2)
# Setup field mapping for intersection_field (assuming sum_intersection is the intended outcome)
# Corrected to focus on intersection_field
intersection_field_index = field_mappings_2.findFieldMapIndex(intersection_field)
if intersection_field_index != -1:
field_map = field_mappings_2.getFieldMap(intersection_field_index)
field = field_map.outputField
field.name = "sum_intersection"
field.aliasName = "Sum of Intersection"
field_map.outputField = field
field_map.mergeRule = "Sum"
field_mappings_2.replaceFieldMap(intersection_field_index, field_map)
# Execute the second spatial join
arcpy.analysis.SpatialJoin(
target_features=f"{target_features}_add_join_1",
join_features=join_features_2,
out_feature_class=River_N100.centerline_pruning_loop__water_feature_summarized__n100.value,
join_operation="JOIN_ONE_TO_ONE",
join_type="KEEP_ALL",
field_mapping=field_mappings_2,
match_option="INTERSECT",
)
# Use CalculateField to set null ("sum_intersection" = <NULL>) values to 0
arcpy.CalculateField_management(
in_table=River_N100.centerline_pruning_loop__water_feature_summarized__n100.value,
field="sum_intersection",
expression="0 if !sum_intersection! is None else !sum_intersection!",
expression_type="PYTHON3",
)
sql_simple_water_features = (
"(sum_intersection < sum_inlets) OR (sum_intersection = 1 AND sum_inlets = 1)"
)
custom_arcpy.select_attribute_and_make_permanent_feature(
input_layer=River_N100.centerline_pruning_loop__water_feature_summarized__n100.value,
expression=sql_simple_water_features,
output_name=River_N100.centerline_pruning_loop__simple_water_features__n100.value,
)
sql_complex_water_features = "(sum_intersection >= sum_inlets) AND (sum_intersection <> 1 OR sum_inlets <> 1)"
custom_arcpy.select_attribute_and_make_permanent_feature(
input_layer=River_N100.centerline_pruning_loop__water_feature_summarized__n100.value,
expression=sql_complex_water_features,
output_name=River_N100.centerline_pruning_loop__complex_water_features__n100.value,
)
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=centerline,
overlap_type=custom_arcpy.OverlapType.HAVE_THEIR_CENTER_IN.value,
select_features=River_N100.centerline_pruning_loop__simple_water_features__n100.value,
output_name=River_N100.centerline_pruning_loop__simple_centerlines__n100.value,
)
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=centerline,
overlap_type=custom_arcpy.OverlapType.HAVE_THEIR_CENTER_IN.value,
select_features=River_N100.centerline_pruning_loop__complex_water_features__n100.value,
output_name=River_N100.centerline_pruning_loop__complex_centerlines__n100.value,
)
create_lake_centerline_feature = FeatureClassCreator(
template_fc=input_rivers,
input_fc=River_N100.centerline_pruning_loop__simple_centerlines__n100.value,
output_fc=River_N100.centerline_pruning_loop__finnished_centerlines__n100.value,
object_type="POLYLINE",
delete_existing=True,
)
create_lake_centerline_feature.run()
[docs]
def create_feature_class():
# create_lake_centerline_feature = FeatureClassCreator(
# template_fc=input_rivers,
# input_fc=River_N100.centerline_pruning_loop__simple_centerlines__n100.value,
# output_fc=River_N100.centerline_pruning_loop__finnished_centerlines__n100.value,
# object_type="POLYLINE",
# delete_existing=True,
# )
# create_lake_centerline_feature.run()
input_feature_class = (
River_N100.centerline_pruning_loop__water_features_processed__n100.value
)
dissolve_output = f"{input_feature_class}_dissolved"
arcpy.analysis.PairwiseDissolve(
in_features=input_feature_class,
out_feature_class=dissolve_output,
dissolve_field=["shape_Length", "shape_Area"],
multi_part="MULTI_PART",
)
eliminate_polygon_part_output = f"{input_feature_class}_eliminate_polygon_part"
arcpy.management.EliminatePolygonPart(
in_features=dissolve_output,
out_feature_class=eliminate_polygon_part_output,
condition="AREA_OR_PERCENT",
part_area="1000000",
part_area_percent="99",
part_option="CONTAINED_ONLY",
)
polygon_islands = f"{input_feature_class}_polygon_islands"
custom_arcpy.select_location_and_make_permanent_feature(
input_layer=input_feature_class,
overlap_type=custom_arcpy.OverlapType.COMPLETELY_WITHIN.value,
select_features=eliminate_polygon_part_output,
output_name=polygon_islands,
)
arcpy.topographic.EliminatePolygon(
in_features=polygon_islands,
surrounding_features=input_feature_class,
)
if __name__ == "__main__":
main()