Skip to content

Commit

Permalink
first patch: bugs and performance
Browse files Browse the repository at this point in the history
  • Loading branch information
kauevestena committed Dec 17, 2023
1 parent f8e5d70 commit 647a23e
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 48 deletions.
99 changes: 71 additions & 28 deletions generic_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,25 +576,26 @@ def remove_layerlist(listoflayer_alias):
project_instance.removeMapLayer(layerfullname)


def remove_unconnected_lines(inputlayer):
#thx: https://gis.stackexchange.com/a/316058/49900
with edit(inputlayer):
for i,feature_A in enumerate(inputlayer.getFeatures()):
is_disjointed = True
# disjointed_features = 0
for j,feature_B in enumerate(inputlayer.getFeatures()):
if not i == j:
if not feature_A.geometry().disjoint(feature_B.geometry()):
# print('not disjointed!!',i,j)
is_disjointed=False

if is_disjointed:
# print(is_disjointed)

inputlayer.deleteFeature(feature_A.id())

# # # # it works inplace =D ()
# # # # return inputlayer
### DEPRECATED ###
# # def remove_unconnected_lines(inputlayer):
# # #thx: https://gis.stackexchange.com/a/316058/49900
# # with edit(inputlayer):
# # for i,feature_A in enumerate(inputlayer.getFeatures()):
# # is_disjointed = True
# # # disjointed_features = 0
# # for j,feature_B in enumerate(inputlayer.getFeatures()):
# # if not i == j:
# # if not feature_A.geometry().disjoint(feature_B.geometry()):
# # # print('not disjointed!!',i,j)
# # is_disjointed=False

# # if is_disjointed:
# # # print(is_disjointed)

# # inputlayer.deleteFeature(feature_A.id())

# # # # # # it works inplace =D ()
# # # # # # return inputlayer

def qgs_point_geom_from_line_at(inputlinefeature,index=0):
return QgsGeometry.fromPointXY(inputlinefeature.geometry().asPolyline()[index])
Expand All @@ -607,6 +608,7 @@ def remove_lines_from_no_block(inputlayer,layer_to_check_culdesac=None):
the "layer_to_check_culdesac" is a whole layer (dissolved) that should be checked for 'within' condition
'''


# TODO: check if will work with multilinestrings

check_for_culdesacs = False
Expand All @@ -617,6 +619,8 @@ def remove_lines_from_no_block(inputlayer,layer_to_check_culdesac=None):

feature_ids_to_be_removed = []

index = QgsSpatialIndex(inputlayer.getFeatures())


for i,feature_A in enumerate(inputlayer.getFeatures()):

Expand All @@ -626,19 +630,27 @@ def remove_lines_from_no_block(inputlayer,layer_to_check_culdesac=None):
P0_count = 0
PF_count = 0

# THE OPTIMIZATION PATROL:
# for j,feature_B in enumerate(inputlayer.getFeatures()):
# # if not i == j:
# if P0.intersects(feature_B.geometry()):
# P0_count += 1
# if PF.intersects(feature_B.geometry()):
# PF_count += 1

for j,feature_B in enumerate(inputlayer.getFeatures()):
# if not i == j:
if P0.intersects(feature_B.geometry()):
P0_count += 1
if PF.intersects(feature_B.geometry()):
PF_count += 1
intersect_ids = index.intersects(feature_A.geometry().boundingBox())

for id in intersect_ids:
if id != feature_A.id():
if P0.intersects(inputlayer.getFeature(id).geometry()):
P0_count += 1
if PF.intersects(inputlayer.getFeature(id).geometry()):
PF_count += 1

# print(P0_count,PF_count)


if any(count == 1 for count in [P0_count,PF_count]):
if any(count == 0 for count in [P0_count,PF_count]):
# after checking, only add if its not a "culdesac"
if check_for_culdesacs:
if not feature_A.geometry().within(checker_geom):
Expand Down Expand Up @@ -1079,21 +1091,52 @@ def select_vertex_pol_nodes(inputpolygonfeature,minC_angle=160,maxC_angle=200):


def create_incidence_field_layers_A_B(inputlayer,incident_layer,fieldname='incident',total_length_instead=False):

"""
Creates incidence field layers A and B based on the given input layer and incident layer.
:param inputlayer: The input layer on which the incidence field layers will be created.
:type inputlayer: QgsVectorLayer
:param incident_layer: The incident layer from which the features will be used to create the incidence field layers.
:type incident_layer: QgsVectorLayer
:param fieldname: The name of the field in the input layer that will store the incidence information. Defaults to 'incident'.
:type fieldname: str
:param total_length_instead: If True, the total length of intersecting features will be stored in the field. If False, the IDs of intersecting features will be stored. Defaults to False.
:type total_length_instead: bool
:return: The field ID of the created incidence field layer.
:rtype: int
"""



if total_length_instead:
field_id = create_new_layerfield(inputlayer,fieldname,QVariant.Double)
else:
field_id = create_new_layerfield(inputlayer,fieldname,QVariant.String)

index = QgsSpatialIndex(incident_layer.getFeatures())


with edit(inputlayer):

for feature in inputlayer.getFeatures():

contained_list = []
sum = 0

for tested_feature in incident_layer.getFeatures():
# with not disjoint one can go back and forth

intersecting_ids = index.intersects(feature.geometry().boundingBox())


# for tested_feature in incident_layer.getFeatures():
for id in intersecting_ids:

tested_feature = incident_layer.getFeature(id)
# with not disjointed one can go back and forth
if not feature.geometry().disjoint(tested_feature.geometry()):

if total_length_instead:
Expand Down
52 changes: 32 additions & 20 deletions osm_sidewalkreator.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class sidewalkreator:
already_existing_sidewalks_layer = None

# hint texts:
en_hint = 'Many Times its better to\ncorrect errors on OSM data first!'
en_hint = "Sometimes it's better to\ncorrect errors on OSM data first!"
ptbr_hint = 'Pode ser melhor consertar\nerros na base do OSM antes!'


Expand Down Expand Up @@ -507,8 +507,8 @@ def data_clean(self):
width_value = float(self.dlg.higway_values_table.item(i,1).text())
except:
# if the user input value not convertible to float, just use the value from
print('invalid input value: ',self.dlg.higway_values_table.item(i,1).text(),', using default: ',default_widths[val])
width_value = default_widths[val]
print('invalid input value: ',self.dlg.higway_values_table.item(i,1).text(),', using default: ',default_widths.get(val,fallback_default_width))
width_value = default_widths.get(val,fallback_default_width)

highway_valuestable_dict[val] = width_value

Expand Down Expand Up @@ -553,7 +553,7 @@ def data_clean(self):



# protoblocks has been moved to here:
# protoblocks have been moved to here:
self.protoblocks = polygonize_lines(self.clipped_reproj_datalayer)
self.protoblocks.setCrs(self.custom_localTM_crs) # better safe than sorry kkkk

Expand All @@ -575,7 +575,7 @@ def data_clean(self):
with edit(self.protoblocks):
for feature in self.protoblocks.getFeatures():

# dividing by 4 approximates a square corner
# dividing by 4 approximates the side of a squared shape block
ratio = (((feature['inc_sidewalk_len']/4)**2) / feature.geometry().area()) * 100

self.protoblocks.changeAttributeValue(feature.id(),protoblocks_ratio_id,ratio)
Expand Down Expand Up @@ -1002,6 +1002,7 @@ def draw_crossings(self):
self.above_tol_fieldname = self.string_according_language('above_tol','acima_da_tolerancia')
self.nearest_centerpoint_fieldname= self.string_according_language('nearest_centerpoint','ponto_central_maisprox')

index = QgsSpatialIndex(self.splitted_lines.getFeatures())

for i,feature_A in enumerate(self.splitted_lines.getFeatures()):

Expand Down Expand Up @@ -1031,28 +1032,33 @@ def draw_crossings(self):
# tolerance for considering that a crossing center will have the crossing effectively drawn
# a: two times (half width plus self.dlg.d_to_add_box.value())
# b: three times half the width
initial_vec_len = featurewidth + self.dlg.d_to_add_box.value()

# # 3 times to KNN search
# # KNN search was deprecated

for j,feature_B in enumerate(self.splitted_lines.getFeatures()):
# if not i == j:
if P0.intersects(feature_B.geometry()):
P0_count += 1
P0_small_region = P0.buffer(.1,5).boundingBox()
PF_small_region = PF.buffer(.1,5).boundingBox()

intersecting_ids_P0 = index.intersects(P0_small_region)

if not feature_B.id() == feature_layer_id:
if not feature_osm_id == feature_B['id']:
P0_intersecting_widths[feature_B.id()] = feature_B['width']
if intersecting_ids_P0:
P0_count = len([id for id in intersecting_ids_P0 if self.splitted_lines.getFeature(id).geometry().intersects(P0.buffer(.1,5))])

for id in intersecting_ids_P0:
if id != feature_A.id():
P0_intersecting_widths[id] = self.splitted_lines.getFeature(id)['width']

if PF.intersects(feature_B.geometry()):
PF_count += 1
intersecting_ids_PF = index.intersects(PF_small_region)

if not feature_B.id() == feature_layer_id:
if not feature_osm_id == feature_B['id']:
PF_intersecting_widths[feature_B.id()] = feature_B['width']
if intersecting_ids_PF:
PF_count = len([id for id in intersecting_ids_PF if self.splitted_lines.getFeature(id).geometry().intersects(PF.buffer(.1,5))])

for id in intersecting_ids_PF:
if id != feature_A.id():
PF_intersecting_widths[id] = self.splitted_lines.getFeature(id)['width']


initial_vec_len = featurewidth + self.dlg.d_to_add_box.value()

# print(i+1,P0_intersecting_widths)
# print(i+1,PF_intersecting_widths,'\n')
Expand Down Expand Up @@ -2120,6 +2126,10 @@ def reset_fields(self):
self.set_text_based_on_language(self.dlg.input_status,'waiting a valid input...','aguardando uma entrada válida...',self.change_input_labels)
self.set_text_based_on_language(self.dlg.input_status_of_data,'waiting for data...','aguardando dados...',self.change_input_labels)

# hint box:
self.en_hint = "Sometimes it's better to\ncorrect errors on OSM data first!"
self.ptbr_hint = 'Pode ser melhor consertar\nerros na base do OSM antes!'


# to not exclude created layers and data when the "Ok" button is pressed:
if not self.ok_ready:
Expand Down Expand Up @@ -2502,7 +2512,7 @@ def call_get_osm_data(self):

self.dlg.higway_values_table.setItem(i,0,QTableWidgetItem(vvalue))

self.dlg.higway_values_table.setItem(i,1,QTableWidgetItem(str(default_widths[vvalue])))
self.dlg.higway_values_table.setItem(i,1,QTableWidgetItem(str(default_widths.get(vvalue,fallback_default_width))))



Expand Down Expand Up @@ -3409,6 +3419,8 @@ def try_to_merge_small_stretches(self):
# touching_times_dict[feat_id] = 0
# touchers[feat_id] = []

# MARKED FOR IMPROVEMENT WITH QgsSpatialIndex

for feat2 in extracted_adj_lines.getFeatures():
if not feat2.id in already_used_adj: # to avoid a feature to be used 2 times, or acess a not existent anymore feature
if tiny_feats_dict[feat_id].geometry().touches(feat2.geometry()):
Expand All @@ -3430,7 +3442,7 @@ def try_to_merge_small_stretches(self):

break # so, go for the next small stretch

print(feat2.geometry().length())
# print(feat2.geometry().length())
# print(already_used_adj)

#remove the layerfield: It wont be necessary anymore
Expand Down
3 changes: 3 additions & 0 deletions parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@
# '' : ,
}

# for cases of an unexpected value:
fallback_default_width = 6.0

# ASSETS:
# names of the assets filenames:
sidewalks_stylefilename = 'sidewalkstyles.qml'
Expand Down

0 comments on commit 647a23e

Please sign in to comment.