BERATools 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- beratools/__init__.py +8 -3
- beratools/core/{algo_footprint_rel.py → algo_canopy_footprint_exp.py} +176 -139
- beratools/core/algo_centerline.py +61 -77
- beratools/core/algo_common.py +48 -57
- beratools/core/algo_cost.py +18 -25
- beratools/core/algo_dijkstra.py +37 -45
- beratools/core/algo_line_grouping.py +100 -100
- beratools/core/algo_merge_lines.py +40 -8
- beratools/core/algo_split_with_lines.py +289 -304
- beratools/core/algo_vertex_optimization.py +25 -46
- beratools/core/canopy_threshold_relative.py +755 -0
- beratools/core/constants.py +8 -9
- beratools/{tools → core}/line_footprint_functions.py +411 -258
- beratools/core/logger.py +18 -2
- beratools/core/tool_base.py +17 -75
- beratools/gui/assets/BERALogo.ico +0 -0
- beratools/gui/assets/BERA_Splash.gif +0 -0
- beratools/gui/assets/BERA_WizardImage.png +0 -0
- beratools/gui/assets/beratools.json +475 -2171
- beratools/gui/bt_data.py +585 -234
- beratools/gui/bt_gui_main.py +129 -91
- beratools/gui/main.py +4 -7
- beratools/gui/tool_widgets.py +530 -354
- beratools/tools/__init__.py +0 -7
- beratools/tools/{line_footprint_absolute.py → canopy_footprint_absolute.py} +81 -56
- beratools/tools/canopy_footprint_exp.py +113 -0
- beratools/tools/centerline.py +30 -37
- beratools/tools/check_seed_line.py +127 -0
- beratools/tools/common.py +65 -586
- beratools/tools/{line_footprint_fixed.py → ground_footprint.py} +140 -117
- beratools/tools/line_footprint_relative.py +64 -35
- beratools/tools/tool_template.py +48 -40
- beratools/tools/vertex_optimization.py +20 -34
- beratools/utility/env_checks.py +53 -0
- beratools/utility/spatial_common.py +210 -0
- beratools/utility/tool_args.py +138 -0
- beratools-0.2.4.dist-info/METADATA +134 -0
- beratools-0.2.4.dist-info/RECORD +50 -0
- {beratools-0.2.2.dist-info → beratools-0.2.4.dist-info}/WHEEL +1 -1
- beratools-0.2.4.dist-info/entry_points.txt +3 -0
- beratools-0.2.4.dist-info/licenses/LICENSE +674 -0
- beratools/core/algo_tiler.py +0 -428
- beratools/gui/__init__.py +0 -11
- beratools/gui/batch_processing_dlg.py +0 -513
- beratools/gui/map_window.py +0 -162
- beratools/tools/Beratools_r_script.r +0 -1120
- beratools/tools/Ht_metrics.py +0 -116
- beratools/tools/batch_processing.py +0 -136
- beratools/tools/canopy_threshold_relative.py +0 -672
- beratools/tools/canopycostraster.py +0 -222
- beratools/tools/fl_regen_csf.py +0 -428
- beratools/tools/forest_line_attributes.py +0 -408
- beratools/tools/line_grouping.py +0 -45
- beratools/tools/ln_relative_metrics.py +0 -615
- beratools/tools/r_cal_lpi_elai.r +0 -25
- beratools/tools/r_generate_pd_focalraster.r +0 -101
- beratools/tools/r_interface.py +0 -80
- beratools/tools/r_point_density.r +0 -9
- beratools/tools/rpy_chm2trees.py +0 -86
- beratools/tools/rpy_dsm_chm_by.py +0 -81
- beratools/tools/rpy_dtm_by.py +0 -63
- beratools/tools/rpy_find_cellsize.py +0 -43
- beratools/tools/rpy_gnd_csf.py +0 -74
- beratools/tools/rpy_hummock_hollow.py +0 -85
- beratools/tools/rpy_hummock_hollow_raster.py +0 -71
- beratools/tools/rpy_las_info.py +0 -51
- beratools/tools/rpy_laz2las.py +0 -40
- beratools/tools/rpy_lpi_elai_lascat.py +0 -466
- beratools/tools/rpy_normalized_lidar_by.py +0 -56
- beratools/tools/rpy_percent_above_dbh.py +0 -80
- beratools/tools/rpy_points2trees.py +0 -88
- beratools/tools/rpy_vegcoverage.py +0 -94
- beratools/tools/tiler.py +0 -48
- beratools/tools/zonal_threshold.py +0 -144
- beratools-0.2.2.dist-info/METADATA +0 -108
- beratools-0.2.2.dist-info/RECORD +0 -74
- beratools-0.2.2.dist-info/entry_points.txt +0 -2
- beratools-0.2.2.dist-info/licenses/LICENSE +0 -22
|
@@ -1,513 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Copyright (C) 2025 Applied Geospatial Research Group.
|
|
3
|
-
|
|
4
|
-
This script is licensed under the GNU General Public License v3.0.
|
|
5
|
-
See <https://gnu.org/licenses/gpl-3.0> for full license details.
|
|
6
|
-
|
|
7
|
-
Author: Richard Zeng
|
|
8
|
-
|
|
9
|
-
Description:
|
|
10
|
-
This script is part of the BERA Tools.
|
|
11
|
-
Webpage: https://github.com/appliedgrg/beratools
|
|
12
|
-
|
|
13
|
-
Batch processing dialog.
|
|
14
|
-
"""
|
|
15
|
-
import sys
|
|
16
|
-
import pandas as pd
|
|
17
|
-
from PyQt5 import QtCore
|
|
18
|
-
from PyQt5 import QtWidgets
|
|
19
|
-
from PyQt5 import QtGui, QtPrintSupport
|
|
20
|
-
|
|
21
|
-
from beratools.gui.tool_widgets import ToolWidgets
|
|
22
|
-
from beratools.gui.bt_data import BTData
|
|
23
|
-
bt = BTData()
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class _PandasModel(QtCore.QAbstractTableModel):
|
|
27
|
-
def __init__(self, df=pd.DataFrame(), parent=None):
|
|
28
|
-
QtCore.QAbstractTableModel.__init__(self, parent=None)
|
|
29
|
-
self._df = df
|
|
30
|
-
self.setChanged = False
|
|
31
|
-
self.dataChanged.connect(self.setModified)
|
|
32
|
-
|
|
33
|
-
def setModified(self):
|
|
34
|
-
self.setChanged = True
|
|
35
|
-
print(self.setChanged)
|
|
36
|
-
|
|
37
|
-
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
|
|
38
|
-
if role != QtCore.Qt.DisplayRole:
|
|
39
|
-
return QtCore.QVariant()
|
|
40
|
-
if orientation == QtCore.Qt.Horizontal:
|
|
41
|
-
try:
|
|
42
|
-
return self._df.columns.tolist()[section]
|
|
43
|
-
except (IndexError,):
|
|
44
|
-
return QtCore.QVariant()
|
|
45
|
-
elif orientation == QtCore.Qt.Vertical:
|
|
46
|
-
try:
|
|
47
|
-
return self._df.index.tolist()[section]
|
|
48
|
-
except (IndexError,):
|
|
49
|
-
return QtCore.QVariant()
|
|
50
|
-
|
|
51
|
-
def flags(self, index):
|
|
52
|
-
return (
|
|
53
|
-
QtCore.Qt.ItemIsEnabled
|
|
54
|
-
| QtCore.Qt.ItemIsSelectable
|
|
55
|
-
| QtCore.Qt.ItemIsEditable
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
def data(self, index, role=QtCore.Qt.DisplayRole):
|
|
59
|
-
if index.isValid():
|
|
60
|
-
if role == QtCore.Qt.EditRole:
|
|
61
|
-
return self._df.values[index.row()][index.column()]
|
|
62
|
-
elif role == QtCore.Qt.DisplayRole:
|
|
63
|
-
return self._df.values[index.row()][index.column()]
|
|
64
|
-
return None
|
|
65
|
-
|
|
66
|
-
def data_row_dict(self, row):
|
|
67
|
-
return self._df.iloc[row].to_dict()
|
|
68
|
-
|
|
69
|
-
def setData(self, index, value, role):
|
|
70
|
-
row = self._df.index[index.row()]
|
|
71
|
-
col = self._df.columns[index.column()]
|
|
72
|
-
self._df.values[row][col] = value
|
|
73
|
-
self.dataChanged.emit(index, index)
|
|
74
|
-
return True
|
|
75
|
-
|
|
76
|
-
def rowCount(self, parent=QtCore.QModelIndex()):
|
|
77
|
-
return len(self._df.index)
|
|
78
|
-
|
|
79
|
-
def columnCount(self, parent=QtCore.QModelIndex()):
|
|
80
|
-
return len(self._df.columns)
|
|
81
|
-
|
|
82
|
-
def sort(self, column, order):
|
|
83
|
-
col_name = self._df.columns.tolist()[column]
|
|
84
|
-
self.layoutAboutToBeChanged.emit()
|
|
85
|
-
self._df.sort_values(
|
|
86
|
-
col_name, ascending=order == QtCore.Qt.AscendingOrder, inplace=True
|
|
87
|
-
)
|
|
88
|
-
self._df.reset_index(inplace=True, drop=True)
|
|
89
|
-
self.layoutChanged.emit()
|
|
90
|
-
|
|
91
|
-
def insertRows(self, position, rows=1, index=QtCore.QModelIndex()):
|
|
92
|
-
self.beginInsertRows(QtCore.QModelIndex(), position, position + rows - 1)
|
|
93
|
-
for i in range(rows):
|
|
94
|
-
self._df.loc[len(self._df)] = self.default_record
|
|
95
|
-
|
|
96
|
-
self.endInsertRows()
|
|
97
|
-
return True
|
|
98
|
-
|
|
99
|
-
def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
|
|
100
|
-
self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
|
|
101
|
-
for i in range(rows):
|
|
102
|
-
self._df.drop(self._df.index[position + i], inplace=True)
|
|
103
|
-
print('removed: {}'.format(position + i))
|
|
104
|
-
|
|
105
|
-
self.endRemoveRows()
|
|
106
|
-
return True
|
|
107
|
-
|
|
108
|
-
def updateRow(self, row, row_data):
|
|
109
|
-
self._df.loc[row] = row_data
|
|
110
|
-
self.dataChanged(row, 0)
|
|
111
|
-
|
|
112
|
-
def save_csv(self, csv_file):
|
|
113
|
-
self._df.to_csv(csv_file, index=False)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
class BPDialog(QtWidgets.QDialog):
|
|
117
|
-
"""Batch Processing Dialog."""
|
|
118
|
-
|
|
119
|
-
# signals
|
|
120
|
-
signal_update_tool_widgets = QtCore.pyqtSignal(int)
|
|
121
|
-
|
|
122
|
-
def __init__(self, tool_name, parent=None):
|
|
123
|
-
super(BPDialog, self).__init__(parent)
|
|
124
|
-
self.setWindowTitle('Batch Processing')
|
|
125
|
-
self.MaxRecentFiles = 5
|
|
126
|
-
self.window_list = []
|
|
127
|
-
self.recent_files = []
|
|
128
|
-
self.settings = QtCore.QSettings('Richard Zeng', 'Batch Processing')
|
|
129
|
-
self.filename = ""
|
|
130
|
-
self.setGeometry(0, 0, 800, 600)
|
|
131
|
-
|
|
132
|
-
# table view
|
|
133
|
-
self.table_view = QtWidgets.QTableView()
|
|
134
|
-
self.table_view.verticalHeader().setVisible(True)
|
|
135
|
-
self.model = _PandasModel()
|
|
136
|
-
self.table_view.setModel(self.model)
|
|
137
|
-
self.table_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
|
138
|
-
self.table_view.setSelectionBehavior(self.table_view.SelectRows)
|
|
139
|
-
self.table_view.setSelectionMode(self.table_view.ExtendedSelection)
|
|
140
|
-
|
|
141
|
-
self.table_view.clicked.connect(self.table_view_clicked)
|
|
142
|
-
self.table_view.verticalHeader().sectionClicked.connect(
|
|
143
|
-
self.table_view_vertical_header_clicked
|
|
144
|
-
)
|
|
145
|
-
QtWidgets.QShortcut(
|
|
146
|
-
QtCore.Qt.Key_Up, self.table_view, activated=self.table_view_key_up
|
|
147
|
-
)
|
|
148
|
-
QtWidgets.QShortcut(
|
|
149
|
-
QtCore.Qt.Key_Down, self.table_view, activated=self.table_view_key_down
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
# create form
|
|
153
|
-
self.tool_name = tool_name
|
|
154
|
-
tool_args = bt.get_bera_tool_args(self.tool_name)
|
|
155
|
-
self.tool_widgets = ToolWidgets(tool_name, tool_args, False)
|
|
156
|
-
|
|
157
|
-
# self.createToolBar()
|
|
158
|
-
hbox_widgets = QtWidgets.QHBoxLayout()
|
|
159
|
-
hbox_widgets.addWidget(self.table_view, 2)
|
|
160
|
-
hbox_widgets.addWidget(self.tool_widgets, 1)
|
|
161
|
-
|
|
162
|
-
# Add project, record related button box
|
|
163
|
-
self.project_btns = QtWidgets.QHBoxLayout()
|
|
164
|
-
open_button = QtWidgets.QPushButton('Open')
|
|
165
|
-
save_button = QtWidgets.QPushButton('Save')
|
|
166
|
-
save_as_button = QtWidgets.QPushButton('Save as')
|
|
167
|
-
delete_button = QtWidgets.QPushButton('Delete records')
|
|
168
|
-
add_button = QtWidgets.QPushButton('Add record')
|
|
169
|
-
print_button = QtWidgets.QPushButton('Print')
|
|
170
|
-
|
|
171
|
-
open_button.clicked.connect(self.load_csv)
|
|
172
|
-
save_button.setShortcut(QtGui.QKeySequence.Open)
|
|
173
|
-
save_button.clicked.connect(self.write_csv_update)
|
|
174
|
-
save_button.setShortcut(QtGui.QKeySequence.Save)
|
|
175
|
-
save_as_button.clicked.connect(self.write_csv)
|
|
176
|
-
save_as_button.setShortcut(QtGui.QKeySequence.SaveAs)
|
|
177
|
-
delete_button.clicked.connect(self.table_view_delete_records)
|
|
178
|
-
delete_button.setShortcut(QtGui.QKeySequence.Delete)
|
|
179
|
-
|
|
180
|
-
add_button.clicked.connect(self.table_view_add_records)
|
|
181
|
-
|
|
182
|
-
self.last_files = QtWidgets.QComboBox()
|
|
183
|
-
self.last_files.setFixedWidth(300)
|
|
184
|
-
self.last_files.currentIndexChanged.connect(self.load_recent)
|
|
185
|
-
|
|
186
|
-
self.line_find = QtWidgets.QLineEdit()
|
|
187
|
-
self.line_find.setPlaceholderText("find")
|
|
188
|
-
self.line_find.setClearButtonEnabled(True)
|
|
189
|
-
self.line_find.setFixedWidth(250)
|
|
190
|
-
self.line_find.returnPressed.connect(self.find_in_table)
|
|
191
|
-
|
|
192
|
-
print_button.clicked.connect(self.handle_preview)
|
|
193
|
-
|
|
194
|
-
self.project_btns.addWidget(open_button, QtWidgets.QDialogButtonBox.ActionRole)
|
|
195
|
-
self.project_btns.addWidget(save_button, QtWidgets.QDialogButtonBox.ActionRole)
|
|
196
|
-
self.project_btns.addWidget(save_as_button, QtWidgets.QDialogButtonBox.ActionRole)
|
|
197
|
-
self.project_btns.addWidget(delete_button, QtWidgets.QDialogButtonBox.ActionRole)
|
|
198
|
-
self.project_btns.addWidget(add_button, QtWidgets.QDialogButtonBox.ActionRole)
|
|
199
|
-
self.project_btns.addWidget(self.line_find, QtWidgets.QDialogButtonBox.ActionRole)
|
|
200
|
-
self.project_btns.addWidget(print_button, QtWidgets.QDialogButtonBox.ActionRole)
|
|
201
|
-
|
|
202
|
-
# Add OK/cancel buttons
|
|
203
|
-
self.ok_btn_box = QtWidgets.QDialogButtonBox()
|
|
204
|
-
self.ok_btn_box.addButton("Run", QtWidgets.QDialogButtonBox.AcceptRole)
|
|
205
|
-
self.ok_btn_box.addButton("Cancel", QtWidgets.QDialogButtonBox.RejectRole)
|
|
206
|
-
self.ok_btn_box.addButton("Help", QtWidgets.QDialogButtonBox.HelpRole)
|
|
207
|
-
|
|
208
|
-
self.ok_btn_box.accepted.connect(self.run)
|
|
209
|
-
self.ok_btn_box.rejected.connect(self.reject)
|
|
210
|
-
self.ok_btn_box.helpRequested.connect(self.help)
|
|
211
|
-
|
|
212
|
-
hbox_btns = QtWidgets.QHBoxLayout()
|
|
213
|
-
hbox_btns.addLayout(self.project_btns)
|
|
214
|
-
hbox_btns.addWidget(self.ok_btn_box)
|
|
215
|
-
|
|
216
|
-
vbox_main = QtWidgets.QVBoxLayout()
|
|
217
|
-
vbox_main.addLayout(hbox_widgets)
|
|
218
|
-
vbox_main.addLayout(hbox_btns)
|
|
219
|
-
self.setLayout(vbox_main)
|
|
220
|
-
|
|
221
|
-
# delete dialog when close
|
|
222
|
-
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
|
223
|
-
|
|
224
|
-
self.setContentsMargins(10, 10, 10, 10)
|
|
225
|
-
self.read_settings()
|
|
226
|
-
self.table_view.setFocus()
|
|
227
|
-
# self.statusBar().showMessage("Ready", 0)
|
|
228
|
-
|
|
229
|
-
# signals
|
|
230
|
-
self.tool_widgets.signal_save_tool_params.connect(self.table_view_update_record)
|
|
231
|
-
self.signal_update_tool_widgets.connect(self.update_tool_widgets)
|
|
232
|
-
|
|
233
|
-
def accept(self):
|
|
234
|
-
if self.line_find.hasFocus():
|
|
235
|
-
return
|
|
236
|
-
|
|
237
|
-
print("Run the batch processing.")
|
|
238
|
-
QtWidgets.QDialog.accept(self)
|
|
239
|
-
|
|
240
|
-
def run(self):
|
|
241
|
-
self.model.save_csv(self.filename)
|
|
242
|
-
self.accept()
|
|
243
|
-
|
|
244
|
-
def reject(self):
|
|
245
|
-
print("Batch processing canceled.")
|
|
246
|
-
self.close()
|
|
247
|
-
|
|
248
|
-
def help(self):
|
|
249
|
-
print("Help requested.")
|
|
250
|
-
|
|
251
|
-
def table_view_clicked(self, item):
|
|
252
|
-
print('Row, column:{}, {}'.format(item.row(), item.column()))
|
|
253
|
-
self.signal_update_tool_widgets.emit(item.row())
|
|
254
|
-
|
|
255
|
-
def table_view_vertical_header_clicked(self, item):
|
|
256
|
-
print('Horizontal header clicked: {}'.format(item))
|
|
257
|
-
self.signal_update_tool_widgets.emit(item)
|
|
258
|
-
|
|
259
|
-
def table_view_key_up(self):
|
|
260
|
-
current_row = self.table_view.selectionModel().selectedRows()[-1].row()
|
|
261
|
-
if current_row >= 1:
|
|
262
|
-
self.table_view.selectRow(current_row - 1)
|
|
263
|
-
self.signal_update_tool_widgets.emit(current_row - 1)
|
|
264
|
-
|
|
265
|
-
def table_view_delete_records(self):
|
|
266
|
-
selected_index = self.table_view.selectionModel().selectedRows()
|
|
267
|
-
rows = [item.row() for item in selected_index]
|
|
268
|
-
rows.sort(reverse=True)
|
|
269
|
-
|
|
270
|
-
for i in rows:
|
|
271
|
-
self.model.removeRows(i)
|
|
272
|
-
|
|
273
|
-
current_row = i
|
|
274
|
-
if self.model.rowCount() > 0:
|
|
275
|
-
if current_row > self.model.rowCount() - 1:
|
|
276
|
-
current_row = self.model.rowCount() - 1
|
|
277
|
-
|
|
278
|
-
self.table_view.selectRow(current_row)
|
|
279
|
-
self.signal_update_tool_widgets.emit(current_row)
|
|
280
|
-
|
|
281
|
-
print('remove row {}'.format(i))
|
|
282
|
-
|
|
283
|
-
self.model.submit()
|
|
284
|
-
|
|
285
|
-
def table_view_add_records(self):
|
|
286
|
-
self.model.default_record = bt.get_bera_tool_parameters_list(self.tool_name)
|
|
287
|
-
ret = self.model.insertRow(self.model.rowCount())
|
|
288
|
-
if ret:
|
|
289
|
-
count = self.model.rowCount() - 1
|
|
290
|
-
self.table_view.selectRow(count)
|
|
291
|
-
self.signal_update_tool_widgets.emit(count)
|
|
292
|
-
|
|
293
|
-
print('Insert row in position {}'.format(count))
|
|
294
|
-
self.model.submit()
|
|
295
|
-
|
|
296
|
-
def table_view_update_record(self, row_data):
|
|
297
|
-
current_row = self.table_view.selectionModel().selectedRows()[-1].row()
|
|
298
|
-
self.model.updateRow(current_row, row_data)
|
|
299
|
-
|
|
300
|
-
def update_tool_widgets(self, row):
|
|
301
|
-
tool_params = self.model.data_row_dict(row)
|
|
302
|
-
self.tool_widgets.update_widgets(tool_params)
|
|
303
|
-
print('Update tool parameters for record {}'.format(tool_params))
|
|
304
|
-
|
|
305
|
-
def table_view_key_down(self):
|
|
306
|
-
current_row = self.table_view.selectionModel().selectedRows()[-1].row()
|
|
307
|
-
if current_row < self.model.rowCount() - 1:
|
|
308
|
-
self.table_view.selectRow(current_row + 1)
|
|
309
|
-
self.signal_update_tool_widgets.emit(current_row + 1)
|
|
310
|
-
|
|
311
|
-
def read_settings(self):
|
|
312
|
-
print("reading settings")
|
|
313
|
-
if self.settings.contains("geometry"):
|
|
314
|
-
self.setGeometry(self.settings.value('geometry'))
|
|
315
|
-
if self.settings.contains("recentFiles"):
|
|
316
|
-
self.recent_files = self.settings.value('recentFiles')
|
|
317
|
-
self.last_files.addItem("last Files")
|
|
318
|
-
self.last_files.addItems(self.recent_files[:15])
|
|
319
|
-
|
|
320
|
-
def save_settings(self):
|
|
321
|
-
print("saving settings")
|
|
322
|
-
self.settings.setValue('geometry', self.geometry())
|
|
323
|
-
self.settings.setValue('recentFiles', self.recent_files)
|
|
324
|
-
|
|
325
|
-
def closeEvent(self, event):
|
|
326
|
-
print(self.model.setChanged)
|
|
327
|
-
if self.model.setChanged:
|
|
328
|
-
print("is changed, saving?")
|
|
329
|
-
quit_msg = "<b>The document was changed.<br>Do you want to save the changes?</ b>"
|
|
330
|
-
reply = QtWidgets.QMessageBox.question(
|
|
331
|
-
self,
|
|
332
|
-
"Save Confirmation",
|
|
333
|
-
quit_msg,
|
|
334
|
-
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
|
|
335
|
-
QtWidgets.QMessageBox.Yes,
|
|
336
|
-
)
|
|
337
|
-
if reply == QtWidgets.QMessageBox.Yes:
|
|
338
|
-
self.write_csv_update()
|
|
339
|
-
else:
|
|
340
|
-
print("Settings not saved.")
|
|
341
|
-
return
|
|
342
|
-
else:
|
|
343
|
-
print("nothing changed.")
|
|
344
|
-
self.save_settings()
|
|
345
|
-
|
|
346
|
-
def load_recent(self):
|
|
347
|
-
if self.last_files.currentIndex() > 0:
|
|
348
|
-
print(self.last_files.currentText())
|
|
349
|
-
print(self.model.setChanged)
|
|
350
|
-
if self.model.setChanged:
|
|
351
|
-
print("is changed, saving?")
|
|
352
|
-
quit_msg = "<b>The document was changed.<br>Save the changes?</ b>"
|
|
353
|
-
reply = QtWidgets.QMessageBox.question(
|
|
354
|
-
self,
|
|
355
|
-
"Save Confirmation",
|
|
356
|
-
quit_msg,
|
|
357
|
-
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
|
|
358
|
-
QtWidgets.QMessageBox.Yes,
|
|
359
|
-
)
|
|
360
|
-
if reply == QtWidgets.QMessageBox.Yes:
|
|
361
|
-
self.open_csv(self.last_files.currentText())
|
|
362
|
-
else:
|
|
363
|
-
self.open_csv(self.last_files.currentText())
|
|
364
|
-
else:
|
|
365
|
-
self.open_csv(self.last_files.currentText())
|
|
366
|
-
|
|
367
|
-
def open_csv(self, path):
|
|
368
|
-
f = open(path, 'r+b')
|
|
369
|
-
with f:
|
|
370
|
-
df = pd.read_csv(f, sep='\t|;|,|\s+', keep_default_na=False, engine='python',
|
|
371
|
-
skipinitialspace=True, skip_blank_lines=True)
|
|
372
|
-
f.close()
|
|
373
|
-
self.filename = path
|
|
374
|
-
|
|
375
|
-
self.model = _PandasModel(df)
|
|
376
|
-
self.table_view.setModel(self.model)
|
|
377
|
-
self.table_view.resizeColumnsToContents()
|
|
378
|
-
self.table_view.selectRow(0)
|
|
379
|
-
self.signal_update_tool_widgets.emit(0)
|
|
380
|
-
# self.statusBar().showMessage("%s %s" % (path, "loaded"), 0)
|
|
381
|
-
|
|
382
|
-
def find_in_table(self):
|
|
383
|
-
self.table_view.clearSelection()
|
|
384
|
-
text = self.line_find.text()
|
|
385
|
-
model = self.table_view.model()
|
|
386
|
-
for column in range(self.model.columnCount()):
|
|
387
|
-
start = model.index(0, column)
|
|
388
|
-
matches = model.match(
|
|
389
|
-
start, QtCore.Qt.DisplayRole, text, -1, QtCore.Qt.MatchContains
|
|
390
|
-
)
|
|
391
|
-
if matches:
|
|
392
|
-
for index in matches:
|
|
393
|
-
self.table_view.selectionModel().select(
|
|
394
|
-
index, QtCore.QItemSelectionModel.Select
|
|
395
|
-
)
|
|
396
|
-
|
|
397
|
-
def open_file(self, path=None):
|
|
398
|
-
print(self.model.setChanged)
|
|
399
|
-
if self.model.setChanged:
|
|
400
|
-
print("is changed, saving?")
|
|
401
|
-
quit_msg = "<b>The document was changed.<br>Save the changes?</ b>"
|
|
402
|
-
reply = QtWidgets.QMessageBox.question(
|
|
403
|
-
self,
|
|
404
|
-
"Save Confirmation",
|
|
405
|
-
quit_msg,
|
|
406
|
-
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
|
|
407
|
-
QtWidgets.QMessageBox.Yes,
|
|
408
|
-
)
|
|
409
|
-
if reply == QtWidgets.QMessageBox.Yes:
|
|
410
|
-
self.write_csv_update()
|
|
411
|
-
else:
|
|
412
|
-
print("not saved, loading ...")
|
|
413
|
-
return
|
|
414
|
-
path, _ = QtWidgets.QFileDialog.getOpenFileName(
|
|
415
|
-
self,
|
|
416
|
-
"Open File",
|
|
417
|
-
QtCore.QDir.homePath() + "/Document/CSV/",
|
|
418
|
-
"CSV Files (*.csv)",
|
|
419
|
-
)
|
|
420
|
-
if path:
|
|
421
|
-
return path
|
|
422
|
-
|
|
423
|
-
def load_csv(self):
|
|
424
|
-
file_name = self.open_file()
|
|
425
|
-
if file_name:
|
|
426
|
-
print(file_name + " loaded")
|
|
427
|
-
f = open(file_name, 'r+b')
|
|
428
|
-
with f:
|
|
429
|
-
df = pd.read_csv(
|
|
430
|
-
f,
|
|
431
|
-
sep="\t|;|,|\s+",
|
|
432
|
-
keep_default_na=False,
|
|
433
|
-
engine="python",
|
|
434
|
-
skipinitialspace=True,
|
|
435
|
-
skip_blank_lines=True,
|
|
436
|
-
)
|
|
437
|
-
f.close()
|
|
438
|
-
self.model = _PandasModel(df)
|
|
439
|
-
self.table_view.setModel(self.model)
|
|
440
|
-
self.table_view.resizeColumnsToContents()
|
|
441
|
-
self.table_view.selectRow(0)
|
|
442
|
-
# self.statusBar().showMessage("%s %s" % (fileName, "loaded"), 0)
|
|
443
|
-
self.recent_files.insert(0, file_name)
|
|
444
|
-
self.last_files.insertItem(1, file_name)
|
|
445
|
-
|
|
446
|
-
def write_csv(self):
|
|
447
|
-
file_name, _ = QtWidgets.QFileDialog.getSaveFileName(
|
|
448
|
-
self, "Open File", self.filename, "CSV Files (*.csv)"
|
|
449
|
-
)
|
|
450
|
-
|
|
451
|
-
if file_name:
|
|
452
|
-
print(file_name + " saved")
|
|
453
|
-
f = open(file_name, 'w')
|
|
454
|
-
new_model = self.model
|
|
455
|
-
data_frame = new_model._df.copy()
|
|
456
|
-
data_frame.to_csv(f, sep=',', index=False, header=True, lineterminator='\n')
|
|
457
|
-
|
|
458
|
-
def write_csv_update(self):
|
|
459
|
-
if self.filename:
|
|
460
|
-
f = open(self.filename, 'w')
|
|
461
|
-
new_model = self.model
|
|
462
|
-
data_frame = new_model._df.copy()
|
|
463
|
-
data_frame.to_csv(f, sep='\t', index=False, header=False)
|
|
464
|
-
self.model.setChanged = False
|
|
465
|
-
print("%s %s" % (self.filename, "saved"))
|
|
466
|
-
# self.statusBar().showMessage("%s %s" % (self.filename, "saved"), 0)
|
|
467
|
-
|
|
468
|
-
def handle_preview(self):
|
|
469
|
-
if self.model.rowCount() == 0:
|
|
470
|
-
self.msg("no rows")
|
|
471
|
-
else:
|
|
472
|
-
dialog = QtPrintSupport.QPrintPreviewDialog()
|
|
473
|
-
dialog.setFixedSize(1000, 700)
|
|
474
|
-
dialog.paintRequested.connect(self.handle_paint_request)
|
|
475
|
-
dialog.exec_()
|
|
476
|
-
print("Print Preview closed")
|
|
477
|
-
|
|
478
|
-
def handle_paint_request(self, printer):
|
|
479
|
-
printer.setDocName(self.filename)
|
|
480
|
-
document = QtGui.QTextDocument()
|
|
481
|
-
cursor = QtGui.QTextCursor(document)
|
|
482
|
-
model = self.table_view.model()
|
|
483
|
-
table_format = QtGui.QTextTableFormat()
|
|
484
|
-
table_format.setBorder(0.2)
|
|
485
|
-
table_format.setBorderStyle(3)
|
|
486
|
-
table_format.setCellSpacing(0)
|
|
487
|
-
table_format.setTopMargin(0)
|
|
488
|
-
table_format.setCellPadding(4)
|
|
489
|
-
model = self.table_view.model()
|
|
490
|
-
|
|
491
|
-
# get headers
|
|
492
|
-
my_header = []
|
|
493
|
-
for i in range(0, model.columnCount()):
|
|
494
|
-
my_header = model.headerData(i, QtCore.Qt.Horizontal)
|
|
495
|
-
cursor.insertText(str(my_header))
|
|
496
|
-
cursor.movePosition(QtGui.QTextCursor.NextCell)
|
|
497
|
-
# get cells
|
|
498
|
-
for row in range(0, model.rowCount()):
|
|
499
|
-
for col in range(0, model.columnCount()):
|
|
500
|
-
index = model.index(row, col)
|
|
501
|
-
cursor.insertText(str(index.data()))
|
|
502
|
-
cursor.movePosition(QtGui.QTextCursor.NextCell)
|
|
503
|
-
document.print_(printer)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if __name__ == "__main__":
|
|
507
|
-
app = QtCore.QApplication(sys.argv)
|
|
508
|
-
main = BPDialog('Raster Line Attributes')
|
|
509
|
-
main.show()
|
|
510
|
-
if len(sys.argv) > 1:
|
|
511
|
-
main.open_csv(sys.argv[1])
|
|
512
|
-
|
|
513
|
-
sys.exit(app.exec_())
|
beratools/gui/map_window.py
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
os.environ["QT_API"] = "pyqt5"
|
|
5
|
-
from pyqtlet2 import L, MapWidget
|
|
6
|
-
from qtpy.QtCore import Qt, Signal
|
|
7
|
-
from qtpy.QtWidgets import (
|
|
8
|
-
QApplication,
|
|
9
|
-
QDialog,
|
|
10
|
-
QDialogButtonBox,
|
|
11
|
-
QGroupBox,
|
|
12
|
-
QHBoxLayout,
|
|
13
|
-
QTreeWidget,
|
|
14
|
-
QTreeWidgetItem,
|
|
15
|
-
QVBoxLayout,
|
|
16
|
-
QWidget,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class MapWindow(QDialog):
|
|
21
|
-
def __init__(self, parent=None):
|
|
22
|
-
# Setting up the widgets and layout
|
|
23
|
-
super(MapWindow, self).__init__(parent)
|
|
24
|
-
self.setWindowTitle("Tiler map")
|
|
25
|
-
self.setGeometry(0, 0, 1200, 800)
|
|
26
|
-
|
|
27
|
-
# delete dialog when close
|
|
28
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
29
|
-
|
|
30
|
-
# Add OK/cancel buttons
|
|
31
|
-
self.ok_btn_box = QDialogButtonBox(Qt.Vertical)
|
|
32
|
-
self.ok_btn_box.addButton("Run Tiler", QDialogButtonBox.AcceptRole)
|
|
33
|
-
self.ok_btn_box.addButton("Cancel", QDialogButtonBox.RejectRole)
|
|
34
|
-
self.ok_btn_box.addButton("Help", QDialogButtonBox.HelpRole)
|
|
35
|
-
|
|
36
|
-
self.ok_btn_box.buttons()[0].setFixedSize(120, 40)
|
|
37
|
-
self.ok_btn_box.buttons()[1].setFixedSize(120, 40)
|
|
38
|
-
self.ok_btn_box.buttons()[2].setFixedSize(120, 40)
|
|
39
|
-
|
|
40
|
-
self.ok_btn_box.accepted.connect(self.run)
|
|
41
|
-
self.ok_btn_box.rejected.connect(self.cancel)
|
|
42
|
-
self.ok_btn_box.helpRequested.connect(self.help)
|
|
43
|
-
|
|
44
|
-
self.info_layout = QVBoxLayout() # layout reserved for tiles info widgets
|
|
45
|
-
self.vbox_group = QVBoxLayout()
|
|
46
|
-
self.vbox_group.addLayout(self.info_layout)
|
|
47
|
-
self.vbox_group.addStretch()
|
|
48
|
-
self.vbox_group.addWidget(self.ok_btn_box, alignment=Qt.AlignCenter)
|
|
49
|
-
|
|
50
|
-
groupbox_info = QGroupBox("Tiles")
|
|
51
|
-
groupbox_info.setLayout(self.vbox_group)
|
|
52
|
-
|
|
53
|
-
central_widget = QWidget()
|
|
54
|
-
map_layout = QHBoxLayout(central_widget)
|
|
55
|
-
map_layout.addWidget(groupbox_info)
|
|
56
|
-
|
|
57
|
-
groupbox_map = QGroupBox("Map")
|
|
58
|
-
self.map_widget = MapWidget()
|
|
59
|
-
self.map_widget.setContentsMargins(10, 10, 10, 10)
|
|
60
|
-
self.vbox_map = QVBoxLayout()
|
|
61
|
-
self.vbox_map.addWidget(self.map_widget)
|
|
62
|
-
groupbox_map.setLayout(self.vbox_map)
|
|
63
|
-
map_layout.addWidget(groupbox_map, 10)
|
|
64
|
-
self.setLayout(map_layout)
|
|
65
|
-
|
|
66
|
-
# Working with the maps with pyqtlet
|
|
67
|
-
self.map = L.map(self.map_widget)
|
|
68
|
-
self.map.setView([0, 0], 10) # this is necessary
|
|
69
|
-
|
|
70
|
-
L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png").addTo(self.map)
|
|
71
|
-
|
|
72
|
-
# add marker layer
|
|
73
|
-
# self.add_marker_layer()
|
|
74
|
-
self.show()
|
|
75
|
-
|
|
76
|
-
def add_polygons_to_map(self, layer_name, polygons, color):
|
|
77
|
-
style = {"fillOpacity": 0.1, "color": color}
|
|
78
|
-
vars()[layer_name] = L.polygon(polygons, style)
|
|
79
|
-
self.map.addLayer(vars()[layer_name])
|
|
80
|
-
|
|
81
|
-
# this works too. addLayer has to be called first
|
|
82
|
-
# self.map.runJavaScript("var stylePoly = {fillColor:'red',color: 'blue',weight:2,fillOpacity:0.8};", 0)
|
|
83
|
-
# self.map.runJavaScript(f'{self.multipolygon.jsName}.setStyle(stylePoly);', 0)
|
|
84
|
-
|
|
85
|
-
def add_polylines_to_map(self, polylines, color):
|
|
86
|
-
style = {"color": color}
|
|
87
|
-
lines = L.polyline(polylines, style)
|
|
88
|
-
self.map.addLayer(lines)
|
|
89
|
-
|
|
90
|
-
def set_view(self, point, zoom):
|
|
91
|
-
self.map = self.map.setView(point, zoom)
|
|
92
|
-
|
|
93
|
-
# bounds is a pair of corner points, LL and UR
|
|
94
|
-
def fit_bounds(self, bounds):
|
|
95
|
-
# self.map.fitBounds(bounds)
|
|
96
|
-
self.map.runJavaScript(f"{self.map.jsName}.fitBounds(bounds);", 0)
|
|
97
|
-
|
|
98
|
-
def add_marker_layer(self):
|
|
99
|
-
self.marker = L.marker([12.934056, -77.610029])
|
|
100
|
-
self.marker.bindPopup("Maps are a treasure.")
|
|
101
|
-
self.map.addLayer(self.marker)
|
|
102
|
-
|
|
103
|
-
# Create a icon called markerIcon in the js runtime.
|
|
104
|
-
self.map.runJavaScript(
|
|
105
|
-
"var markerIcon "
|
|
106
|
-
'= L.icon({iconUrl: "https://leafletjs.com/examples/custom-icons/leaf-red.png"});',
|
|
107
|
-
0,
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
# Edit the existing python object by accessing it's jsName property
|
|
111
|
-
self.map.runJavaScript(f"{self.marker.jsName}.setIcon(markerIcon);", 0)
|
|
112
|
-
|
|
113
|
-
def accept(self):
|
|
114
|
-
print("Run the tiling.")
|
|
115
|
-
QDialog.accept(self)
|
|
116
|
-
|
|
117
|
-
def run(self):
|
|
118
|
-
self.accept()
|
|
119
|
-
|
|
120
|
-
def cancel(self):
|
|
121
|
-
print("Tiling canceled.")
|
|
122
|
-
self.reject()
|
|
123
|
-
|
|
124
|
-
def help(self):
|
|
125
|
-
print("Help requested.")
|
|
126
|
-
|
|
127
|
-
def set_tiles_info(self, tiles_info):
|
|
128
|
-
tree = QTreeWidget()
|
|
129
|
-
tree.setColumnCount(2)
|
|
130
|
-
tree.setHeaderLabels(["Item", "Value"])
|
|
131
|
-
item = QTreeWidgetItem(["Tiles"])
|
|
132
|
-
for key, value in tiles_info.items():
|
|
133
|
-
child = QTreeWidgetItem([key, str(value)])
|
|
134
|
-
item.addChild(child)
|
|
135
|
-
|
|
136
|
-
tree.insertTopLevelItem(0, item)
|
|
137
|
-
tree.expandAll()
|
|
138
|
-
|
|
139
|
-
# add to group widget
|
|
140
|
-
self.vbox_group.insertWidget(0, tree)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if __name__ == "__main__":
|
|
144
|
-
# supress web engine logging
|
|
145
|
-
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--enable-logging --log-level=3"
|
|
146
|
-
|
|
147
|
-
app = QApplication(sys.argv)
|
|
148
|
-
widget = MapWindow()
|
|
149
|
-
|
|
150
|
-
# add polygons to map
|
|
151
|
-
polygon_coords_base = [
|
|
152
|
-
[[17.285044, 78.286671], [16.606174, 80.748015], [17.886816, 83.518482]]
|
|
153
|
-
]
|
|
154
|
-
widget.add_polygons_to_map(polygon_coords_base, "blue")
|
|
155
|
-
|
|
156
|
-
polygon_coords = [
|
|
157
|
-
[[17.385044, 78.486671], [16.506174, 80.648015], [17.686816, 83.218482]],
|
|
158
|
-
[[13.082680, 80.270718], [12.971599, 77.594563], [15.828126, 78.037279]],
|
|
159
|
-
]
|
|
160
|
-
widget.add_polygons_to_map(polygon_coords, "red")
|
|
161
|
-
|
|
162
|
-
sys.exit(app.exec_())
|