-
Notifications
You must be signed in to change notification settings - Fork 0
/
tree_assessment_dialog.py
156 lines (123 loc) · 6.08 KB
/
tree_assessment_dialog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# -*- coding: utf-8 -*-
"""
/***************************************************************************
TreeAssessmentDialog
A QGIS plugin
Toets bomen op keringen
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2022-11-28
git sha : $Format:%H$
copyright : (C) 2022 by Rob van Putten
email : [email protected]
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
import os
from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
from qgis.core import QgsVectorLayer, Qgis, QgsGeometry
from .referenceline import ReferenceLine
from .helpers import line_in_or_intersects, lines_intersect
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'tree_assessment_dialog_base.ui'))
class TreeAssessmentDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, iface, parent=None):
"""Constructor."""
super(TreeAssessmentDialog, self).__init__(parent)
# Set up the user interface from Designer through FORM_CLASS.
# After self.setupUi() you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)
self.iface = iface
self._setup_signals_slots()
def _setup_signals_slots(self):
self.mlcbDijktrajectenShape.layerChanged.connect(self.onMlcbDijktrajectenShapeLayerChanged)
self.mfcbDijktrajectVeldnaam.fieldChanged.connect(self.onMfcbDijktrajectVeldnaamFieldChanged)
self.pbAnalyse.clicked.connect(self.onPbAnalyseClicked)
def _update_ui(self):
clayer = self.mlcbDijktrajectenShape.currentLayer()
self.mfcbDijktrajectVeldnaam.setLayer(clayer)
cfield = self.mfcbDijktrajectVeldnaam.currentField()
self.cbDijktrajecten.clear()
for feature in clayer.getFeatures():
self.cbDijktrajecten.addItem(feature[cfield])
def onMlcbDijktrajectenShapeLayerChanged(self):
self._update_ui()
def onMfcbDijktrajectVeldnaamFieldChanged(self):
self._update_ui()
def onPbAnalyseClicked(self):
self._start_analysis()
def _get_waterscheidingslijnen(self, bbox):
result = []
clayer = self.mlcbHydrovakkenShape.currentLayer()
for feature in clayer.getFeatures():
lines = []
geom = feature.geometry()
for part in geom.get():
for i in range(1,len(part)):
p1 = (part[i-1].x(), part[i-1].y())
p2 = (part[i].x(), part[i].y())
if line_in_or_intersects((bbox), (p1,p2)):
result.append((p1,p2))
return result
def _get_trees(self, reference_line, offset=50):
bbox = reference_line.bounding_box(offset)
wlijnen = self._get_waterscheidingslijnen(bbox) # list [(x1,y1),(x2,y2)]
clayer = self.mlcbTreeShape.currentLayer()
trees = []
for feature in clayer.getFeatures():
pt = QgsGeometry.asPoint(feature.geometry())
x_tree = pt.x()
y_tree = pt.y()
if bbox['left'] <= x_tree and x_tree <= bbox['right'] and bbox['bottom'] <= y_tree and y_tree <= bbox['top']:
x_ref, y_ref = reference_line.closest_point_to_xy(x_tree, y_tree)
add = True
for wlijn in wlijnen:
if lines_intersect(wlijn[0], wlijn[1], (x_tree, y_tree), (x_ref,y_ref)):
add = False
break
if add:
trees.append(feature)
return trees
def _start_analysis(self):
dtcode = self.cbDijktrajecten.currentText()
try:
# get the geometry
clayer = self.mlcbDijktrajectenShape.currentLayer()
cfield = self.mfcbDijktrajectVeldnaam.currentField()
query = f'"{cfield}"=\'{dtcode}\''
feature = clayer.selectByExpression(query)
# get the points on the geometry
selection = clayer.selectedFeatures()[0]
geom = selection.geometry()
points = []
for part in geom.get():
points += [(p.x(), p.y()) for p in part]
except Exception as e:
self.iface.messageBar().pushMessage("Error", f"There was en error getting the geometry; {e}", level=Qgis.Critical)
return
# zoom the UI to that location
box = clayer.boundingBoxOfSelected()
self.iface.mapCanvas().setExtent(box)
self.iface.mapCanvas().refresh()
# convert the points to a line with 1m points
reference_line = ReferenceLine.from_points(points)
# get all the trees
trees = self._get_trees(reference_line, offset=50)
# show the selected trees
tree_layer = self.mlcbTreeShape.currentLayer()
self.iface.setActiveLayer(tree_layer)
fids = [f.id() for f in trees]
tree_layer.selectByIds(fids)
layer = self.iface.activeLayer()