diff --git a/custom_tools/custom_arcpy.py b/custom_tools/custom_arcpy.py index 2b58ee85..79318a75 100644 --- a/custom_tools/custom_arcpy.py +++ b/custom_tools/custom_arcpy.py @@ -197,10 +197,10 @@ def select_location_and_make_feature_layer( Example: >>> custom_arcpy.select_location_and_make_feature_layer( - ... input_layer=Building_N100.data_preparation___large_enough_polygon___n100_building.value, + ... input_layer=Building_N100.data_preparation___polygons_that_are_large_enough___n100_building.value, ... overlap_type=custom_arcpy.OverlapType.INTERSECT.value, ... select_features=Building_N100.grunnriss_to_point__aggregated_polygon__n100.value, - ... output_name=Building_N100.polygon_to_point___intersect_aggregated_and_original___n100_building.value, + ... output_name=Building_N100.simplify_polygons___not_intersect_aggregated_and_original_polygon___n100_building.value, ... inverted=True, ... ) 'grunnriss_to_point__intersect_aggregated_and_original__n100' created temporarily. @@ -271,7 +271,7 @@ def select_location_and_make_permanent_feature( Example: >>> custom_arcpy.select_location_and_make_permanent_feature( - ... input_layer=Building_N100.data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building.value, + ... input_layer=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building.value, ... overlap_type=OverlapType.WITHIN_A_DISTANCE.value, ... select_features=Building_N100.polygon_propogate_displacement___after_displacement___n100_building.value, ... output_name=Building_N100.polygon_propogate_displacement___begrensningskurve_500m_from_displaced_polygon___n100_building.value, diff --git a/custom_tools/partition_iterator.py b/custom_tools/partition_iterator.py index 2c57793e..52fa6a5b 100644 --- a/custom_tools/partition_iterator.py +++ b/custom_tools/partition_iterator.py @@ -762,7 +762,7 @@ def run(self): inputs = { building_points: [ "input", - Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, + Building_N100.data_preparation___matrikkel_points___n100_building.value, ], building_polygons: [ "input", diff --git a/custom_tools/partition_iterator_state_based.py b/custom_tools/partition_iterator_state_based.py index a1f58a0e..b4865a9b 100644 --- a/custom_tools/partition_iterator_state_based.py +++ b/custom_tools/partition_iterator_state_based.py @@ -762,7 +762,7 @@ def run(self): inputs = { building_points: [ "input", - Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, + Building_N100.data_preparation___matrikkel_points___n100_building.value, ], building_polygons: [ "input", diff --git a/file_manager/n100/file_manager_buildings.py b/file_manager/n100/file_manager_buildings.py index 13ba2468..76b2baae 100644 --- a/file_manager/n100/file_manager_buildings.py +++ b/file_manager/n100/file_manager_buildings.py @@ -20,7 +20,7 @@ polygon_to_point = "polygon_to_point" calculating_field_values = "calculating_field_values" point_propogate_displacement = "point_propogate_displacement" -point_cleanup = "point_cleanup" +removing_points_in_water_features = "removing_points_in_water_features" hospital_church_clusters = "hospital_church_clusters" point_displacement_with_buffer = "point_displacement_with_buffer" points_to_squares = "points_to_squares" @@ -85,10 +85,27 @@ class Building_N100(Enum): # DATA PREPARATION # ======================================== - data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building = ( + data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building = file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="waterfeatures_from_begrensningskurve_not_rivers", + ) + + data_preperation___waterfeatures_from_begrensningskurve_rivers___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, - description="selected_waterfeatures_from_begrensningskurve", + description="waterfeatures_from_begrensningskurve_rivers", + ) + ) + + data_preperation___waterfeatures_from_begrensningskurve_rivers_buffer___n100_building = file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="waterfeatures_from_begrensningskurve_rivers_buffer", + ) + + data_preparation___merged_begrensningskurve_all_waterbodies___n100_building = ( + file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="merged_begrensningskurve_all_waterbodies", ) ) @@ -134,10 +151,10 @@ class Building_N100(Enum): ) ) - data_preparation___unsplit_veg_sti___n100_building = ( + data_preparation___unsplit_roads___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, - description="unsplit_veg_sti", + description="unsplit_roads", ) ) @@ -169,13 +186,18 @@ class Building_N100(Enum): ) ) - data_preparation___matrikkel_bygningspunkt___n100_building = ( + data_preparation___matrikkel_points___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, - description="matrikkel_bygningspunkt", + description="matrikkel_points", ) ) + data_preparation___n50_points___n100_building = file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="n50_points", + ) + data_preparation___grunnriss_copy___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, @@ -183,38 +205,59 @@ class Building_N100(Enum): ) ) - data_preparation___large_enough_polygon___n100_building = ( + data_preparation___polygons_that_are_large_enough___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, - description="large_enough_polygon", + description="polygons_that_are_large_enough", ) ) - data_preparation___too_small_polygon___n100_building = ( + data_preparation___polygons_that_are_too_small___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, - description="too_small_polygon", + description="polygons_that_are_too_small", ) ) - data_preparation___points_created_from_small_polygon___n100_building = ( + data_preparation___points_created_from_small_polygons___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=data_preparation, - description="points_created_from_small_polygon", + description="points_created_from_small_polygons", ) ) - # ======================================== - # CALCULATING FIELD VALUES - # ======================================== + data_preperation___matrikkel_n50_points_merged___n100_building = ( + file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="matrikkel_n50_points_merged", + ) + ) - calculating_field_values___merged_points_n50_matrikkel___n100_building = ( + data_preparation___n50_polygons___n100_building = ( file_manager.generate_file_name_gdb( - script_source_name=calculating_field_values, - description="merged_points_n50_matrikkel", + script_source_name=data_preparation, + description="n50_polygons", + ) + ) + + data_preparation___n50_points_in_urban_areas___n100_building = ( + file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="n50_points_in_urban_areas", ) ) + data_preparation___churches_and_hospitals_in_urban_areas___n100_building = ( + file_manager.generate_file_name_gdb( + script_source_name=data_preparation, + description="churches_and_hospitals_in_urban_areas", + ) + ) + + # ======================================== + # CALCULATING FIELD VALUES + # ======================================== + calculate_field_values___points_pre_resolve_building_conflicts___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=calculating_field_values, @@ -237,20 +280,6 @@ class Building_N100(Enum): # POLYGON TO POINT # ======================================== - polygon_to_point___intersect_aggregated_and_original___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=polygon_to_point, - description="intersect_aggregated_and_original", - ) - ) - - polygon_to_point___polygons_to_point___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=polygon_to_point, - description="polygons_to_point", - ) - ) - polygon_to_point___spatial_join_points___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=polygon_to_point, @@ -269,6 +298,18 @@ class Building_N100(Enum): # SIMPLIFY POLYGONS # ======================================== + simplify_polygons___aggregated_polygons_to_points___n100_building = ( + file_manager.generate_file_name_gdb( + script_source_name=simplify_polygons, + description="aggregated_polygons_to_points", + ) + ) + + simplify_polygons___not_intersect_aggregated_and_original_polygon___n100_building = file_manager.generate_file_name_gdb( + script_source_name=polygon_to_point, + description="not_intersect_aggregated_and_original_polygon", + ) + simplify_polygons___small_gaps___n100_building = ( file_manager.generate_file_name_gdb( script_source_name=simplify_polygons, @@ -304,9 +345,11 @@ class Building_N100(Enum): ) ) - simplify_polygons___polygons___n100_building = file_manager.generate_file_name_gdb( - script_source_name=simplify_polygons, - description="polygons", + simplify_polygons___simplify_polygon___n100_building = ( + file_manager.generate_file_name_gdb( + script_source_name=simplify_polygons, + description="simplify_polygon", + ) ) simplify_polygons___points___n100_building = file_manager.generate_file_name_gdb( @@ -344,9 +387,9 @@ class Building_N100(Enum): ) ) - polygon_propogate_displacement___displacement_feature_1000m_from_polygon___n100_building = file_manager.generate_file_name_gdb( + polygon_propogate_displacement___displacement_feature_500m_from_polygon___n100_building = file_manager.generate_file_name_gdb( script_source_name=polygon_propogate_displacement, - description="displacement_feature_1000m_from_polygon", + description="displacement_feature_500m_from_polygon", ) polygon_propogate_displacement___begrensningskurve_500m_from_displaced_polygon___n100_building = file_manager.generate_file_name_gdb( @@ -550,7 +593,6 @@ class Building_N100(Enum): ) ) - # Function: reducing_clusters hospital_church_clusters___minimum_bounding_geometry_hospital___n100_hospital = ( file_manager.generate_file_name_gdb( script_source_name=hospital_church_clusters, @@ -607,76 +649,30 @@ class Building_N100(Enum): ) ) + point_propogate_displacement___displacement_feature_500m_from_point___n100_building = file_manager.generate_file_name_gdb( + script_source_name=point_propogate_displacement, + description="displacement_feature_500m_from_point", + ) + point_propogate_displacement___points_after_propogate_displacement___n100_building = file_manager.generate_file_name_gdb( script_source_name=point_propogate_displacement, description="points_after_propogate_displacement", ) # ======================================== - # POINT CLEANUP + # REMOVING POINTS IN WATER FEATURES # ======================================== - point_cleanup___water_features___n100_building = ( + removing_points_in_water_features___water_features___n100_building = ( file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, + script_source_name=removing_points_in_water_features, description="water_features", ) ) - point_cleanup___points_that_intersect_water_features___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="points_that_intersect_water_features", - ) - ) - - point_cleanup___points_not_intersecting_buffer___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="points_not_intersecting_buffer", - ) - ) - - point_cleanup___building_points_to_squares___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="building_points_to_squares", - ) - ) - - point_cleanup___points_50m_from_building_polygons___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="points_50m_from_building_polygons", - ) - ) - - point_cleanup___polygons_not_too_close_to_squares___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="polygons_not_too_close_to_squares", - ) - ) - - point_cleanup___polygons_too_close_to_squares___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="polygons_too_close_to_squares", - ) - ) - - point_cleanup___building_points_final___n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="building_points_final", - ) - ) - - point_cleanup___building_points_merged_final__n100_building = ( - file_manager.generate_file_name_gdb( - script_source_name=point_cleanup, - description="building_points_merged_final", - ) + removing_points_in_water_features___points_that_do_not_intersect_water_features___n100_building = file_manager.generate_file_name_gdb( + script_source_name=removing_points_in_water_features, + description="points_that_do_not_intersect_water_features", ) ############################################## NEEDS TO BE UPDATED ########################################################### diff --git a/generalization/n100/building/building_main.py b/generalization/n100/building/building_main.py index e89f0d14..d3dd1dbc 100644 --- a/generalization/n100/building/building_main.py +++ b/generalization/n100/building/building_main.py @@ -1,6 +1,7 @@ # Importing modules from env_setup import environment_setup from custom_tools.timing_decorator import timing_decorator +from custom_tools.timing_decorator import clear_print_output # Importing building scripts from generalization.n100.building import data_preparation @@ -13,7 +14,7 @@ from generalization.n100.building import point_displacement_with_buffer from generalization.n100.building import points_to_squares from generalization.n100.building import resolve_building_conflicts_points -from generalization.n100.building import point_cleanup +from generalization.n100.building import removing_points_in_water_features from generalization.n100.building import data_clean_up @@ -50,7 +51,7 @@ def main(): 11. clean_up_building """ - + clear_print_output() environment_setup.main() data_preparation.main() simplify_polygons.main() diff --git a/generalization/n100/building/calculating_field_values.py b/generalization/n100/building/calculating_field_values.py index 0f9d040d..a5606f35 100644 --- a/generalization/n100/building/calculating_field_values.py +++ b/generalization/n100/building/calculating_field_values.py @@ -24,69 +24,44 @@ def main(): Adds required fields for building point for symbology and resolves building conflicts: angle, hierarchy, and invisibility. Creates a symbology value field based on NBR values and logs undefined NBR values, reclassifying them to 729. Ensures that building types which should not be delivered are correctly reclassified. """ environment_setup.main() - table_management() + reclassifying_hospital_and_church_points_from_matrikkel() + adding_original_source_to_points() + merge_matrikkel_and_n50_with_points_from_grunnriss() + find_undefined_nbr_values() + find_each_unique_nbr_value() + calculate_angle_and_visibility_for_points() + calculate_hierarchy_for_points() @timing_decorator -def table_management(): - """ - Summary: - Adds required fields for building point for symbology and resolves building conflicts: angle, hierarchy, and invisibility. - Creates a symbology value field based on NBR values and logs undefined NBR values, reclassifying them to 729. - Ensures that building types which should not be delivered are correctly reclassified. - - Details: - - Reclassify the sykehus from matrikkel to another NBR value. - - Reclassify the sykehus from grunnriss to another NBR value. - - Merge the n50 building point and points added from matrikkel. - - Adding a field to indicate that the merged building point and matrikkel does not come from grunnriss. - - Adding a field to indicate that points resulting from grunnriss are tracked. - - Reclassify the sykehus from grunnriss to another NBR value. - - Merge the merged building point from n50 and matrikkel with points created from grunnriss. - - Adding a symbology value field based on NBR values. - - Code block to transform BYGGTYP_NBR values without symbology to other buildings (729). - - Code block to update the symbol_val to reflect the new BYGGTYP_NBR. - - Adding angle, hierarchy, and invisibility fields to the building point pre symbology and setting them to 0. - - Calculate fields. - - Code block hierarchy logic where churches and hospitals have hierarchy of 1, farms have hierarchy of 2 and the rest of the hierarchy is 3. - """ - - # Reclassify the sykehus from matrikkel to another NBR value - code_block_hospital = ( - "def hospital_nbr(nbr):\n" - " mapping = {970: 729, 719: 729}\n" +def reclassifying_hospital_and_church_points_from_matrikkel(): + # Reclassify hospitals and churches from matrikken to another NBR value ("Other buildings" / "Andre bygg") + code_block_hospital_church = ( + "def reclassify(nbr):\n" + " mapping = {970: 729, 719: 729, 671: 729}\n" " return mapping.get(nbr, nbr)" ) - # Reclassify the sykehus from grunnriss to another NBR value arcpy.CalculateField_management( - in_table=Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, + in_table=Building_N100.data_preparation___matrikkel_points___n100_building.value, field="BYGGTYP_NBR", - expression="hospital_nbr(!BYGGTYP_NBR!)", + expression="reclassify(!BYGGTYP_NBR!)", expression_type="PYTHON3", - code_block=code_block_hospital, - ) - print( - "#######################NEEDS TO IMPLEMENT LATEST LOGIC FROM DATA PREPERATION! #######################" + code_block=code_block_hospital_church, ) - # Merge the n50 building point and matrikkel - arcpy.management.Merge( - inputs=[ - input_n50.BygningsPunkt, - Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, - ], - output=Building_N100.calculating_field_values___merged_points_n50_matrikkel___n100_building.value, - ) + +@timing_decorator +def adding_original_source_to_points(): # Adding a field to indicate that the merged building point and matrikkel does not come from grunnriss arcpy.AddField_management( - in_table=Building_N100.calculating_field_values___merged_points_n50_matrikkel___n100_building.value, + in_table=Building_N100.data_preperation___matrikkel_n50_points_merged___n100_building.value, field_name="grunnriss", field_type="LONG", ) arcpy.CalculateField_management( - in_table=Building_N100.calculating_field_values___merged_points_n50_matrikkel___n100_building.value, + in_table=Building_N100.data_preperation___matrikkel_n50_points_merged___n100_building.value, field="grunnriss", expression="0", ) @@ -103,39 +78,26 @@ def table_management(): expression="1", ) - # Reclassify the sykehus from grunnriss to another NBR value - arcpy.CalculateField_management( - in_table=Building_N100.polygon_to_point___merged_points_final___n100_building.value, - field="BYGGTYP_NBR", - expression="hospital_nbr(!BYGGTYP_NBR!)", - expression_type="PYTHON3", - code_block=code_block_hospital, - ) + +@timing_decorator +def merge_matrikkel_and_n50_with_points_from_grunnriss(): # Merge the merged building point from n50 and matrikkel with points created from grunnriss arcpy.management.Merge( inputs=[ - Building_N100.calculating_field_values___merged_points_n50_matrikkel___n100_building.value, + Building_N100.data_preperation___matrikkel_n50_points_merged___n100_building.value, Building_N100.polygon_to_point___merged_points_final___n100_building.value, ], output=Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, ) - try: - # Attempt to add the field - arcpy.AddField_management( - in_table=Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, - field_name="symbol_val", - field_type="LONG", - ) - print("Field 'symbol_val' added successfully.") - except arcpy.ExecuteError: - print("Field 'symbol_val' already exists.") - - print( - f"{Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value} merged" + arcpy.AddField_management( + in_table=Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, + field_name="symbol_val", + field_type="SHORT", ) + # Determining and assigning symbol val arcpy.CalculateField_management( in_table=Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, field="symbol_val", @@ -144,12 +106,20 @@ def table_management(): code_block=N100_SQLResources.nbr_symbol_val_code_block.value, ) + +@timing_decorator +def find_undefined_nbr_values(): + custom_arcpy.select_attribute_and_make_feature_layer( input_layer=Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, expression="symbol_val = -99", output_name=Building_N100.calculating_field_values___selection_building_points_with_undefined_nbr_values___n100_building.value, ) + +@timing_decorator +def find_each_unique_nbr_value(): + # Counter to store the count of each unique BYGGTYP_NBR nbr_counter = Counter() @@ -213,38 +183,39 @@ def table_management(): code_block=code_block_update_symbol_val, ) - # Adding angle, hierarchy and invisibility fields to the building point pre symbology and setting them to 0 - # Define field information - fields_to_add = [["angle", "LONG"], ["hierarchy", "LONG"], ["invisibility", "LONG"]] - fields_to_calculate = [["angle", "0"], ["hierarchy", "0"], ["invisibility", "0"]] + +@timing_decorator +def calculate_angle_and_visibility_for_points(): # Feature class to check fields existence point_feature_class = ( Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value ) - # Check if fields already exist - existing_fields = arcpy.ListFields(point_feature_class) - existing_field_names = [field.name.lower() for field in existing_fields] - fields_to_add_names = [field[0].lower() for field in fields_to_add] + # List of fields to add and calculate + fields_to_add = [["angle", "LONG"], ["invisibility", "LONG"]] + fields_to_calculate = [["angle", "0"], ["invisibility", "0"]] - if not all( - field_name in existing_field_names for field_name in fields_to_add_names - ): - # Add fields - arcpy.management.AddFields( - in_table=point_feature_class, - field_description=fields_to_add, - ) + # Check if the fields exist in the feature class + existing_fields = [field.name for field in arcpy.ListFields(point_feature_class)] + + # Add fields if they don't exist + for field_name, field_type in fields_to_add: + if field_name not in existing_fields: + arcpy.AddField_management(point_feature_class, field_name, field_type) - # Calculate fields - arcpy.management.CalculateFields( + # Calculate values for each field + for field_name, field_value in fields_to_calculate: + arcpy.management.CalculateField( in_table=point_feature_class, + field=field_name, + expression=field_value, expression_type="PYTHON3", - fields=fields_to_calculate, ) - else: - print("Fields already exist. Skipping adding and calculating fields.") + + +@timing_decorator +def calculate_hierarchy_for_points(): code_block_hierarchy = """def determineHierarchy(symbol_val):\n if symbol_val in [1, 2, 3]:\n diff --git a/generalization/n100/building/data_clean_up.py b/generalization/n100/building/data_clean_up.py index 902eca1e..aac2b057 100644 --- a/generalization/n100/building/data_clean_up.py +++ b/generalization/n100/building/data_clean_up.py @@ -9,6 +9,7 @@ # Main function +@timing_decorator("data_clean_up.py") def main(): environment_setup.main() delete_uneccessary_fields() @@ -18,7 +19,7 @@ def main(): def delete_uneccessary_fields(): # Provide the path to your feature class feature_class_to_clean_up = ( - Building_N100.polygon_to_point___polygons_to_point___n100_building.value + Building_N100.simplify_polygons___aggregated_polygons_to_points___n100_building.value ) # Switch out to correct feature class # List of field names to delete diff --git a/generalization/n100/building/data_preparation.py b/generalization/n100/building/data_preparation.py index f1c0c68a..1daeef94 100644 --- a/generalization/n100/building/data_preparation.py +++ b/generalization/n100/building/data_preparation.py @@ -11,6 +11,7 @@ from env_setup import environment_setup from custom_tools.timing_decorator import timing_decorator from custom_tools import custom_arcpy +from constants.n100_constants import N100_SQLResources @timing_decorator("data_preparation.py") @@ -18,59 +19,42 @@ def main(): """ Summary: This is the main function of building data preparation, which aims to prepare the data for future building generalization processing. - - Details: - 1. `preparation_begrensningskurve`: - This function creates a buffer for water features using the water features (begrensningskurve for vann). It prepares the data for future building placement on the water features edge. - - 2. `preperation_veg_sti`: - This function unsplits a line feature of roads to reduce the number of objects in future processing. - - 3. `adding_matrikkel_as_points`: - This function adds building points from the cadastre (matrikkel) for areas that are no longer considered urban after the generalization of land cover (arealdekke). - It also adds the required fields and values for future analysis. - - 4. `selecting_grunnriss_for_generalization`: - This function selects building polygons (grunnriss) to be generalized. Smaller polygons, churches and hospitals are excluded, transformed into points, and sent to building point generalization. """ environment_setup.main() - preparation_begrensningskurve() - preperation_veg_sti() - adding_matrikkel_as_points() - selecting_grunnriss_for_generalization() - - -###################################### Preparing begrensningskurve (limitation curve) ################################################ + begrensningskurve_land_and_water_bodies() + begrensningskurve_river() + merge_begrensningskurve_all_water_features() + unsplit_roads() + matrikkel_and_n50_not_in_urban_areas() + adding_field_values_to_matrikkel() + merge_matrikkel_and_n50_points() + selecting_polygons_not_in_urban_areas() + reclassifying_polygon_values() + polygon_selections_based_on_size() @timing_decorator -def preparation_begrensningskurve(): +def begrensningskurve_land_and_water_bodies(): """ Summary: - This function creates a buffer for water features using the "begrensningskurve" feature. It prepares the data for future building placement on the water's edge. + Processes land and water body features from the begrensningskurve dataset. Details: - - Using the object types ('ElvBekk', 'Havflate', 'Innsjø', 'InnsjøRegulert') in the "begrensningskurve" feature in SQL expressions to select water features and in inverse to select land features. - - Create a temporary feature of water features from the "begrensningskurve" using the defined SQL expression. - - Select land features using an inverted selection using the defined SQL expression. - - Identify land features near water features by selecting those that boundary-touch with water features to reduce the amount of processing. - - Apply a 15-meter buffer to the identified land features to create buffered land features, this is the distance objects is allowed to be overlapping water features in the final output. - - Apply a 45-meter buffer to the selected water features to create buffered water features, this is to make sure features are not going past the water barrier and is instead pushed towrds land instead of further inside waterfeatures. - - Erase buffered water features from the buffered land features to create a final set of waterfeature buffer which is used throughout this generalization of buildings. - - Note: - - Additional logic may be required for rivers separately in future development as narrow polygons gets completly removed due to the land buffer being to large for the rivers. In processes actually needing barriers this will allow objects to cross narrow rivers. + This function extracts non-river water features (e.g., lake edges, coastal contours) from the begrensningskurve dataset and nearby land features. + It selects these water features based on predefined object types and creates buffers around them. + Additionally, it selects land features adjacent to the water bodies and creates buffers around them as well. + Finally, it erases overlapping areas between land and water body buffers to delineate distinct land and water body regions. """ - # Defining the SQL selection expression for water features for begrensningskurve - sql_expr_begrensningskurve_waterfeatures = "OBJTYPE = 'ElvBekkKant' Or OBJTYPE = 'Innsjøkant' Or OBJTYPE = 'InnsjøkantRegulert' Or OBJTYPE = 'Kystkontur'" + # Defining the SQL selection expression for water features for begrensningskurve (not river) + sql_expr_begrensningskurve_waterfeatures_not_river = "OBJTYPE = 'Innsjøkant' Or OBJTYPE = 'InnsjøkantRegulert' Or OBJTYPE = 'Kystkontur'" # Creating a temporary feature of water features from begrensningskurve custom_arcpy.select_attribute_and_make_permanent_feature( input_layer=input_n100.BegrensningsKurve, - expression=sql_expr_begrensningskurve_waterfeatures, - output_name=Building_N100.data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building.value, + expression=sql_expr_begrensningskurve_waterfeatures_not_river, + output_name=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building.value, ) custom_arcpy.select_attribute_and_make_permanent_feature( @@ -82,7 +66,7 @@ def preparation_begrensningskurve(): custom_arcpy.select_location_and_make_permanent_feature( input_layer=Building_N100.data_preparation___selected_land_features_area___n100_building.value, overlap_type=custom_arcpy.OverlapType.BOUNDARY_TOUCHES.value, - select_features=Building_N100.data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building.value, + select_features=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building.value, output_name=Building_N100.data_preparation___land_features_near_water___n100_building.value, ) @@ -91,95 +75,106 @@ def preparation_begrensningskurve(): out_feature_class=Building_N100.data_preparation___land_features_buffer___n100_building.value, buffer_distance_or_field="15 Meters", ) - print("Buffered land features created") arcpy.analysis.PairwiseBuffer( - in_features=Building_N100.data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building.value, + in_features=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building.value, out_feature_class=Building_N100.data_preparation___begrensningskurve_waterfeatures_buffer___n100_building.value, buffer_distance_or_field="45 Meters", ) - print("Buffered water features created") arcpy.analysis.PairwiseErase( in_features=Building_N100.data_preparation___begrensningskurve_waterfeatures_buffer___n100_building.value, erase_features=Building_N100.data_preparation___selected_land_features_area___n100_building.value, out_feature_class=Building_N100.data_preparation___begrensningskurve_buffer_erase_1___n100_building.value, ) - print( - f"Erased 1 completed {Building_N100.data_preparation___begrensningskurve_buffer_erase_1___n100_building.value} created" - ) arcpy.analysis.PairwiseErase( in_features=Building_N100.data_preparation___begrensningskurve_buffer_erase_1___n100_building.value, erase_features=Building_N100.data_preparation___land_features_buffer___n100_building.value, out_feature_class=Building_N100.data_preparation___begrensningskurve_buffer_erase_2___n100_building.value, ) - print( - f"Erased 2 completed {Building_N100.data_preparation___begrensningskurve_buffer_erase_2___n100_building.value} created" - ) - print("Need to apply better logic for rivers separatly at a later point") - # Needs to use a different logic for narrow rivers, and instead use the centerline and a small buffer around it which is added to the feature class - # Adding hierarchy and invisibility fields to the preparation_begrensningskurve__begrensningskurve_buffer_waterfeatures__n100 and setting them to 0 - # Define field information - fields_to_add = [["hierarchy", "LONG"], ["invisibility", "LONG"]] - fields_to_calculate = [["hierarchy", "0"], ["invisibility", "0"]] - # Add fields - arcpy.management.AddFields( - in_table=Building_N100.data_preparation___begrensningskurve_buffer_erase_2___n100_building.value, - field_description=fields_to_add, +@timing_decorator +def begrensningskurve_river(): + """ + Summary: + Extracts river features from the begrensningskurve dataset and creates buffers around them. + + Details: + This function selects river outlines from the begrensningskurve dataset based on a predefined object type ('ElvBekkKant'). + It then creates a small buffer around the selected river features. + The resulting river outlines and their corresponding buffers are stored as separate feature classes. + """ + + sql_expr_begrensningskurve_river_outline = "OBJTYPE = 'ElvBekkKant'" + + # Creating a temporary feature of rivers from begrensningskurve + custom_arcpy.select_attribute_and_make_permanent_feature( + input_layer=input_n100.BegrensningsKurve, + expression=sql_expr_begrensningskurve_river_outline, + output_name=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_rivers___n100_building.value, ) - # Calculate fields - arcpy.management.CalculateFields( - in_table=Building_N100.data_preparation___begrensningskurve_buffer_erase_2___n100_building.value, - expression_type="PYTHON3", - fields=fields_to_calculate, + # Creating small buffer around begrensningskurve rivers + + arcpy.analysis.PairwiseBuffer( + in_features=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_rivers___n100_building.value, + out_feature_class=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_rivers_buffer___n100_building.value, + buffer_distance_or_field="0.1 Meters", ) -###################################### Preparing roads ################################################ +@timing_decorator +def merge_begrensningskurve_all_water_features(): + """ + Summary: + Merges water feature buffers from begrensningskurve dataset. + + Details: + This function merges buffers representing water bodies and rivers from the begrensningskurve dataset into a single feature class. + """ + + # Merge begrensningskurve buffers (water bodies and rivers) + arcpy.management.Merge( + inputs=[ + Building_N100.data_preperation___waterfeatures_from_begrensningskurve_rivers_buffer___n100_building.value, + Building_N100.data_preparation___begrensningskurve_buffer_erase_2___n100_building.value, + ], + output=Building_N100.data_preparation___merged_begrensningskurve_all_waterbodies___n100_building.value, + ) @timing_decorator -def preperation_veg_sti(): +def unsplit_roads(): """ Summary: - This function unsplit a line feature of roads to reduce the number of objects in future processing. + Unsplits road features. Details: - - It takes the input line feature `input_n100.VegSti` and removes any geometric splits. - - The feature is dissolved based on the fields "subtypekode," "motorvegtype," and "UTTEGNING" to merge segments with the same values in these fields. - Note: - - In the future when the inputs makes spatial selections of the features used for context for processing like roads this step is redundant and will instead increase processing time. + This function unsplit road features in a specified feature class based on certain attributes. """ arcpy.UnsplitLine_management( in_features=input_n100.VegSti, - out_feature_class=Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + out_feature_class=Building_N100.data_preparation___unsplit_roads___n100_building.value, dissolve_field=["subtypekode", "motorvegtype", "UTTEGNING"], ) -###################################### Adding matrikkel-points (cadastre) for areas which are no longer urban ################################################ - - @timing_decorator -def adding_matrikkel_as_points(): +def matrikkel_and_n50_not_in_urban_areas(): """ Summary: - This function adds building points from the matrikkel dataset for areas that are no longer considered urban after the generalization of 'ArealdekkeFlate'. It also adds the required fields and values for future analysis. + Selects matrikkel and n50 building points not within urban areas. Details: - - Define an SQL expression to select urban areas ('Tettbebyggelse', 'Industriområde', 'BymessigBebyggelse') in the 'ArealdekkeFlate' dataset. - - Select urban areas from 'ArealdekkeFlate' in both n100 and n50 datasets using the defined SQL expression. - - Create a buffer of the selected urban areas from n100 to take into consideration that points should not be too close to urban areas. - - Remove areas from n50 urban areas that intersect with the buffer of n100 urban areas, resulting in areas in n100 that are no longer considered urban. - - Select matrikkel bygningspunkter based on the new urban selection layer. - - Transfer the NBR (building type) value to the matrikkel_bygningspunkt dataset by adding a new field "BYGGTYP_NBR" of type LONG and calculating its values from the "bygningstype" field. - Note: - - Should consider removing the logic of adding a buffer to the urban areas to prevent points to close to urban areas and instead using urban areas as a barrier feature in future processing. + This function performs a series of spatial and attribute selections to identify building points from the matrikkel and n50 datasets that are not within urban areas. + It first selects urban areas from the n100 and n50 datasets using a predefined SQL expression based on their object types. + Then, it creates a buffer around the urban areas from the n100 dataset and removes overlapping areas with the urban areas from the n50 dataset. + Building points from the matrikkel dataset that do not intersect with the resulting areas are selected. + Additionally, building points from the n50 dataset that are not within urban areas are selected, ensuring the retention of churches and hospitals within urban areas. + The selected churches and hospitals within urban areas are also retained. """ # Defining sql expression to select urban areas @@ -214,92 +209,223 @@ def adding_matrikkel_as_points(): out_feature_class=Building_N100.data_preparation___no_longer_urban_areas___n100_building.value, ) - # Selecting matrikkel bygningspunkter based on this new urban selection layer + # Selecting matrikkel building points based on this new urban selection layer custom_arcpy.select_location_and_make_permanent_feature( input_layer=input_other.matrikkel_bygningspunkt, overlap_type=custom_arcpy.OverlapType.INTERSECT, select_features=Building_N100.data_preparation___no_longer_urban_areas___n100_building.value, - output_name=Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, + output_name=Building_N100.data_preparation___matrikkel_points___n100_building.value, ) - # Adding transferring the NBR value to the matrikkel_bygningspunkt + # Selecting n50 so they are not in urban areas + custom_arcpy.select_location_and_make_permanent_feature( + input_layer=input_n50.BygningsPunkt, + overlap_type=custom_arcpy.OverlapType.INTERSECT, + select_features=Building_N100.data_preparation___urban_area_selection_n100_buffer___n100_building.value, + output_name=Building_N100.data_preparation___n50_points___n100_building.value, + inverted=True, + ) + + # Making sure we are not loosing churches or hospitals + custom_arcpy.select_location_and_make_permanent_feature( + input_layer=input_n50.BygningsPunkt, + overlap_type=custom_arcpy.OverlapType.INTERSECT, + select_features=Building_N100.data_preparation___urban_area_selection_n100_buffer___n100_building.value, + output_name=Building_N100.data_preparation___n50_points_in_urban_areas___n100_building.value, + ) + + sql_church_hospitals = "BYGGTYP_NBR IN (970, 719, 671)" + custom_arcpy.select_attribute_and_make_permanent_feature( + input_layer=Building_N100.data_preparation___n50_points_in_urban_areas___n100_building.value, + expression=sql_church_hospitals, + output_name=Building_N100.data_preparation___churches_and_hospitals_in_urban_areas___n100_building.value, + ) + + +@timing_decorator +def adding_field_values_to_matrikkel(): + """ + Summary: + Adds field values to matrikkel building points. + + Details: + This function adds a new field called 'BYGGTYP_NBR' of type 'LONG' to the matrikkel building points dataset. + Then, it copies values from an existing field ('bygningstype') into the newly added 'BYGGTYP_NBR' field for each record. + """ + + # Adding transferring the NBR value to the matrikkel building points arcpy.AddField_management( - in_table=Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, + in_table=Building_N100.data_preparation___matrikkel_points___n100_building.value, field_name="BYGGTYP_NBR", field_type="LONG", ) arcpy.CalculateField_management( - in_table=Building_N100.data_preparation___matrikkel_bygningspunkt___n100_building.value, + in_table=Building_N100.data_preparation___matrikkel_points___n100_building.value, field="BYGGTYP_NBR", expression="!bygningstype!", ) -###################################### Transforms hospitals and churches polygons to points ################################################ +@timing_decorator +def merge_matrikkel_and_n50_points(): + """ + Summary: + Merges points from different datasets into a single feature class. + + Details: + This function merges points from the n50 building dataset, churches and hospitals in urban areas dataset, and the matrikkel dataset into a single feature class. + The resulting feature class contains the combined points from these datasets. + """ + + # Merge the n50 building point and matrikkel + arcpy.management.Merge( + inputs=[ + Building_N100.data_preparation___n50_points___n100_building.value, + Building_N100.data_preparation___churches_and_hospitals_in_urban_areas___n100_building.value, + Building_N100.data_preparation___matrikkel_points___n100_building.value, + ], + output=Building_N100.data_preperation___matrikkel_n50_points_merged___n100_building.value, + ) + + +@timing_decorator +def adding_field_values_to_matrikkel(): + """ + Summary: + Adds and transfers field values to matrikkel building points. + + Details: + This function adds a new field called 'BYGGTYP_NBR' of type 'LONG' to the matrikkel building points dataset. + Subsequently, it copies values from an existing field ('bygningstype') into the newly added 'BYGGTYP_NBR' field for each record. + """ + + # Adding transferring the NBR value to the matrikkel building points + arcpy.AddField_management( + in_table=Building_N100.data_preparation___matrikkel_points___n100_building.value, + field_name="BYGGTYP_NBR", + field_type="LONG", + ) + arcpy.CalculateField_management( + in_table=Building_N100.data_preparation___matrikkel_points___n100_building.value, + field="BYGGTYP_NBR", + expression="!bygningstype!", + ) @timing_decorator -def selecting_grunnriss_for_generalization(): +def merge_matrikkel_and_n50_points(): """ Summary: - This function selects building polygons (grunnriss) to be generalized. Smaller polygons and churches or hospitals are excluded, transformed into points, and sent to building point generalization. + Merges points from the n50 building dataset and matrikkel dataset. Details: - - Reclassify hospitals and churches polygons to 'NBR 729' (other buildings). - - Select grunnriss that are large enough based on a minimum polygon size of 2500 square meters. - - Transform small grunnriss features into points by calculating centroids. + This function combines points from the n50 building dataset and the matrikkel dataset into a single feature class. + """ + + # Merge the n50 building point and matrikkel + arcpy.management.Merge( + inputs=[ + Building_N100.data_preparation___n50_points___n100_building.value, + Building_N100.data_preparation___matrikkel_points___n100_building.value, + ], + output=Building_N100.data_preperation___matrikkel_n50_points_merged___n100_building.value, + ) +@timing_decorator +def selecting_polygons_not_in_urban_areas(): + """ + Summary: + Selects polygons not within urban areas. - Parameters: - - Minimum Polygon Size: The minimum size of polygons, in square meters. It currently at **'2500 Meters'**. + Details: + This function copies the input data to preserve the original fields, ensuring no modifications are made to the original dataset. + Then, it selects building polygons from the copied data based on their spatial relationship with a layer representing areas no longer classified as urban. + Polygons that do not intersect with the specified urban area layer are retained and stored as a new feature layer. """ + print( + "might want to remove this copyl ater when we have another script for just copying the database" + ) # Copy the input data to not modify the original fields. arcpy.management.Copy( in_data=input_n50.Grunnriss, out_data=Building_N100.data_preparation___grunnriss_copy___n100_building.value, ) - # Reclassify the church and hospitals from grunnriss to another NBR value - code_block_church_hospital = ( - "def hospital_nbr(nbr):\n" + # Selecting n50 building points based on this new urban selection layer + custom_arcpy.select_location_and_make_permanent_feature( + input_layer=input_n50.Grunnriss, + overlap_type=custom_arcpy.OverlapType.INTERSECT, + select_features=Building_N100.data_preparation___no_longer_urban_areas___n100_building.value, + output_name=Building_N100.data_preparation___n50_polygons___n100_building.value, + ) + + +@timing_decorator +def reclassifying_polygon_values(): + """ + Summary: + Reclassifies the values of hospitals and churches in the specified polygon layer to a new value (729), corresponding to "other buildings". + + Details: + This function defines a reclassification scheme for hospitals and churches within a polygon layer. Hospitals and churches are identified by their respective values in the 'BYGGTYP_NBR' field. + These values (970, 719, and 671) are mapped to a new value (729) representing "other buildings" using a Python dictionary. + The reclassification is applied to the 'BYGGTYP_NBR' field. + """ + + # Reclassify the hospitals and churches to NBR value 729 ("other buildings" / "andre bygg") + reclassify_hospital_church_polygons = ( + "def reclassify(nbr):\n" " mapping = {970: 729, 719: 729, 671: 729}\n" " return mapping.get(nbr, nbr)" ) - # Reclassify the sykehus from grunnriss to another NBR value arcpy.CalculateField_management( - in_table=input_n50.Grunnriss, + in_table=Building_N100.data_preparation___n50_polygons___n100_building.value, field="BYGGTYP_NBR", - expression="hospital_nbr(!BYGGTYP_NBR!)", + expression="reclassify(!BYGGTYP_NBR!)", expression_type="PYTHON3", - code_block=code_block_church_hospital, + code_block=reclassify_hospital_church_polygons, ) - # Selecting grunnriss which are large enough + +@timing_decorator +def polygon_selections_based_on_size(): + """ + Summary: + Selects building polygons based on their size and converts small polygons to points. + + Details: + This function performs a selection on building polygons based on their size. It first defines a minimum size threshold of 2500 square units. + Then, it selects polygons that meet this threshold (polygons over or equal to 2500 square meters) and those that do not (polygons under 2500 square meters). + The selected polygons over the minimum size are retained for further processing, while the smaller polygons are transformed into points. + """ + + # Selecting only building polygons over 2500 (the rest will be transformed to points due to size) grunnriss_minimum_size = 2500 - sql_expression_too_small_grunnriss = f"Shape_Area < {grunnriss_minimum_size}" - sql_expression_correct_size_grunnriss = f"Shape_Area >= {grunnriss_minimum_size}" + sql_expression_too_small_polygons = f"Shape_Area < {grunnriss_minimum_size}" + sql_expression_correct_size_polygons = f"Shape_Area >= {grunnriss_minimum_size}" + # Polygons over or equal to 2500 Square Meters are selected custom_arcpy.select_attribute_and_make_permanent_feature( input_layer=Building_N100.data_preparation___grunnriss_copy___n100_building.value, - expression=sql_expression_correct_size_grunnriss, - output_name=Building_N100.data_preparation___large_enough_polygon___n100_building.value, + expression=sql_expression_correct_size_polygons, + output_name=Building_N100.data_preparation___polygons_that_are_large_enough___n100_building.value, ) + # Polygons under 2500 Square Meters are selected custom_arcpy.select_attribute_and_make_feature_layer( input_layer=Building_N100.data_preparation___grunnriss_copy___n100_building.value, - expression=sql_expression_too_small_grunnriss, - output_name=Building_N100.data_preparation___too_small_polygon___n100_building.value, + expression=sql_expression_too_small_polygons, + output_name=Building_N100.data_preparation___polygons_that_are_too_small___n100_building.value, selection_type=custom_arcpy.SelectionType.NEW_SELECTION, ) - # Transforming small grunnriss features into points - arcpy.FeatureToPoint_management( - in_features=Building_N100.data_preparation___too_small_polygon___n100_building.value, - out_feature_class=Building_N100.data_preparation___points_created_from_small_polygon___n100_building.value, - point_location="CENTROID", + # Transforming small building polygons into points + arcpy.management.FeatureToPoint( + in_features=Building_N100.data_preparation___polygons_that_are_too_small___n100_building.value, + out_feature_class=Building_N100.data_preparation___points_created_from_small_polygons___n100_building.value, # Sent to polygon to point - to get merged as an additional input ) diff --git a/generalization/n100/building/not_in_use_models/create_cartographic_partitions.py b/generalization/n100/building/not_in_use_models/create_cartographic_partitions.py index 8a216335..d615be40 100644 --- a/generalization/n100/building/not_in_use_models/create_cartographic_partitions.py +++ b/generalization/n100/building/not_in_use_models/create_cartographic_partitions.py @@ -24,7 +24,7 @@ def create_cartographic_partitions(): in_features=[ Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, Building_N100.simplify_building_polygons__simplified_grunnriss__n100.value, - Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + Building_N100.data_preparation___unsplit_roads___n100_building.value, Building_N100.data_preparation___begrensningskurve_buffer_erase_2___n100_building.value, ], out_features=Building_N100.create_cartographic_partitions__cartographic_partitions__n100.value, diff --git a/generalization/n100/building/not_in_use_models/old_resolve_building_conflicts.py b/generalization/n100/building/not_in_use_models/old_resolve_building_conflicts.py index 10ec023b..d9abc0a3 100644 --- a/generalization/n100/building/not_in_use_models/old_resolve_building_conflicts.py +++ b/generalization/n100/building/not_in_use_models/old_resolve_building_conflicts.py @@ -106,7 +106,7 @@ def iterate_through_selections(): "output_name": selection_grunnriss, }, { - "input_layer": Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + "input_layer": Building_N100.data_preparation___unsplit_roads___n100_building.value, "output_name": selection_veg_sti, }, { @@ -615,7 +615,7 @@ def rbc_iteration(): # "output_name": selection_grunnriss, # }, # { -# "input_layer": Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, +# "input_layer": Building_N100.data_preparation___unsplit_roads___n100_building.value, # "output_name": selection_veg_sti, # }, # { @@ -623,7 +623,7 @@ def rbc_iteration(): # "output_name": selection_bygningspunkt, # }, # { -# "input_layer": Building_N100.data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building.value, +# "input_layer": Building_N100.data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building.value, # "output_name": selection_begrensningskurve, # }, # ] diff --git a/generalization/n100/building/point_cleanup.py b/generalization/n100/building/point_cleanup.py deleted file mode 100644 index 6f6b8f0d..00000000 --- a/generalization/n100/building/point_cleanup.py +++ /dev/null @@ -1,114 +0,0 @@ -# Importing modules -import arcpy -import time - -# Importing custom files -from input_data import input_n100 -from file_manager.n100.file_manager_buildings import Building_N100 - -# Import custom modules -from custom_tools import custom_arcpy -from env_setup import environment_setup -from custom_tools.polygon_processor import PolygonProcessor -from constants.n100_constants import N100Symbology - - -def main(): - environment_setup.main() - removing_building_points_in_water_features() - polygons_too_close_to_building_points() - merging_points() - - -def removing_building_points_in_water_features(): - - 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_n100.ArealdekkeFlate, - expression=sql_expression_water_features, - output_name=Building_N100.point_cleanup___water_features___n100_building.value, - ) - - # Select points that intersect water features - custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.resolve_building_conflicts__building_points_RBC_final__n100.value, - overlap_type=custom_arcpy.OverlapType.INTERSECT, - select_features=Building_N100.point_cleanup___water_features___n100_building.value, - output_name=Building_N100.point_cleanup___points_that_intersect_water_features___n100_building.value, - ) - - # Select points that do NOT intersect water feature buffer - custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.point_cleanup___points_that_intersect_water_features___n100_building.value, - overlap_type=custom_arcpy.OverlapType.INTERSECT, - select_features=Building_N100.data_preparation___begrensningskurve_buffer_erase_1___n100_building.value, - output_name=Building_N100.point_cleanup___points_not_intersecting_buffer___n100_building.value, - inverted=True, # Inverted - ) - - -def polygons_too_close_to_building_points(): - - # Checking if building polygons intersect with building squares (representing point symbology) - custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.resolve_building_conflicts__building_points_RBC_final__n100.value, - overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, - select_features=Building_N100.polygon_propogate_displacement___building_polygons_final___n100_building.value, - output_name=Building_N100.point_cleanup___points_50m_from_building_polygons___n100_building.value, - search_distance="50 Meters", - ) - - # Polygon prosessor to transform building points to squares, representing the points symbology. - - print("Polygon prosessor...") - polygon_process = PolygonProcessor( - input_building_points=Building_N100.point_cleanup___points_50m_from_building_polygons___n100_building.value, # input - output_polygon_feature_class=Building_N100.point_cleanup___building_points_to_squares___n100_building.value, # output - building_symbol_dimensions=N100Symbology.building_symbol_dimensions.value, - symbol_field_name="symbol_val", - index_field_name="OBJECTID", - ) - polygon_process.run() - - # Checking which building polygons DO NOT intersect with building squares (representing point symbology) - custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.polygon_propogate_displacement___building_polygons_final___n100_building.value, - overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, - select_features=Building_N100.point_cleanup___building_points_to_squares___n100_building.value, - output_name=Building_N100.point_cleanup___polygons_not_too_close_to_squares___n100_building.value, - search_distance="15 Meters", - inverted=True, # Inverted - ) - - # Checking which building polygons intersect with building squares (representing point symbology) - custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.polygon_propogate_displacement___building_polygons_final___n100_building.value, - overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, - select_features=Building_N100.point_cleanup___building_points_to_squares___n100_building.value, - output_name=Building_N100.point_cleanup___polygons_too_close_to_squares___n100_building.value, - search_distance="15 Meters", - inverted=False, # NOT Inverted - ) - # Transforming the polygons that overlap with points to points - arcpy.management.FeatureToPoint( - in_features=Building_N100.point_cleanup___polygons_too_close_to_squares___n100_building.value, - out_feature_class=Building_N100.point_cleanup___building_points_final___n100_building.value, - ) - - -def merging_points(): - # Layers to merge - merge_list = [ - Building_N100.point_cleanup___building_points_final___n100_building.value, - Building_N100.resolve_building_conflicts__building_points_RBC_final__n100.value, - Building_N100.polygon_propogate_displacement___small_building_polygons_to_point___n100_building.value, - ] - # Merge the new points with other building points - arcpy.management.Merge( - inputs=merge_list, - output=Building_N100.point_cleanup___building_points_merged_final__n100_building.value, - ) - - -if __name__ == "__main__": - main() diff --git a/generalization/n100/building/point_displacement_with_buffer.py b/generalization/n100/building/point_displacement_with_buffer.py index e0e983b4..36b175a0 100644 --- a/generalization/n100/building/point_displacement_with_buffer.py +++ b/generalization/n100/building/point_displacement_with_buffer.py @@ -59,7 +59,7 @@ def selection(): ) custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + input_layer=Building_N100.data_preparation___unsplit_roads___n100_building.value, overlap_type=custom_arcpy.OverlapType.INTERSECT.value, select_features=Building_N100.rbc_selection__selection_area_resolve_building_conflicts__n100.value, output_name=Building_N100.building_point_buffer_displacement__roads_study_area__n100.value, @@ -100,7 +100,7 @@ def pre_create_template_feature_class(): buffer_output_name = f"{Building_N100.building_point_buffer_displacement__roads_buffer__n100.value}_template" custom_arcpy.select_attribute_and_make_feature_layer( - input_layer=Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + input_layer=Building_N100.data_preparation___unsplit_roads___n100_building.value, expression=template_query, output_name=selection_output_name, ) diff --git a/generalization/n100/building/point_propogate_displacement.py b/generalization/n100/building/point_propogate_displacement.py index 57fe1d5b..286cddaf 100644 --- a/generalization/n100/building/point_propogate_displacement.py +++ b/generalization/n100/building/point_propogate_displacement.py @@ -3,6 +3,7 @@ # Importing custom modules import config +from custom_tools import custom_arcpy # Importing environment settings from env_setup import environment_setup @@ -14,7 +15,7 @@ from custom_tools.timing_decorator import timing_decorator -@timing_decorator("building_points_propogate_displacement.py") +@timing_decorator("points_propogate_displacement.py") def main(): """ Summary: @@ -49,9 +50,18 @@ def propagate_displacement_building_points(): out_data=Building_N100.point_propogate_displacement___points_pre_propogate_displacement___n100_building.value, ) + # Selecting propogate displacement features 500 meters from building polgyons + custom_arcpy.select_location_and_make_permanent_feature( + input_layer=config.displacement_feature, + overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, + select_features=Building_N100.point_propogate_displacement___points_pre_propogate_displacement___n100_building.value, + output_name=Building_N100.point_propogate_displacement___displacement_feature_500m_from_point___n100_building.value, + search_distance="500 Meters", + ) + arcpy.cartography.PropagateDisplacement( in_features=Building_N100.calculate_field_values___points_pre_resolve_building_conflicts___n100_building.value, - displacement_features=config.displacement_feature, + displacement_features=Building_N100.point_propogate_displacement___displacement_feature_500m_from_point___n100_building.value, adjustment_style="SOLID", ) diff --git a/generalization/n100/building/polygon_propogate_displacement.py b/generalization/n100/building/polygon_propogate_displacement.py index ea1b1259..81d76870 100644 --- a/generalization/n100/building/polygon_propogate_displacement.py +++ b/generalization/n100/building/polygon_propogate_displacement.py @@ -67,14 +67,15 @@ def main(): environment_setup.main() propagate_displacement_building_polygons() - features_500_m_from_building_polygons() + roads_and_water_barriers_500_m_from_building_polygons() + polygon_processor() apply_symbology_to_layers() resolve_building_conflict_building_polygon() creating_road_buffer() invisible_building_polygons_to_point() intersecting_building_polygons_to_point() merging_invisible_intersecting_points() - removing_small_building_polygons() + check_if_building_polygons_are_big_enough() small_building_polygons_to_points() @@ -105,14 +106,14 @@ def propagate_displacement_building_polygons(): input_layer=config.displacement_feature, overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, select_features=Building_N100.polygon_propogate_displacement___pre_displacement___n100_building.value, - output_name=Building_N100.polygon_propogate_displacement___displacement_feature_1000m_from_polygon___n100_building.value, + output_name=Building_N100.polygon_propogate_displacement___displacement_feature_500m_from_polygon___n100_building.value, search_distance="500 Meters", ) # Running propogate displacement for building polygons arcpy.cartography.PropagateDisplacement( in_features=Building_N100.polygon_propogate_displacement___pre_displacement___n100_building.value, - displacement_features=Building_N100.polygon_propogate_displacement___displacement_feature_1000m_from_polygon___n100_building.value, + displacement_features=Building_N100.polygon_propogate_displacement___displacement_feature_500m_from_polygon___n100_building.value, adjustment_style="SOLID", ) @@ -124,7 +125,7 @@ def propagate_displacement_building_polygons(): @timing_decorator -def features_500_m_from_building_polygons(): +def roads_and_water_barriers_500_m_from_building_polygons(): """ Summary: Selects waterfeatures and roads located 500 meters from building polygons. @@ -136,7 +137,7 @@ def features_500_m_from_building_polygons(): print("Selecting features 500 meter from building polygon ...") # Selecting begrensningskurve 500 meters from building polygons custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.data_preperation___selected_waterfeatures_from_begrensningskurve___n100_building.value, + input_layer=Building_N100.data_preperation___waterfeatures_from_begrensningskurve_not_rivers___n100_building.value, overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, select_features=Building_N100.polygon_propogate_displacement___after_displacement___n100_building.value, output_name=Building_N100.polygon_propogate_displacement___begrensningskurve_500m_from_displaced_polygon___n100_building.value, @@ -145,7 +146,7 @@ def features_500_m_from_building_polygons(): # Selecting roads 500 meters from building polygons custom_arcpy.select_location_and_make_permanent_feature( - input_layer=Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + input_layer=Building_N100.data_preparation___unsplit_roads___n100_building.value, overlap_type=custom_arcpy.OverlapType.WITHIN_A_DISTANCE, select_features=Building_N100.polygon_propogate_displacement___after_displacement___n100_building.value, output_name=Building_N100.polygon_propogate_displacement___roads_500m_from_displaced_polygon___n100_building.value, @@ -154,45 +155,7 @@ def features_500_m_from_building_polygons(): @timing_decorator -def apply_symbology_to_layers(): - """ - Summary: - Applies symbology (lyrx files) to building polygons, roads, and water barriers. - - """ - print("Applying symbology ...") - # Applying symbology to building polygons - custom_arcpy.apply_symbology( - input_layer=Building_N100.polygon_propogate_displacement___after_displacement___n100_building.value, - in_symbology_layer=input_symbology.SymbologyN100.grunnriss.value, - output_name=Building_N100.polygon_propogate_displacement___building_polygon___n100_building_lyrx.value, - ) - # Applying symbology to roads - custom_arcpy.apply_symbology( - input_layer=Building_N100.polygon_propogate_displacement___roads_500m_from_displaced_polygon___n100_building.value, - in_symbology_layer=input_symbology.SymbologyN100.veg_sti.value, - output_name=Building_N100.polygon_propogate_displacement___roads___n100_building_lyrx.value, - ) - - # Applying symbology to begrensningskurve (limiting curve) - custom_arcpy.apply_symbology( - input_layer=Building_N100.polygon_propogate_displacement___begrensningskurve_500m_from_displaced_polygon___n100_building.value, - in_symbology_layer=input_symbology.SymbologyN100.begrensnings_kurve_line.value, - output_name=Building_N100.polygon_propogate_displacement___begrensningskurve___n100_building_lyrx.value, - ) - - -@timing_decorator -def resolve_building_conflict_building_polygon(): - """ - Summary: - Resolves conflicts among building polygons considering roads, water features, hospitals, and churches as barriers. - - Details: - This function resolves conflicts among building polygons by taking into account various barriers such as roads, - water features, hospitals, and churches. To incorporate hospital and church points as barriers, these points are first - transformed into polygons using the dimensions of their symbology. - """ +def polygon_processor(): # Selecting hospital and churches from n50 custom_arcpy.select_attribute_and_make_permanent_feature( @@ -215,6 +178,7 @@ def resolve_building_conflict_building_polygon(): expression_type="PYTHON3", code_block=N100_SQLResources.nbr_symbol_val_code_block.value, ) + # Polygon prosessor symbol_field_name = "symbol_val" index_field_name = "OBJECTID" @@ -236,6 +200,48 @@ def resolve_building_conflict_building_polygon(): output_name=Building_N100.polygon_propogate_displacement___polygonprocessor_symbology___n100_building_lyrx.value, ) + +@timing_decorator +def apply_symbology_to_layers(): + """ + Summary: + Applies symbology (lyrx files) to building polygons, roads, and water barriers. + + """ + print("Applying symbology ...") + # Applying symbology to building polygons + custom_arcpy.apply_symbology( + input_layer=Building_N100.polygon_propogate_displacement___after_displacement___n100_building.value, + in_symbology_layer=input_symbology.SymbologyN100.grunnriss.value, + output_name=Building_N100.polygon_propogate_displacement___building_polygon___n100_building_lyrx.value, + ) + # Applying symbology to roads + custom_arcpy.apply_symbology( + input_layer=Building_N100.polygon_propogate_displacement___roads_500m_from_displaced_polygon___n100_building.value, + in_symbology_layer=input_symbology.SymbologyN100.veg_sti.value, + output_name=Building_N100.polygon_propogate_displacement___roads___n100_building_lyrx.value, + ) + + # Applying symbology to begrensningskurve (limiting curve) + custom_arcpy.apply_symbology( + input_layer=Building_N100.polygon_propogate_displacement___begrensningskurve_500m_from_displaced_polygon___n100_building.value, + in_symbology_layer=input_symbology.SymbologyN100.begrensnings_kurve_line.value, + output_name=Building_N100.polygon_propogate_displacement___begrensningskurve___n100_building_lyrx.value, + ) + + +@timing_decorator +def resolve_building_conflict_building_polygon(): + """ + Summary: + Resolves conflicts among building polygons considering roads, water features, hospitals, and churches as barriers. + + Details: + This function resolves conflicts among building polygons by taking into account various barriers such as roads, + water features, hospitals, and churches. To incorporate hospital and church points as barriers, these points are first + transformed into polygons using the dimensions of their symbology. + """ + # Resolving Building Conflicts for building polygons print("Resolving building conflicts ...") # Setting scale to 1: 100 000 @@ -318,7 +324,7 @@ def creating_road_buffer(): # Selecting road types and making new feature layer based on SQL query custom_arcpy.select_attribute_and_make_feature_layer( - input_layer=Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + input_layer=Building_N100.data_preparation___unsplit_roads___n100_building.value, expression=sql_query, output_name=selection_output_name, ) @@ -425,11 +431,6 @@ def merging_invisible_intersecting_points(): """ Summary: Merges points representing intersecting building polygons and invisible polygons. - - Details: - This function merges two sets of points: one set representing building polygons that intersect with roads, - and another set representing invisible building polygons transformed into points. It combines these points - into a single feature class. """ print("Merging points...") arcpy.management.Merge( @@ -442,7 +443,7 @@ def merging_invisible_intersecting_points(): @timing_decorator -def removing_small_building_polygons(): +def check_if_building_polygons_are_big_enough(): """ Summary: Removes small building polygons from the input layer based on a specified area threshold. @@ -453,12 +454,23 @@ def removing_small_building_polygons(): """ custom_arcpy.select_attribute_and_make_permanent_feature( input_layer=Building_N100.polygon_propogate_displacement___building_polygons_not_invisible_not_intersecting___n100_building.value, - expression="Shape_Area > 3200", + expression="Shape_Area >= 3200", output_name=Building_N100.polygon_propogate_displacement___building_polygons_final___n100_building.value, ) +@timing_decorator def small_building_polygons_to_points(): + """ + Summary: + Converts small building polygons to points. + + Details: + This function selects small building polygons based on a specified area threshold and transforms them into points. + It first selects building polygons with an area less than 3200 square units using the select_attribute_and_make_permanent_feature function. + Then, it uses arcpy's FeatureToPoint tool to convert these selected polygons into point features. + """ + custom_arcpy.select_attribute_and_make_permanent_feature( input_layer=Building_N100.polygon_propogate_displacement___building_polygons_not_invisible_not_intersecting___n100_building.value, expression="Shape_Area < 3200", diff --git a/generalization/n100/building/polygon_to_point.py b/generalization/n100/building/polygon_to_point.py index 267ad259..5042bbc6 100644 --- a/generalization/n100/building/polygon_to_point.py +++ b/generalization/n100/building/polygon_to_point.py @@ -17,79 +17,49 @@ @timing_decorator("creating_points_from_polygon.py") def main(): """ - This function creates points from small grunnriss lost during aggregation, and merges + This function creates points from small polygons lost during aggregation, and merges them together with collapsed points from the tools simplify building and simplify polygon. """ environment_setup.main() - grunnriss_to_point() + building_polygons_to_points() @timing_decorator -def grunnriss_to_point(): - """ - Summary: - Transforms building polygons that are too small to points - - """ - - custom_arcpy.select_location_and_make_feature_layer( - input_layer=Building_N100.data_preparation___large_enough_polygon___n100_building.value, - overlap_type=custom_arcpy.OverlapType.INTERSECT, - select_features=Building_N100.simplify_polygons___small_gaps___n100_building.value, - output_name=Building_N100.polygon_to_point___intersect_aggregated_and_original___n100_building.value, - inverted=True, - ) +def building_polygons_to_points(): - arcpy.management.FeatureToPoint( - in_features=Building_N100.polygon_to_point___intersect_aggregated_and_original___n100_building.value, - out_feature_class=Building_N100.polygon_to_point___polygons_to_point___n100_building.value, - ) - - # Base output which the for loop through for output creation - base_output_path = ( - Building_N100.polygon_to_point___spatial_join_points___n100_building.value - ) - - # List of input features which will be spatially joined - input_features = [ - Building_N100.simplify_polygons___points___n100_building.value, - Building_N100.simplify_polygons___simplify_building_1_points___n100_building.value, - Building_N100.simplify_polygons___simplify_building_2_points___n100_building.value, + # List of building points which will be spatially joined with building polygons + input_points = [ + f"{Building_N100.simplify_polygons___simplify_polygon___n100_building.value}_Pnt", + f"{Building_N100.simplify_polygons___simplify_building_1___n100_building.value}_Pnt", + f"{Building_N100.simplify_polygons___simplify_building_2___n100_building.value}_Pnt", ] - # Feature with the field information which will be used for spatial join - join_features = ( - Building_N100.data_preparation___large_enough_polygon___n100_building.value - ) + # List of spatially joined points + spatially_joined_points = [] - # Looping through each Spatial Join operation - for i, input_feature in enumerate(input_features): - # Generate dynamic output path by appending iteration index - output_feature = f"{base_output_path}_{i+1}" + # Looping through each point layer in the list + for point_layer in input_points: + output_feature = f"{point_layer}_spatially_joined" arcpy.analysis.SpatialJoin( - target_features=input_feature, - join_features=join_features, + target_features=point_layer, + join_features=Building_N100.data_preparation___polygons_that_are_large_enough___n100_building.value, out_feature_class=output_feature, join_operation="JOIN_ONE_TO_ONE", match_option="INTERSECT", ) - print(f"Spatial join {i+1} completed with output: {output_feature}") - # Finding the number of outputs from the Spatial Join step to be used in the Merge - num_outputs = len(input_features) - # Generate list of output paths for merge - output_paths = [f"{base_output_path}_{i+1}" for i in range(num_outputs)] + spatially_joined_points.append(output_feature) # Additional inputs for the merge additional_inputs = [ - Building_N100.data_preparation___points_created_from_small_polygon___n100_building.value, - Building_N100.polygon_to_point___polygons_to_point___n100_building.value, + Building_N100.data_preparation___points_created_from_small_polygons___n100_building.value, + Building_N100.simplify_polygons___aggregated_polygons_to_points___n100_building.value, Building_N100.polygon_propogate_displacement___final_merged_points___n100_building.value, Building_N100.polygon_propogate_displacement___small_building_polygons_to_point___n100_building.value, ] # Complete list of inputs for the merge - merge_inputs = additional_inputs + output_paths + merge_inputs = spatially_joined_points + additional_inputs # Perform the Merge operation arcpy.management.Merge( diff --git a/generalization/n100/building/removing_points_in_water_features.py b/generalization/n100/building/removing_points_in_water_features.py new file mode 100644 index 00000000..5ff341a0 --- /dev/null +++ b/generalization/n100/building/removing_points_in_water_features.py @@ -0,0 +1,49 @@ +# Importing modules +import arcpy + +# Importing custom files +from input_data import input_n100 +from file_manager.n100.file_manager_buildings import Building_N100 + +# Import custom modules +from custom_tools import custom_arcpy +from env_setup import environment_setup +from custom_tools.timing_decorator import timing_decorator + + +@timing_decorator("removing_points_in_water_features.py") +def main(): + environment_setup.main() + removing_points_in_water_features() + + +@timing_decorator +def removing_points_in_water_features(): + """ + Summary: + Removes points within water features. + + Details: + This function selects water features from the input layer based on a predefined SQL expression. + Then, it selects points that do not intersect with any water features and retains them. + """ + + 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_n100.ArealdekkeFlate, + expression=sql_expression_water_features, + output_name=Building_N100.removing_points_in_water_features___water_features___n100_building.value, + ) + + # Select points that DO NOT intersect any waterfeatures + custom_arcpy.select_location_and_make_permanent_feature( + input_layer=Building_N100.resolve_building_conflicts__building_points_RBC_final__n100.value, + overlap_type=custom_arcpy.OverlapType.INTERSECT, + select_features=Building_N100.removing_points_in_water_features___water_features___n100_building.value, + output_name=Building_N100.removing_points_in_water_features___points_that_do_not_intersect_water_features___n100_building.value, + inverted=True, + ) + + +if __name__ == "__main__": + main() diff --git a/generalization/n100/building/resolve_building_conflicts_points.py b/generalization/n100/building/resolve_building_conflicts_points.py index 9d39443c..2b55fe1f 100644 --- a/generalization/n100/building/resolve_building_conflicts_points.py +++ b/generalization/n100/building/resolve_building_conflicts_points.py @@ -17,6 +17,7 @@ iteration_fc = config.resolve_building_conflicts_iteration_feature +@timing_decorator("resolve_building_conflicts_points.py") def main(): """ This script resolves building conflicts, both building polygons and points @@ -27,6 +28,7 @@ def main(): resolve_building_conflicts() +@timing_decorator def rbc_selection(): custom_arcpy.select_attribute_and_make_permanent_feature( input_layer=input_n100.AdminFlate, @@ -37,11 +39,11 @@ def rbc_selection(): # List of dictionaries containing parameters for each selection selections = [ { - "input_layer": Building_N100.simplify_polygons___final___n100_building.value, + "input_layer": Building_N100.polygon_propogate_displacement___building_polygons_final___n100_building.value, "output_name": Building_N100.rbc_selection__grunnriss_selection_rbc__n100.value, }, { - "input_layer": Building_N100.data_preparation___unsplit_veg_sti___n100_building.value, + "input_layer": Building_N100.data_preparation___unsplit_roads___n100_building.value, "output_name": Building_N100.rbc_selection__veg_sti_selection_rbc_rbc__n100.value, }, { @@ -68,6 +70,7 @@ def rbc_selection(): ) +@timing_decorator def apply_symbology(): # List of dictionaries containing parameters for each symbology application symbology_configs = [ @@ -107,13 +110,14 @@ def apply_symbology(): ) +@timing_decorator def resolve_building_conflicts(): arcpy.env.referenceScale = "100000" print("Starting Resolve Building Conflicts 1 for drawn polygons") # Define input barriers - input_barriers_1 = [ # NB: confusing name?? input_barriers_1 + input_barriers_for_rbc = [ [ Building_N100.apply_symbology__veg_sti_selection__n100_lyrx.value, "false", @@ -126,10 +130,15 @@ def resolve_building_conflicts(): ], ] + input_buildings_rbc_1 = [ + Building_N100.apply_symbology__grunnriss_selection__n100_lyrx.value, + Building_N100.apply_symbology__drawn_polygon_selection__n100_lyrx.value, + ] + arcpy.cartography.ResolveBuildingConflicts( - in_buildings=Building_N100.apply_symbology__drawn_polygon_selection__n100_lyrx.value, + in_buildings=input_buildings_rbc_1, invisibility_field="invisibility", - in_barriers=input_barriers_1, + in_barriers=input_barriers_for_rbc, building_gap="45 meters", minimum_size="1 meters", hierarchy_field="hierarchy", @@ -140,12 +149,20 @@ def resolve_building_conflicts(): "(invisibility = 0) OR (symbol_val IN (1, 2, 3))" ) + sql_expression_resolve_building_conflicts_polygon = "(invisibility = 0)" + custom_arcpy.select_attribute_and_make_permanent_feature( input_layer=Building_N100.rbc_selection__drawn_polygon_selection_rbc__n100.value, expression=sql_expression_resolve_building_conflicts, output_name=Building_N100.resolve_building_conflicts__drawn_polygons_result_1__n100.value, ) + custom_arcpy.select_attribute_and_make_permanent_feature( + input_layer=Building_N100.rbc_selection__grunnriss_selection_rbc__n100.value, + expression=sql_expression_resolve_building_conflicts_polygon, + output_name=Building_N100.resolve_building_conflicts__drawn_polygons_result_1__n100.value, + ) + custom_arcpy.apply_symbology( input_layer=Building_N100.resolve_building_conflicts__drawn_polygons_result_1__n100.value, in_symbology_layer=Building_N100.apply_symbology__drawn_polygon_selection__n100_lyrx.value, @@ -166,10 +183,15 @@ def resolve_building_conflicts(): print("Starting resolve building conflicts 2") + input_buildings_rbc_2 = [ + Building_N100.resolve_building_conflicts__drawn_polygon_RBC_result_1__n100_lyrx.value, + Building_N100.apply_symbology__drawn_polygon_selection__n100_lyrx.value, + ] + arcpy.cartography.ResolveBuildingConflicts( - in_buildings=Building_N100.resolve_building_conflicts__building_points_RBC_result_1__n100_lyrx.value, + in_buildings=input_buildings_rbc_2, invisibility_field="invisibility", - in_barriers=input_barriers_1, + in_barriers=input_barriers_for_rbc, building_gap="45 meters", minimum_size="1 meters", hierarchy_field="hierarchy", diff --git a/generalization/n100/building/simplify_polygons.py b/generalization/n100/building/simplify_polygons.py index 6c418b1b..4da63a39 100644 --- a/generalization/n100/building/simplify_polygons.py +++ b/generalization/n100/building/simplify_polygons.py @@ -5,13 +5,14 @@ from env_setup import environment_setup from input_data import input_n50 from file_manager.n100.file_manager_buildings import Building_N100 +from custom_tools import custom_arcpy # Importing timing decorator from custom_tools.timing_decorator import timing_decorator # Main function -@timing_decorator("create_simplified_building_polgyons.py") +@timing_decorator("simplify_polygons.py") def main(): """ Summary: @@ -52,25 +53,38 @@ def aggregate_polygons(): - Minimum Area is **`3200 Square Meters`** - Minimum Hole Size is **`10 000 Square Meters`** """ - # Aggregating building polygons - + # Aggregating building polygons (very minimal aggregation) print("Aggregating building polygons...") arcpy.cartography.AggregatePolygons( - in_features=Building_N100.data_preparation___large_enough_polygon___n100_building.value, + in_features=Building_N100.data_preparation___polygons_that_are_large_enough___n100_building.value, out_feature_class=Building_N100.simplify_polygons___small_gaps___n100_building.value, aggregation_distance="4", minimum_area="3200 SquareMeters", minimum_hole_size="10000 SquareMeters", orthogonality_option="ORTHOGONAL", barrier_features=[ - Building_N100.data_preparation___unsplit_veg_sti___n100_building.value + Building_N100.data_preparation___unsplit_roads___n100_building.value ], out_table=f"{Building_N100.simplify_polygons___small_gaps___n100_building.value}_table", - aggregate_field="BYGGTYP_NBR", + ) + + # Find aggregated polygons that do not intersect with "original polygons" (from data preperation) + custom_arcpy.select_location_and_make_permanent_feature( + input_layer=Building_N100.data_preparation___polygons_that_are_large_enough___n100_building.value, + overlap_type=custom_arcpy.OverlapType.INTERSECT, + select_features=Building_N100.simplify_polygons___small_gaps___n100_building.value, + output_name=Building_N100.simplify_polygons___not_intersect_aggregated_and_original_polygon___n100_building.value, + inverted=True, + ) + + # These are transformed to points because they are too small and have been removed by the aggregate polygons minimum area treshold + arcpy.management.FeatureToPoint( + in_features=Building_N100.simplify_polygons___not_intersect_aggregated_and_original_polygon___n100_building.value, + out_feature_class=Building_N100.simplify_polygons___aggregated_polygons_to_points___n100_building.value, ) -# Simplifying building polygons +# First round of simplify buildings @timing_decorator def simplify_buildings_1(): """ @@ -88,27 +102,18 @@ def simplify_buildings_1(): - Minimum Hole Size is **`10,000 Square Meters`**: Sets the minimum size for holes within the building polygons to be retained. """ - print("Simplifying building polygons...") + print("Simplifying building polygons round 1...") arcpy.cartography.SimplifyBuilding( in_features=Building_N100.simplify_polygons___small_gaps___n100_building.value, out_feature_class=Building_N100.simplify_polygons___simplify_building_1___n100_building.value, simplification_tolerance="75", minimum_area="3200 SquareMeters", - collapsed_point_option="KEEP_COLLAPSED_POINTS", + collapsed_point_option="KEEP_COLLAPSED_POINTS", # Name of points will be the same as output, but with `Pnt` at the end ) - # Creating points to permanently store auto generated points from simplified building polygons to a specified path - auto_generated_points_1 = f"{Building_N100.simplify_polygons___simplify_building_1___n100_building.value}_Pnt" - arcpy.management.CopyFeatures( - auto_generated_points_1, - Building_N100.simplify_polygons___simplify_building_1_points___n100_building.value, - ) - arcpy.management.Delete(auto_generated_points_1) - - -# Simplifying polygons +# Simplifying polygons (runs once) @timing_decorator def simplify_polygons(): """ @@ -129,26 +134,13 @@ def simplify_polygons(): arcpy.cartography.SimplifyPolygon( in_features=Building_N100.simplify_polygons___simplify_building_1___n100_building.value, - out_feature_class=Building_N100.simplify_polygons___polygons___n100_building.value, + out_feature_class=Building_N100.simplify_polygons___simplify_polygon___n100_building.value, algorithm="WEIGHTED_AREA", tolerance="15", minimum_area="3200 SquareMeters", - collapsed_point_option="KEEP_COLLAPSED_POINTS", - ) - - # Creating points to permanently store auto generated points from simplified polygon to a specified path - auto_generated_points_2 = ( - f"{Building_N100.simplify_polygons___polygons___n100_building.value}_Pnt" + collapsed_point_option="KEEP_COLLAPSED_POINTS", # Name of points will be the same as output, but with `Pnt` at the end ) - arcpy.management.CopyFeatures( - auto_generated_points_2, - Building_N100.simplify_polygons___points___n100_building.value, - ) - arcpy.management.Delete(auto_generated_points_2) - - # Simplifying building polygons - # Second round of simplify buildings @timing_decorator @@ -167,24 +159,16 @@ def simplify_buildings_2(): - Minimum Area is **`3200 Square Meters`**: Specifies the minimum area a simplified building polygon should have. - Minimum Hole Size is **`10,000 Square Meters`**: Sets the minimum size for holes within the building polygons to be retained. """ + print("Simplifying building polygons round 2...") arcpy.cartography.SimplifyBuilding( in_features=Building_N100.simplify_polygons___simplify_building_1___n100_building.value, out_feature_class=Building_N100.simplify_polygons___simplify_building_2___n100_building.value, simplification_tolerance="75", minimum_area="3200 SquareMeters", - collapsed_point_option="KEEP_COLLAPSED_POINTS", + collapsed_point_option="KEEP_COLLAPSED_POINTS", # Name of points will be the same as output, but with `Pnt` at the end ) - # Creating points to permanently store auto generated points from simplified polygon to a specified path - auto_generated_points_3 = f"{Building_N100.simplify_polygons___simplify_building_2___n100_building.value}_Pnt" - - arcpy.management.CopyFeatures( - auto_generated_points_3, - Building_N100.simplify_polygons___simplify_building_2_points___n100_building.value, - ) - arcpy.management.Delete(auto_generated_points_3) - # Spatial join and adding fields to polygons @timing_decorator @@ -231,10 +215,14 @@ def join_and_add_fields(): arcpy.management.CalculateFields( in_table=Building_N100.simplify_polygons___spatial_join_polygons___n100_building.value, expression_type="PYTHON3", - fields=[["angle", "0"], ["hierarchy", "0"], ["invisibility", "0"]], + fields=[ + ["angle", "0"], + ["hierarchy", "1"], # Hierachy 1 so buildings can be moved around + ["invisibility", "0"], + ], ) - # Making a copy of the feature class + # Assigning new name to the final building polygons print("Making a copy of the feature class...") arcpy.management.CopyFeatures( Building_N100.simplify_polygons___spatial_join_polygons___n100_building.value,