Merge branch 'layer-flaten'
This commit is contained in:
commit
8b113331dd
10
log.txt
10
log.txt
@ -1,6 +1,4 @@
|
||||
2022-05-17 16:14:17,007 - root - INFO - lic data:2022-12-01 00:00:00
|
||||
2022-05-17 16:14:17,010 - root - INFO - remain_days: 197
|
||||
2022-05-17 16:14:18,338 - root - INFO - lic data:2022-12-01 00:00:00
|
||||
2022-05-17 16:14:18,338 - root - INFO - remain_days: 197
|
||||
2022-05-17 16:35:12,026 - root - INFO - Empty module name
|
||||
2022-05-17 16:35:13,397 - root - INFO - None
|
||||
2022-05-23 19:52:34,008 - root - INFO - lic data:2022-12-01 00:00:00
|
||||
2022-05-23 19:52:34,012 - root - INFO - remain_days: 191
|
||||
2022-05-23 19:52:35,282 - root - INFO - lic data:2022-12-01 00:00:00
|
||||
2022-05-23 19:52:35,282 - root - INFO - remain_days: 191
|
||||
|
@ -5,7 +5,7 @@ from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QAction, QDialog, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from rscder.utils.project import Project, PairLayer, ResultLayer
|
||||
from rscder.utils.project import BasicLayer, Project, PairLayer, ResultPointLayer, RasterLayer
|
||||
from rscder.gui.layercombox import LayerCombox
|
||||
from osgeo import gdal, gdal_array
|
||||
from threading import Thread
|
||||
@ -77,32 +77,19 @@ class BasicMethod(BasicPlugin):
|
||||
basic_diff_method.triggered.connect(self.basic_diff_alg)
|
||||
|
||||
self.message_send.connect(self.send_message)
|
||||
self.result_ok.connect(self.on_result_ok)
|
||||
# self.result_ok.connect(self.on_result_ok)
|
||||
|
||||
self.gap = 250
|
||||
|
||||
|
||||
def on_data_load(self, layer_id):
|
||||
def setup(self):
|
||||
self.basic_diff_method.setEnabled(True)
|
||||
|
||||
|
||||
def send_message(self, s):
|
||||
self.message_box.info(s)
|
||||
|
||||
def on_result_ok(self, data):
|
||||
layer = Project().layers[data['layer_id']]
|
||||
csv_result = ResultLayer('basic_diff_result', layer, ResultLayer.POINT)
|
||||
csv_result.load_file(data['csv_file'])
|
||||
|
||||
raster_layer = ResultLayer('basic_diff_result-raster',layer, ResultLayer.RASTER)
|
||||
raster_layer.load_file(data['raster_file'])
|
||||
layer.results.append(csv_result)
|
||||
layer.results.append(raster_layer)
|
||||
self.layer_tree.update_layer(layer.id)
|
||||
|
||||
def run_basic_diff_alg(self, layer:PairLayer, out):
|
||||
def run_basic_diff_alg(self, layer:PairLayer):
|
||||
|
||||
pth1 = layer.pth1
|
||||
pth2 = layer.pth2
|
||||
pth1 = layer.main_l1.path
|
||||
pth2 = layer.main_l2.path
|
||||
|
||||
cell_size = layer.cell_size
|
||||
|
||||
@ -118,7 +105,7 @@ class BasicMethod(BasicPlugin):
|
||||
geo = ds1.GetGeoTransform()
|
||||
|
||||
driver = gdal.GetDriverByName('GTiff')
|
||||
out_tif = os.path.join(out, 'temp.tif')
|
||||
out_tif = os.path.join(Project().cmi_path, 'temp.tif')
|
||||
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
|
||||
out_ds.SetGeoTransform(ds1.GetGeoTransform())
|
||||
out_ds.SetProjection(ds1.GetProjection())
|
||||
@ -155,7 +142,7 @@ class BasicMethod(BasicPlugin):
|
||||
self.message_send.emit('归一化概率中...')
|
||||
temp_in_ds = gdal.Open(out_tif)
|
||||
|
||||
out_normal_tif = os.path.join(out, '{}.tif'.format(int(np.random.rand() * 100000)))
|
||||
out_normal_tif = os.path.join(Project().cmi_path, '{}-{}.tif'.format(layer.name, int(np.random.rand() * 100000)))
|
||||
out_normal_ds = driver.Create(out_normal_tif, xsize, ysize, 1, gdal.GDT_Byte)
|
||||
out_normal_ds.SetGeoTransform(ds1.GetGeoTransform())
|
||||
out_normal_ds.SetProjection(ds1.GetProjection())
|
||||
@ -188,7 +175,7 @@ class BasicMethod(BasicPlugin):
|
||||
self.message_send.emit('完成归一化概率')
|
||||
|
||||
self.message_send.emit('计算变化表格中...')
|
||||
out_csv = os.path.join(out, '{}.csv'.format(int(np.random.rand() * 100000)))
|
||||
out_csv = os.path.join(Project().bcdm_path, '{}-{}.csv'.format(layer.name, int(np.random.rand() * 100000)))
|
||||
xblocks = xsize // cell_size[0]
|
||||
|
||||
normal_in_ds = gdal.Open(out_normal_tif)
|
||||
@ -215,11 +202,11 @@ class BasicMethod(BasicPlugin):
|
||||
f.write(f'{center_x},{center_y},{block_data_xy.mean() / 255 * 100},1\n')
|
||||
|
||||
|
||||
self.result_ok.emit({
|
||||
'layer_id': layer.id,
|
||||
'csv_file': out_csv,
|
||||
'raster_file': out_normal_tif
|
||||
})
|
||||
point_result_lalyer = ResultPointLayer(out_csv, enable=False, proj = layer.proj, geo = layer.geo)
|
||||
raster_result_layer = RasterLayer(None, True, out_normal_tif, BasicLayer.BOATH_VIEW)
|
||||
|
||||
layer.add_result_layer(point_result_lalyer)
|
||||
layer.add_result_layer(raster_result_layer)
|
||||
|
||||
self.message_send.emit('完成计算变化表格')
|
||||
|
||||
@ -237,11 +224,8 @@ class BasicMethod(BasicPlugin):
|
||||
|
||||
if not layer.check():
|
||||
return
|
||||
out_dir =os.path.join(self.project.root, 'basic_diff_result')
|
||||
if not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
t = Thread(target=self.run_basic_diff_alg, args=(layer, out_dir))
|
||||
|
||||
t = Thread(target=self.run_basic_diff_alg, args=(layer,))
|
||||
t.start()
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import shutil
|
||||
from rscder.utils.project import Project, PairLayer, ResultLayer
|
||||
from rscder.utils.project import Project, PairLayer, ResultPointLayer
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QFileDialog, QComboBox, QVBoxLayout, QPushButton, QLabel, QLineEdit, QAction
|
||||
from PyQt5.QtGui import QIcon
|
||||
@ -20,8 +20,8 @@ class ExportDialog(QDialog):
|
||||
|
||||
result_layer_select.addItem('---', None)
|
||||
for layer in Project().layers.values():
|
||||
for result_layer in layer.results:
|
||||
if result_layer.layer_type == ResultLayer.POINT:
|
||||
for result_layer in layer.layers:
|
||||
if isinstance(result_layer, ResultPointLayer):
|
||||
result_layer_select.addItem( layer.name[:5] + '-' + result_layer.name, result_layer)
|
||||
|
||||
for i in range(result_layer_select.count() - 1):
|
||||
|
@ -12,7 +12,7 @@ from rscder.utils.project import PairLayer, Project
|
||||
class LayerTree(QtWidgets.QWidget):
|
||||
|
||||
LAYER_TOOT = 0
|
||||
SUB_RASTER = 1
|
||||
SUB_LAYERS = 1
|
||||
RESULT = 2
|
||||
LEFT_RASTER = 0
|
||||
RIGHT_RASTER = 1
|
||||
@ -32,195 +32,85 @@ class LayerTree(QtWidgets.QWidget):
|
||||
self.tree.customContextMenuRequested.connect(self.right_menu_show)
|
||||
self.root=QTreeWidgetItem(self.tree)
|
||||
self.tree.setHeaderHidden(True)
|
||||
|
||||
# self.tree.setHeaderLabels(['图层'])
|
||||
self.root.setText(0,'图层')
|
||||
self.root.setIcon(0,QtGui.QIcon(':/icons/layer.png'))
|
||||
|
||||
|
||||
|
||||
self.tree.expandAll()
|
||||
|
||||
self.tree.addTopLevelItem(self.root)
|
||||
|
||||
self.tree.itemChanged.connect(self.onItemChanged)
|
||||
self.tree.itemExpanded.connect(self.onItemExpanded)
|
||||
|
||||
self._expand = True
|
||||
self.root.setExpanded(self._expand)
|
||||
|
||||
layout = QtWidgets.QGridLayout()
|
||||
layout.addWidget(self.tree)
|
||||
self.setLayout(layout)
|
||||
self.setLayoutDirection(Qt.LeftToRight)
|
||||
self.is_in_add_layer = False
|
||||
self.is_update_layer = False
|
||||
self.current_item = None
|
||||
|
||||
def onItemExpanded(self, item:QtWidgets.QTreeWidgetItem):
|
||||
if item == self.root:
|
||||
self._expand = item.isExpanded()
|
||||
return
|
||||
|
||||
if hasattr(item, 'item_update'):
|
||||
item.item_update(item)
|
||||
|
||||
def onItemChanged(self, item:QtWidgets.QTreeWidgetItem, column):
|
||||
if self.is_in_add_layer:
|
||||
if self.is_update_layer:
|
||||
return
|
||||
if item == self.root:
|
||||
return
|
||||
root = item
|
||||
if item.data(0, Qt.UserRole) != LayerTree.LAYER_TOOT:
|
||||
root = item.parent()
|
||||
|
||||
layer = Project().layers[root.data(0, Qt.UserRole + 1)]
|
||||
if item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
|
||||
layer.enable = item.checkState(0) == Qt.Checked
|
||||
if item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER:
|
||||
if item.data(0, Qt.UserRole + 1) == LayerTree.LEFT_RASTER:
|
||||
layer.l1_enable = item.checkState(0) == Qt.Checked
|
||||
elif item.data(0, Qt.UserRole + 1) == LayerTree.RIGHT_RASTER:
|
||||
layer.l2_enable = item.checkState(0) == Qt.Checked
|
||||
if item.data(0, Qt.UserRole) == LayerTree.RESULT:
|
||||
layer.results[item.data(0, Qt.UserRole + 1)].enable = item.checkState(0) == Qt.Checked
|
||||
|
||||
if item.data(0, Qt.UserRole) == LayerTree.GRID:
|
||||
layer.grid_enable = item.checkState(0) == Qt.Checked
|
||||
|
||||
self.tree_changed.emit()
|
||||
|
||||
def add_layer(self, layer:str):
|
||||
# self.tree.it
|
||||
self.is_in_add_layer = True
|
||||
layer:PairLayer = Project().layers[layer]
|
||||
item_root = QtWidgets.QTreeWidgetItem(self.root)
|
||||
item_root.setText(0,layer.name)
|
||||
item_root.setIcon(0, QtGui.QIcon(':/icons/document.png'))
|
||||
item_root.setData(0, Qt.UserRole, LayerTree.LAYER_TOOT)
|
||||
item_root.setData(0, Qt.UserRole + 1, layer.id)
|
||||
item_root.setCheckState(0, Qt.Checked if layer.enable else Qt.Unchecked)
|
||||
|
||||
self.add_sub_layer(item_root, layer)
|
||||
self.is_in_add_layer = False
|
||||
|
||||
def add_sub_layer(self, item_root, layer:PairLayer):
|
||||
# print(item_root.text(0))
|
||||
# print(layer.results.__len__())
|
||||
grid_item = QtWidgets.QTreeWidgetItem(item_root)
|
||||
grid_item.setText(0,'格网')
|
||||
grid_item.setData(0, Qt.UserRole, LayerTree.GRID)
|
||||
grid_item.setCheckState(0, Qt.Checked if layer.grid_enable else Qt.Unchecked)
|
||||
grid_item.setIcon(0, QtGui.QIcon(':/icons/grid.png'))
|
||||
|
||||
item1 = QtWidgets.QTreeWidgetItem(item_root)
|
||||
item1.setText(0, layer.l1_name)
|
||||
item1.setCheckState(0, Qt.Checked if layer.l1_enable else Qt.Unchecked)
|
||||
item1.setData(0, Qt.UserRole, LayerTree.SUB_RASTER)
|
||||
item1.setData(0, Qt.UserRole + 1, LayerTree.LEFT_RASTER)
|
||||
item1.setIcon(0, QtGui.QIcon(':/icons/layer.png'))
|
||||
|
||||
item2 = QtWidgets.QTreeWidgetItem(item_root)
|
||||
item2.setText(0, layer.l2_name)
|
||||
item2.setCheckState(0, Qt.Checked if layer.l2_enable else Qt.Unchecked)
|
||||
item2.setData(0, Qt.UserRole, LayerTree.SUB_RASTER)
|
||||
item2.setData(0, Qt.UserRole + 1, LayerTree.RIGHT_RASTER)
|
||||
item2.setIcon(0, QtGui.QIcon(':/icons/layer.png'))
|
||||
|
||||
for ri, item in enumerate(layer.results):
|
||||
item_result = QtWidgets.QTreeWidgetItem(item_root)
|
||||
item_result.setText(0, item.name)
|
||||
item_result.setCheckState(0, Qt.Checked if item.enable else Qt.Unchecked)
|
||||
item_result.setData(0, Qt.UserRole, LayerTree.RESULT)
|
||||
item_result.setData(0, Qt.UserRole + 1, ri)
|
||||
|
||||
item_result.setIcon(0, QtGui.QIcon(':/icons/vector.svg'))
|
||||
|
||||
self.tree.expandAll()
|
||||
|
||||
def update_layer(self, layer:str):
|
||||
self.is_in_add_layer = True
|
||||
layer:PairLayer = Project().layers[layer]
|
||||
|
||||
layer_root = None
|
||||
# pdb.set_trace()
|
||||
for idx in range(self.root.childCount()):
|
||||
item_root = self.root.child(idx)
|
||||
if item_root.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
|
||||
if item_root.data(0, Qt.UserRole + 1) == layer.id:
|
||||
layer_root = item_root
|
||||
break
|
||||
logging.info(layer_root.text(0))
|
||||
if layer_root is None:
|
||||
self.add_layer(layer.id)
|
||||
self._expand = item.isExpanded()
|
||||
return
|
||||
|
||||
layer_root.setText(0,layer.name)
|
||||
if hasattr(item, 'item_update'):
|
||||
item.item_update(item)
|
||||
|
||||
while layer_root.childCount() > 0:
|
||||
layer_root.removeChild(layer_root.child(0))
|
||||
|
||||
self.add_sub_layer(layer_root, layer)
|
||||
self.is_in_add_layer = False
|
||||
def update_layer(self):
|
||||
self.is_update_layer = True
|
||||
self.clear()
|
||||
for layer_group in Project().layers.values():
|
||||
item_root = layer_group.get_item(self.root)
|
||||
# self.root.addChild(item_root)
|
||||
layer_group.grid.get_item(item_root)
|
||||
for _, sub in enumerate(layer_group.layers):
|
||||
sub.get_item(item_root)
|
||||
# item_root.addChild(item)
|
||||
self.is_update_layer = False
|
||||
|
||||
def clear(self):
|
||||
self.tree.clear()
|
||||
self.root = QTreeWidgetItem(self.tree)
|
||||
self.root.setText(0,'图层')
|
||||
self.tree.addTopLevelItem(self.root)
|
||||
|
||||
def delete_layer(self):
|
||||
item = self.current_item
|
||||
if item is None:
|
||||
return
|
||||
if item == self.root:
|
||||
return
|
||||
root = item
|
||||
if item.data(0, Qt.UserRole) != LayerTree.LAYER_TOOT:
|
||||
root = item.parent()
|
||||
|
||||
if item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
|
||||
self.root.takeChild(self.root.indexOfChild(item))
|
||||
del Project().layers[root.data(0, Qt.UserRole + 1)]
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER:
|
||||
return
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.GRID:
|
||||
return
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.RESULT:
|
||||
root.takeChild(root.indexOfChild(item))
|
||||
del Project().layers[root.data(0, Qt.UserRole + 1)].results[item.data(0, Qt.UserRole + 1)]
|
||||
self.update_layer(root.data(0, Qt.UserRole + 1))
|
||||
self.tree_changed.emit(root.data(0, Qt.UserRole + 1))
|
||||
|
||||
def zoom_to_layer(self):
|
||||
item = self.current_item
|
||||
if item is None:
|
||||
return
|
||||
if item == self.root:
|
||||
return
|
||||
root = item
|
||||
if item.data(0, Qt.UserRole) != LayerTree.LAYER_TOOT:
|
||||
root = item.parent()
|
||||
|
||||
self.zoom_to_layer_signal.emit(root.data(0, Qt.UserRole + 1))
|
||||
|
||||
self.tree.expandAll()
|
||||
self.root.setText(0,'图层')
|
||||
self.root.setIcon(0,QtGui.QIcon(':/icons/layer.png'))
|
||||
self.root.setExpanded(self._expand)
|
||||
|
||||
def right_menu_show(self, position):
|
||||
rightMenu = QtWidgets.QMenu(self)
|
||||
# QAction = QtWidgets.QAction(self.menuBar1)
|
||||
|
||||
item = self.tree.itemAt(position)
|
||||
self.current_item = item
|
||||
action_manager = get_action_manager()
|
||||
actions = []
|
||||
data_load_action = action_manager.get_action('&数据加载', 'File')
|
||||
actions.append(data_load_action)
|
||||
zoom_to_action = QtWidgets.QAction(QIcon(':/icons/full.svg'), '&缩放至该图层', self)
|
||||
del_action = QtWidgets.QAction(QIcon(':/icons/delete.png'), '&删除该图层', self)
|
||||
zoom_to_action.triggered.connect(self.zoom_to_layer)
|
||||
del_action.triggered.connect(self.delete_layer)
|
||||
|
||||
if item is None:
|
||||
logging.info('nothing')
|
||||
else:
|
||||
if item == self.root:
|
||||
pass
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
|
||||
actions.append(zoom_to_action)
|
||||
actions.append(QtWidgets.QAction('&重命名', self))
|
||||
actions.append(del_action)
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER:
|
||||
actions.append(zoom_to_action)
|
||||
actions.append(QtWidgets.QAction('&重命名', self))
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.RESULT:
|
||||
actions.append(zoom_to_action)
|
||||
actions.append(QtWidgets.QAction('&重命名', self))
|
||||
actions.append(del_action)
|
||||
|
||||
|
||||
else:
|
||||
actions.extend(item.get_actions())
|
||||
|
||||
for action in actions:
|
||||
rightMenu.addAction(action)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import pdb
|
||||
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QToolBox
|
||||
from PyQt5.QtCore import Qt, QSize, QSettings
|
||||
from PyQt5.QtCore import Qt, QSize, QSettings, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5 import QtGui
|
||||
from PyQtAds import QtAds
|
||||
@ -15,6 +15,8 @@ from rscder.utils.project import Project
|
||||
from rscder.gui.layercombox import LayerCombox
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
closed = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None, **kargs):
|
||||
super().__init__(parent)
|
||||
# self.current_instance = kargs.get('current_instance', 0)
|
||||
@ -33,11 +35,8 @@ class MainWindow(QMainWindow):
|
||||
self.layer_tree,
|
||||
self.message_box,
|
||||
self.result_box)
|
||||
self.layer_tree.tree_changed.connect(self.double_map.layer_changed)
|
||||
self.layer_tree.result_clicked.connect(self.result_box.on_result)
|
||||
self.result_box.on_item_click.connect(self.double_map.zoom_to_result)
|
||||
self.result_box.on_item_changed.connect(Project().change_result)
|
||||
self.layer_tree.zoom_to_layer_signal.connect(self.double_map.zoom_to_layer)
|
||||
|
||||
self.result_box.on_item_click.connect(self.double_map.zoom_to_extent)
|
||||
|
||||
self.action_manager = ActionManager(
|
||||
self.double_map,
|
||||
@ -126,7 +125,7 @@ class MainWindow(QMainWindow):
|
||||
set_docker_fixed(self.message_dock)
|
||||
|
||||
def closeEvent(self, event):
|
||||
pass
|
||||
self.closed.emit()
|
||||
|
||||
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
|
||||
Settings.General().size = (a0.size().width(), a0.size().height())
|
||||
|
@ -20,7 +20,7 @@ import tempfile
|
||||
import cv2
|
||||
import os
|
||||
|
||||
from rscder.utils.project import PairLayer, Project
|
||||
from rscder.utils.project import BasicLayer, PairLayer, Project
|
||||
|
||||
class DoubleCanvas(QWidget):
|
||||
corr_changed = pyqtSignal(str)
|
||||
@ -106,18 +106,20 @@ class DoubleCanvas(QWidget):
|
||||
layer_list_2 = []
|
||||
for layer in layers.values():
|
||||
if layer.enable:
|
||||
if layer.grid_enable and self.grid_show:
|
||||
layer_list_1.append(layer.grid_layer.grid_layer)
|
||||
layer_list_2.append(layer.grid_layer.grid_layer)
|
||||
if layer.l1_enable:
|
||||
layer_list_1.append(layer.l1)
|
||||
if layer.l2_enable:
|
||||
layer_list_2.append(layer.l2)
|
||||
|
||||
for result in layer.results:
|
||||
if result.enable:
|
||||
layer_list_1.append(result.layer)
|
||||
layer_list_2.append(result.layer)
|
||||
if layer.grid.enable and self.grid_show:
|
||||
layer_list_1.append(layer.grid.layer)
|
||||
layer_list_2.append(layer.grid.layer)
|
||||
|
||||
for sub_layer in layer.layers:
|
||||
if sub_layer.enable:
|
||||
if sub_layer.view_mode == BasicLayer.LEFT_VIEW:
|
||||
layer_list_1.append(sub_layer.layer)
|
||||
elif sub_layer.view_mode == BasicLayer.RIGHT_VIEW:
|
||||
layer_list_2.append(sub_layer.layer)
|
||||
elif sub_layer.view_mode == BasicLayer.BOATH_VIEW:
|
||||
layer_list_2.append(sub_layer.layer)
|
||||
layer_list_1.append(sub_layer.layer)
|
||||
|
||||
|
||||
self.mapcanva1.setLayers(layer_list_1)
|
||||
self.mapcanva2.setLayers(layer_list_2)
|
||||
@ -149,22 +151,14 @@ class DoubleCanvas(QWidget):
|
||||
self.mapcanva1.refresh()
|
||||
self.mapcanva2.refresh()
|
||||
|
||||
def zoom_to_result(self, xydict:dict):
|
||||
x = xydict['x']
|
||||
y = xydict['y']
|
||||
if Project().current_layer is not None:
|
||||
layer = Project().current_layer
|
||||
else:
|
||||
layer = Project().layers[list(Project().layers.keys())[0]]
|
||||
|
||||
extent = QgsRectangle(x - layer.cell_size[0] * layer.xres, y - layer.cell_size[1] * layer.yres, x + layer.cell_size[0] * layer.xres, y + layer.cell_size[1] * layer.yres)
|
||||
def zoom_to_extent(self, extent):
|
||||
# extent = QgsRectangle(x - layer.cell_size[0] * layer.xres, y - layer.cell_size[1] * layer.yres, x + layer.cell_size[0] * layer.xres, y + layer.cell_size[1] * layer.yres)
|
||||
self.mapcanva1.set_extent(extent)
|
||||
self.mapcanva2.set_extent(extent)
|
||||
|
||||
def zoom_to_layer(self, layer:str):
|
||||
layer:PairLayer = Project().layers[layer]
|
||||
self.mapcanva1.set_extent(layer.l1.extent())
|
||||
self.mapcanva2.set_extent(layer.l2.extent())
|
||||
def zoom_to_layer(self, layer):
|
||||
self.mapcanva1.set_extent(layer.extent())
|
||||
self.mapcanva2.set_extent(layer.extent())
|
||||
def layer_changed(self, layer:str):
|
||||
self.add_layer(layer)
|
||||
|
||||
|
@ -4,29 +4,26 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import Qt,QModelIndex, pyqtSignal
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtWidgets import (QTableWidgetItem, QTableWidget, QMessageBox, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||
|
||||
from rscder.utils.project import PairLayer, Project, ResultLayer
|
||||
from qgis.core import QgsRectangle
|
||||
from rscder.utils.project import PairLayer, Project, ResultPointLayer
|
||||
|
||||
class ResultTable(QtWidgets.QWidget):
|
||||
|
||||
on_item_click = pyqtSignal(dict)
|
||||
on_item_click = pyqtSignal(QgsRectangle)
|
||||
on_item_changed = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ResultTable, self).__init__(parent)
|
||||
# self.tableview = QTableView(self)
|
||||
self.tablewidget = QTableWidget(self)
|
||||
self.tablewidget.setColumnCount(4)
|
||||
self.tablewidget.setColumnCount(3)
|
||||
self.tablewidget.setRowCount(0)
|
||||
self.tablewidget.setHorizontalHeaderLabels(['X', 'Y', '概率', '变化'])
|
||||
self.tablewidget.setHorizontalHeaderLabels(['变化位置(x,y)', '疑似变化概率', '目视判读'])
|
||||
self.tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
|
||||
self.tablewidget.cellDoubleClicked.connect(self.onDoubleClicked)
|
||||
self.tablewidget.cellClicked.connect(self.onClicked)
|
||||
# self.tablewidget.cellClicked.connect(self.onClicked)
|
||||
self.tablewidget.cellChanged.connect(self.onChanged)
|
||||
|
||||
# self.tablewidget.setModel(self.tableview)
|
||||
# self.tableview
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(self.tablewidget)
|
||||
self.setLayout(layout)
|
||||
@ -36,27 +33,44 @@ class ResultTable(QtWidgets.QWidget):
|
||||
|
||||
def clear(self):
|
||||
self.tablewidget.clear()
|
||||
self.tablewidget.setColumnCount(3)
|
||||
self.tablewidget.setRowCount(0)
|
||||
self.tablewidget.setHorizontalHeaderLabels(['变化位置(x,y)', '疑似变化概率', '目视判读'])
|
||||
|
||||
def onChanged(self, row, col):
|
||||
if self.is_in_set_data or self.no_change:
|
||||
return
|
||||
if col == 3:
|
||||
if col == 2:
|
||||
self.no_change = True
|
||||
item_idx = row
|
||||
item_status = self.tablewidget.item(row, col).checkState() == Qt.Checked
|
||||
if item_status:
|
||||
self.tablewidget.item(row, col).setBackground(Qt.yellow)
|
||||
self.tablewidget.item(row, col).setText('YES')
|
||||
else:
|
||||
self.tablewidget.item(row, col).setBackground(Qt.green)
|
||||
self.tablewidget.item(row, col).setText('NO')
|
||||
# logging
|
||||
# logging.info()
|
||||
self.result.update({'row':item_idx, 'value':item_status})
|
||||
self.no_change = False
|
||||
|
||||
def onDoubleClicked(self, row, col):
|
||||
x = self.tablewidget.item(row, 0).text()
|
||||
y = self.tablewidget.item(row, 1).text()
|
||||
self.on_item_click.emit({'x':float(x), 'y':float(y)})
|
||||
def onClicked(self, row, col):
|
||||
if col != 0:
|
||||
return
|
||||
data = self.result.data[row]
|
||||
x = data[0]
|
||||
y = data[1]
|
||||
xres = self.result.layer_parent.geo[1]
|
||||
yres = self.result.layer_parent.geo[5]
|
||||
cell_size = self.result.layer_parent.cell_size
|
||||
x_min = x - xres * cell_size[0]
|
||||
x_max = x + xres * cell_size[0]
|
||||
y_min = y - yres * cell_size[1]
|
||||
y_max = y + yres * cell_size[1]
|
||||
extent = QgsRectangle(x_min, y_min, x_max, y_max)
|
||||
|
||||
self.on_item_click.emit(extent)
|
||||
|
||||
def save(self):
|
||||
if self.result is None:
|
||||
@ -70,26 +84,27 @@ class ResultTable(QtWidgets.QWidget):
|
||||
self.save()
|
||||
self.result = result
|
||||
self.clear()
|
||||
self.set_data(result)
|
||||
def set_data(self, data:ResultLayer):
|
||||
self.show_result(result)
|
||||
|
||||
def show_result(self, data:ResultPointLayer):
|
||||
self.is_in_set_data = True
|
||||
if data.layer_type != ResultLayer.POINT:
|
||||
return
|
||||
self.result = data
|
||||
self.tablewidget.setRowCount(len(data.data))
|
||||
# print(len(data.data))
|
||||
self.tablewidget.setVerticalHeaderLabels([ str(i+1) for i in range(len(data.data))])
|
||||
for i, d in enumerate(data.data):
|
||||
self.tablewidget.setItem(i, 0, QTableWidgetItem(str(d[0]))) # X
|
||||
self.tablewidget.setItem(i, 1, QTableWidgetItem(str(d[1]))) # Y
|
||||
self.tablewidget.setItem(i, 2, QTableWidgetItem(str(d[2]))) # 概率
|
||||
status_item = QTableWidgetItem('变化')
|
||||
self.tablewidget.setItem(i, 0, QTableWidgetItem('%.3f,%.3f'%(d[0], d[1]))) # X
|
||||
self.tablewidget.setItem(i, 1, QTableWidgetItem('%.2f'%d[2])) # Y
|
||||
status_item = QTableWidgetItem('')
|
||||
if d[3] == 0:
|
||||
status_item.setBackground(Qt.green)
|
||||
status_item.setCheckState(Qt.Unchecked)
|
||||
status_item.setText('NO')
|
||||
elif d[3] == 1:
|
||||
status_item.setBackground(Qt.yellow)
|
||||
status_item.setCheckState(Qt.Checked)
|
||||
self.tablewidget.setItem(i, 3, status_item) # 变化
|
||||
status_item.setText('YES')
|
||||
self.tablewidget.setItem(i, 2, status_item) # 变化
|
||||
self.tablewidget.resizeColumnsToContents()
|
||||
self.tablewidget.resizeRowsToContents()
|
||||
self.tablewidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
|
@ -34,7 +34,7 @@ class BasicPlugin(QObject):
|
||||
self.project = ctx['project']
|
||||
self.mainwindow = ctx['mainwindow']
|
||||
self.set_action()
|
||||
self.project.layer_load.connect(self.on_data_load)
|
||||
# self.project.layer_load.connect(self.on_data_load)
|
||||
self.project.project_init.connect(self.setup)
|
||||
|
||||
|
||||
|
13
rscder/utils/icons.py
Normal file
13
rscder/utils/icons.py
Normal file
@ -0,0 +1,13 @@
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import QObject
|
||||
from .misc import singleton
|
||||
|
||||
@singleton
|
||||
class IconInstance(QObject):
|
||||
|
||||
def __init__(self, parent) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self.GRID_ON = QIcon(':/icons/grid.png')
|
||||
self.TABLE = QIcon(':/icons/table.png')
|
||||
self.DELETE = QIcon(':/icons/delete.png')
|
@ -1,4 +1,5 @@
|
||||
from functools import wraps
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
|
@ -1,16 +1,21 @@
|
||||
from cgitb import enable
|
||||
from collections import OrderedDict
|
||||
import inspect
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from threading import Thread
|
||||
from time import sleep, time
|
||||
from typing import Dict, List
|
||||
import uuid
|
||||
import numpy as np
|
||||
from osgeo import gdal, gdal_array
|
||||
from rscder.utils.icons import IconInstance
|
||||
from rscder.utils.setting import Settings
|
||||
from qgis.core import QgsRasterLayer, QgsMarkerSymbol, QgsUnitTypes, QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsPalLayerSettings, QgsRuleBasedLabeling, QgsTextFormat, QgsLineSymbol, QgsSingleSymbolRenderer, QgsSimpleLineSymbolLayer, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsGeometry, QgsPointXY
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
from PyQt5.QtGui import QColor
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, Qt, QThread
|
||||
from PyQt5.QtWidgets import QTreeWidgetItem, QAction
|
||||
from PyQt5.QtGui import QColor, QIcon, QFont
|
||||
import yaml
|
||||
from .misc import singleton
|
||||
|
||||
@ -20,27 +25,33 @@ def relative_path(path: str, root:str) -> str:
|
||||
@singleton
|
||||
class Project(QObject):
|
||||
|
||||
instance:'Project'
|
||||
|
||||
project_init = pyqtSignal(bool)
|
||||
layer_load = pyqtSignal(str)
|
||||
# layer_load = pyqtSignal()
|
||||
layer_tree_update = pyqtSignal()
|
||||
layer_show_update = pyqtSignal()
|
||||
|
||||
ABSOLUTE_MODE = 'absolute'
|
||||
RELATIVE_MODE = 'relative'
|
||||
|
||||
def run_auto_save(self):
|
||||
|
||||
# t = QThread(self)
|
||||
if self.in_save:
|
||||
return
|
||||
if not self.is_init:
|
||||
return
|
||||
if not Settings.General().auto_save:
|
||||
return
|
||||
t = Thread(target=self.auto_save)
|
||||
t.run()
|
||||
t.start()
|
||||
|
||||
def auto_save(self):
|
||||
# pre = time()
|
||||
while True:
|
||||
if Settings.General().auto_save and self.is_init:
|
||||
self.save()
|
||||
if self.is_closed:
|
||||
break
|
||||
sleep(Settings.General().auto_save_intervel)
|
||||
self.in_save = True
|
||||
self.save()
|
||||
self.in_save = False
|
||||
|
||||
|
||||
def __init__(self,
|
||||
parent=None):
|
||||
super().__init__(parent)
|
||||
@ -53,9 +64,17 @@ class Project(QObject):
|
||||
self.layers:Dict[str, PairLayer] = OrderedDict()
|
||||
self.current_layer = None
|
||||
self.is_closed = False
|
||||
self.in_save = False
|
||||
|
||||
def set_close():
|
||||
self.is_closed = True
|
||||
|
||||
parent.closed.connect(set_close)
|
||||
|
||||
self.run_auto_save()
|
||||
|
||||
def connect(self, pair_canvas,
|
||||
def connect(self,
|
||||
pair_canvas,
|
||||
layer_tree,
|
||||
message_box,
|
||||
result_table):
|
||||
@ -63,21 +82,14 @@ class Project(QObject):
|
||||
self.layer_tree = layer_tree
|
||||
self.message_box = message_box
|
||||
self.result_table = result_table
|
||||
|
||||
self.layer_load.connect(layer_tree.add_layer)
|
||||
self.layer_load.connect(pair_canvas.add_layer)
|
||||
|
||||
def change_result(self, layer_id, result_id, data):
|
||||
if layer_id in self.layers:
|
||||
result = self.layers[layer_id].results[result_id]
|
||||
|
||||
if result.layer_type == ResultLayer.POINT:
|
||||
result.update(data)
|
||||
elif result.layer_type == ResultLayer.RASTER:
|
||||
pass
|
||||
IconInstance(self)
|
||||
self.layer_tree_update.connect(layer_tree.update_layer)
|
||||
self.layer_show_update.connect(pair_canvas.update_layer)
|
||||
self.layer_tree_update.connect(self.run_auto_save)
|
||||
self.layer_show_update.connect(self.run_auto_save)
|
||||
|
||||
def setup(self, path = None, name = None):
|
||||
self.is_init = True
|
||||
|
||||
if path is not None:
|
||||
self.root = path
|
||||
if name is None:
|
||||
@ -91,8 +103,8 @@ class Project(QObject):
|
||||
pass
|
||||
else:
|
||||
self.load()
|
||||
# self.cmi_dir = str(Path(self.root)/'cmi')
|
||||
# self.project_created.emit()
|
||||
|
||||
self.is_init = True
|
||||
self.project_init.emit(True)
|
||||
|
||||
def save(self):
|
||||
@ -101,20 +113,18 @@ class Project(QObject):
|
||||
'max_memory': self.max_memory,
|
||||
'max_threads': self.max_threads,
|
||||
'root': self.root,
|
||||
'layers': [ layer.to_dict(None if self.file_mode == Project.ABSOLUTE_MODE else self.root) for layer in self.layers.values() ],
|
||||
'layers': [ layer.to_dict() for layer in self.layers.values() ],
|
||||
}
|
||||
for layer in self.layers.values():
|
||||
layer.save()
|
||||
# for layer in self.layers.values():
|
||||
# layer.save()
|
||||
with open(self.file, 'w') as f:
|
||||
yaml.safe_dump(data_dict, f)
|
||||
# yaml.safe_dump(data_dict, open(self.file, 'w'))
|
||||
|
||||
|
||||
def clear(self):
|
||||
'''
|
||||
clear all layers
|
||||
'''
|
||||
self.layers = dict()
|
||||
self.layers:Dict[str, PairLayer] = dict()
|
||||
self.layer_tree.clear()
|
||||
self.pair_canvas.clear()
|
||||
self.message_box.clear()
|
||||
@ -133,48 +143,181 @@ class Project(QObject):
|
||||
self.root = data['root']
|
||||
self.layers = dict()
|
||||
for layer in data['layers']:
|
||||
player = PairLayer.from_dict(layer, None if self.file_mode == Project.ABSOLUTE_MODE else self.root)
|
||||
player = PairLayer.from_dict(layer)
|
||||
if player.check():
|
||||
self.layers[player.id] = player
|
||||
self.layer_load.emit(player.id)
|
||||
|
||||
self.layer_show_update.emit()
|
||||
self.layer_tree_update.emit()
|
||||
if len(list(self.layers.values())) > 0:
|
||||
self.current_layer = list(self.layers.values())[0]
|
||||
self.pair_canvas.zoom_to_layer(list(self.layers.values())[0].main_l1.layer)
|
||||
|
||||
except Exception as e:
|
||||
self.message_box.error(str(e))
|
||||
self.clear()
|
||||
def add_layer(self, pth1, pth2):
|
||||
# self.root = str(Path(pth1).parent)
|
||||
|
||||
player = PairLayer(pth1, pth2, self.cell_size)
|
||||
if player.check():
|
||||
# self.layers.append(player)
|
||||
self.layers[player.id] = player
|
||||
self.layer_load.emit(player.id)
|
||||
else:
|
||||
self.message_box.error(player.msg)
|
||||
|
||||
class GridLayer:
|
||||
def zoom_to_layer(self, data):
|
||||
self.pair_canvas.zoom_to_layer(data['layer'])
|
||||
|
||||
@property
|
||||
def cmi_path(self):
|
||||
pth = os.path.join(self.root, 'cmi')
|
||||
if not os.path.exists(pth):
|
||||
os.makedirs(pth)
|
||||
return pth
|
||||
|
||||
@property
|
||||
def bcdm_path(self):
|
||||
pth = os.path.join(self.root, 'bcdm')
|
||||
if not os.path.exists(pth):
|
||||
os.makedirs(pth)
|
||||
return pth
|
||||
@property
|
||||
def evalution_path(self):
|
||||
pth = os.path.join(self.root, 'evalution')
|
||||
if not os.path.exists(pth):
|
||||
os.makedirs(pth)
|
||||
return pth
|
||||
|
||||
@property
|
||||
def other_path(self):
|
||||
pth = os.path.join(self.root, 'other')
|
||||
if not os.path.exists(pth):
|
||||
os.makedirs(pth)
|
||||
return pth
|
||||
|
||||
def add_layer(self, pth1, pth2):
|
||||
player = PairLayer(pth1, pth2)
|
||||
if player.check():
|
||||
self.layers[player.id] = player
|
||||
self.layer_show_update.emit()
|
||||
self.layer_tree_update.emit()
|
||||
self.pair_canvas.zoom_to_layer(player.main_l1.layer)
|
||||
else:
|
||||
self.message_box.error(f'{player.name} and {player.name} are not same size')
|
||||
|
||||
def to_dict(obj:'BasicLayer'):
|
||||
init_args = inspect.getfullargspec(obj.__class__.__init__)[0][1:]
|
||||
data = {}
|
||||
for args in init_args:
|
||||
if hasattr(obj, args):
|
||||
data[args] = getattr(obj, args)
|
||||
data['type']=obj.__class__.__name__
|
||||
return data
|
||||
|
||||
def from_dict(data:dict):
|
||||
cls_type = data.pop('type')
|
||||
if cls_type is not None and cls_type in globals():
|
||||
return globals()[cls_type](**data)
|
||||
|
||||
class BasicLayer(QObject):
|
||||
|
||||
LEFT_VIEW=1
|
||||
RIGHT_VIEW=2
|
||||
BOATH_VIEW=3
|
||||
|
||||
IN_MEMORY=1
|
||||
IN_FILE=2
|
||||
|
||||
layer_tree_update = pyqtSignal()
|
||||
layer_show_update = pyqtSignal()
|
||||
zoom_to_layer = pyqtSignal(dict)
|
||||
|
||||
def __init__(self,
|
||||
name='未命名',
|
||||
enable = False,
|
||||
icon = None,
|
||||
path = None,
|
||||
path_mode = IN_MEMORY,
|
||||
view_mode = BOATH_VIEW,):
|
||||
super().__init__(Project())
|
||||
self.enable = enable
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
self._path = path
|
||||
self._expand = True
|
||||
self.path_mode = path_mode
|
||||
self.view_mode = view_mode
|
||||
self.layer = None
|
||||
self.layer_tree_update.connect(Project().layer_tree_update)
|
||||
self.layer_show_update.connect(Project().layer_show_update)
|
||||
self.zoom_to_layer.connect(Project().zoom_to_layer)
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
if self.path_mode == BasicLayer.IN_FILE and Project().file_mode == Project.RELATIVE_MODE:
|
||||
return os.path.relpath(self._path, Project().root)
|
||||
return self._path
|
||||
|
||||
def get_item(self, root):
|
||||
|
||||
item = QTreeWidgetItem(root)
|
||||
if self.icon is not None:
|
||||
item.setIcon(0, QIcon(self.icon))
|
||||
item.setText(0, self.name)
|
||||
item.setCheckState(0, Qt.Checked if self.enable else Qt.Unchecked)
|
||||
item.item_update = self.item_update
|
||||
item.get_actions = self.get_actions
|
||||
item.setExpanded(self._expand)
|
||||
|
||||
return item
|
||||
|
||||
def item_update(self, item:QTreeWidgetItem):
|
||||
# item = self._item
|
||||
# print('start update')
|
||||
self.name = item.text(0)
|
||||
self._expand = item.isExpanded()
|
||||
pre = self.enable
|
||||
cur = item.checkState(0) == Qt.Checked
|
||||
if pre != cur:
|
||||
self.enable = cur
|
||||
self.layer_show_update.emit()
|
||||
# print('end update')
|
||||
|
||||
def set_layer_parent(self, layer):
|
||||
self.layer_parent = layer
|
||||
|
||||
def get_actions(self):
|
||||
actions = []
|
||||
zoom_to_action = QAction(IconInstance().GRID_ON, '缩放至所在图层', self)
|
||||
actions.append(zoom_to_action)
|
||||
def zoom_to():
|
||||
self.zoom_to_layer.emit(dict(layer=self.layer))
|
||||
zoom_to_action.triggered.connect(zoom_to)
|
||||
|
||||
del_action = QAction(IconInstance().DELETE, '删除图层', self)
|
||||
|
||||
def del_layer():
|
||||
Project().remove_layer(self)
|
||||
del_action.triggered.connect(del_layer)
|
||||
actions.append(del_action)
|
||||
|
||||
return actions
|
||||
|
||||
class GridLayer(BasicLayer):
|
||||
|
||||
def set_render(self):
|
||||
symbol_layer = QgsSimpleLineSymbolLayer()
|
||||
symbol_layer.setWidth(1 * self.x_res)
|
||||
symbol_layer.setWidth(1)
|
||||
symbol_layer.setColor(QColor.fromRgb(255,255,255, 200))
|
||||
|
||||
symbol = QgsLineSymbol()
|
||||
symbol.changeSymbolLayer(0, symbol_layer)
|
||||
symbol.setWidthUnit(QgsUnitTypes.RenderMapUnits)
|
||||
# symbol.setWidthUnit(QgsUnitTypes.RenderMapUnits)
|
||||
render = QgsSingleSymbolRenderer(symbol)
|
||||
self.lines_layer.setRenderer(render)
|
||||
self.layer.setRenderer(render)
|
||||
|
||||
|
||||
def __init__(self, cell_size, ds):
|
||||
self.cell_size = cell_size
|
||||
self.ds = ds
|
||||
def __init__(self, proj, geo, x_size, y_size, enable=True, name='格网', cell_size=(100,100), style_opts={}):
|
||||
|
||||
proj = ds.GetProjection()
|
||||
geo = ds.GetGeoTransform()
|
||||
super().__init__(name, enable, icon='')
|
||||
|
||||
self.cell_size = cell_size
|
||||
self.proj = proj
|
||||
self.geo = geo
|
||||
self.x_size = ds.RasterXSize
|
||||
self.y_size = ds.RasterYSize
|
||||
self.x_size = x_size
|
||||
self.y_size = y_size
|
||||
|
||||
self.x_min = geo[0]
|
||||
self.y_min = geo[3]
|
||||
@ -183,19 +326,19 @@ class GridLayer:
|
||||
self.x_max = self.x_min + self.x_res * self.x_size
|
||||
self.y_max = self.y_min + self.y_res * self.y_size
|
||||
self.x_lines = []
|
||||
for xi in range(self.x_size // self.cell_size[0]):
|
||||
for xi in range(self.x_size // self.cell_size[0] +1):
|
||||
self.x_lines.append(self.x_min + self.x_res * xi * self.cell_size[0])
|
||||
if self.x_lines[-1] == self.x_max:
|
||||
self.x_lines.pop()
|
||||
self.x_lines.append(self.x_max)
|
||||
self.y_lines = []
|
||||
for yi in range(self.y_size // self.cell_size[1]):
|
||||
for yi in range(self.y_size // self.cell_size[1]+1):
|
||||
self.y_lines.append(self.y_min + self.y_res * yi * self.cell_size[1])
|
||||
if self.y_lines[-1] == self.y_max:
|
||||
self.y_lines.pop()
|
||||
self.y_lines.append(self.y_max)
|
||||
crs = QgsCoordinateReferenceSystem()
|
||||
crs.createFromString('WKT:{}'.format(ds.GetProjection()))
|
||||
crs.createFromString('WKT:{}'.format(proj))
|
||||
# print(crs)
|
||||
lines_layer = QgsVectorLayer('LineString?crs={}'.format(crs.toProj()), 'temp-grid-outline', "memory")
|
||||
if not lines_layer.isValid():
|
||||
@ -214,74 +357,101 @@ class GridLayer:
|
||||
features.append(line)
|
||||
lines_layer.addFeatures(features)
|
||||
lines_layer.commitChanges()
|
||||
self.lines_layer = lines_layer
|
||||
self.layer = lines_layer
|
||||
|
||||
self.set_render()
|
||||
# self.x_lines = [ self.x_min + i * self.x_res for i in range(self.x_size) ]
|
||||
|
||||
|
||||
|
||||
class RasterLayer(BasicLayer):
|
||||
|
||||
def __init__(self, name=None, enable=False, path=None, view_mode=BasicLayer.BOATH_VIEW):
|
||||
if name is None:
|
||||
name = os.path.splitext(os.path.basename(path))[0]
|
||||
super().__init__(name, enable, ':/icons/raster.png', path, BasicLayer.IN_FILE, view_mode)
|
||||
self.layer = QgsRasterLayer(self.path, self.name)
|
||||
|
||||
def compare(self, other:'RasterLayer'):
|
||||
ds1 = gdal.Open(self.path)
|
||||
ds2 = gdal.Open(other.path)
|
||||
if ds1 is None or ds2 is None:
|
||||
Project().message_box.error('图层打开失败')
|
||||
return False
|
||||
|
||||
if ds1.RasterXSize != ds2.RasterXSize or ds1.RasterYSize != ds2.RasterYSize:
|
||||
Project().message_box.error('图层尺寸不一致')
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def geo(self):
|
||||
ds = gdal.Open(self.path)
|
||||
if ds is None:
|
||||
return None
|
||||
geo = ds.GetGeoTransform()
|
||||
del ds
|
||||
return geo
|
||||
|
||||
@property
|
||||
def grid_layer(self):
|
||||
return self.lines_layer
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'cell_size': self.cell_size
|
||||
}
|
||||
def proj(self):
|
||||
ds = gdal.Open(self.path)
|
||||
if ds is None:
|
||||
return None
|
||||
proj = ds.GetProjection()
|
||||
del ds
|
||||
return proj
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data):
|
||||
return GridLayer()
|
||||
@property
|
||||
def size(self):
|
||||
ds = gdal.Open(self.path)
|
||||
if ds is None:
|
||||
return None
|
||||
s = (ds.RasterXSize, ds.RasterYSize)
|
||||
del ds
|
||||
return s
|
||||
|
||||
class ResultLayer:
|
||||
class VectorLayer(BasicLayer):
|
||||
pass
|
||||
|
||||
POINT = 0
|
||||
RASTER = 1
|
||||
|
||||
def __init__(self, name, parent, layer_type = POINT):
|
||||
self.layer_type = layer_type
|
||||
class ResultPointLayer(BasicLayer):
|
||||
|
||||
def __init__(self, path, name=None, enable = False, proj = None, geo = None):
|
||||
if name is None:
|
||||
name = os.path.splitext(os.path.basename(path))[0]
|
||||
super().__init__(name, enable, icon=':/icons/points.png', path=path, path_mode = BasicLayer.IN_FILE, view_mode=BasicLayer.BOATH_VIEW )
|
||||
self.data = None
|
||||
self.layer = None
|
||||
self.name = name
|
||||
self.path = None
|
||||
self.wkt = None
|
||||
self.enable = False
|
||||
self.parent = parent
|
||||
self.wkt = proj
|
||||
self.geo = geo
|
||||
|
||||
self.load_point_file()
|
||||
|
||||
def save(self):
|
||||
if self.layer_type == ResultLayer.POINT:
|
||||
with open(self.path, 'w') as f:
|
||||
f.write('x,y,diff,status\n')
|
||||
for i in range(len(self.data)):
|
||||
f.write('{},{},{},{}\n'.format(self.data[i][0], self.data[i][1], self.data[i][2], int(self.data[i][3])))
|
||||
|
||||
with open(self.path, 'w') as f:
|
||||
f.write('x,y,diff,status\n')
|
||||
for i in range(len(self.data)):
|
||||
f.write('{},{},{},{}\n'.format(self.data[i][0], self.data[i][1], self.data[i][2], int(self.data[i][3])))
|
||||
|
||||
|
||||
def update(self, data):
|
||||
if self.layer_type == ResultLayer.POINT:
|
||||
row = data['row']
|
||||
value = data['value']
|
||||
self.data[row][-1] = value
|
||||
self.update_point_layer(row)
|
||||
elif self.layer_type == ResultLayer.RASTER:
|
||||
pass
|
||||
|
||||
def load_file(self, path):
|
||||
self.path = path
|
||||
if self.layer_type == ResultLayer.POINT:
|
||||
self.load_point_file()
|
||||
elif self.layer_type == ResultLayer.RASTER:
|
||||
self.load_raster_file()
|
||||
else:
|
||||
raise Exception('Unknown layer type')
|
||||
row = data['row']
|
||||
value = data['value']
|
||||
self.data[row][-1] = int(value)
|
||||
self.update_point_layer(row)
|
||||
|
||||
def format_point_layer(self, layer):
|
||||
layer.setLabelsEnabled(True)
|
||||
lyr = QgsPalLayerSettings()
|
||||
lyr.enabled = True
|
||||
lyr.fieldName = 'fid'
|
||||
lyr.fieldName = 'prob'
|
||||
lyr.placement = QgsPalLayerSettings.OverPoint
|
||||
lyr.textNamedStyle = 'Medium'
|
||||
lyr.xOffset = 2
|
||||
lyr.yOffset = -2
|
||||
lyr.textFont = QFont('Times New Roman', 16)
|
||||
text_format = QgsTextFormat()
|
||||
text_format.color = QColor('#ffffff')
|
||||
text_format.color = QColor.fromRgb(255,0,0)
|
||||
text_format.background().color = QColor('#000000')
|
||||
text_format.buffer().setEnabled(True)
|
||||
text_format.buffer().setSize(1)
|
||||
@ -296,11 +466,12 @@ class ResultLayer:
|
||||
layer.setLabeling(rules)
|
||||
|
||||
def set_render(self, layer):
|
||||
symbol_change = QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': 5 * self.parent.xres })
|
||||
symbol_change.setSizeUnit(QgsUnitTypes.RenderUnit.RenderMetersInMapUnits)
|
||||
# xres = self.geo[1]
|
||||
symbol_change = QgsMarkerSymbol.createSimple({'color': '#ffff00', 'size': 2 })
|
||||
symbol_change.setSizeUnit(QgsUnitTypes.RenderUnit.RenderMillimeters)
|
||||
category_change = QgsRendererCategory(1, symbol_change,'change')
|
||||
|
||||
symbol_unchange = QgsMarkerSymbol.createSimple({'color': '#00000000', 'size': '0'})
|
||||
symbol_unchange = QgsMarkerSymbol.createSimple({'color': '#00000000', 'size': 0})
|
||||
|
||||
category_unchange = QgsRendererCategory(0, symbol_unchange, 'unchange')
|
||||
render = QgsCategorizedSymbolRenderer('status', [category_change, category_unchange])
|
||||
@ -320,7 +491,7 @@ class ResultLayer:
|
||||
else:
|
||||
crs = QgsCoordinateReferenceSystem()
|
||||
|
||||
uri = 'Point?crs={}&field=status:integer'.format(crs.toProj())
|
||||
uri = 'Point?crs={}&field=status:integer&field=prob:string'.format(crs.toProj())
|
||||
layer = QgsVectorLayer(uri, self.name, "memory")
|
||||
if not layer.isValid():
|
||||
Project().message_box.error('Failed to create layer')
|
||||
@ -334,6 +505,10 @@ class ResultLayer:
|
||||
point.setId(i)
|
||||
point.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(d[0], d[1])))
|
||||
point.setAttribute('status', int(d[-1]))
|
||||
if d[-1] == 0:
|
||||
point.setAttribute('prob', '')
|
||||
else:
|
||||
point.setAttribute('prob', '%.2f'%(d[2]))
|
||||
# point.setAttribute('id', i)
|
||||
features.append(point)
|
||||
layer.addFeatures(features)
|
||||
@ -351,152 +526,117 @@ class ResultLayer:
|
||||
feature = self.layer.getFeature(i+1)
|
||||
if feature is None:
|
||||
continue
|
||||
feature.setAttribute('status', d[-1])
|
||||
feature.setAttribute('status', int(d[-1]))
|
||||
if d[-1] == 0:
|
||||
feature.setAttribute('prob', '')
|
||||
else:
|
||||
feature.setAttribute('prob', '%.2f'%(d[2]))
|
||||
else:
|
||||
feature = self.layer.getFeature(row+1)
|
||||
# print(feature)
|
||||
if feature is None:
|
||||
return
|
||||
# print(feature.fields().names())
|
||||
# self.layer.deleteFeature(feature.id())
|
||||
# del feature
|
||||
feature.setAttribute('status', int(self.data[row][-1]))
|
||||
if self.data[row][-1] == 0:
|
||||
feature.setAttribute('prob', '')
|
||||
else:
|
||||
feature.setAttribute('prob', '%.2f'%(self.data[row][2]))
|
||||
self.layer.updateFeature(feature)
|
||||
self.layer.commitChanges()
|
||||
|
||||
|
||||
def load_raster_file(self):
|
||||
ds = gdal.Open(self.path)
|
||||
if ds is None:
|
||||
return
|
||||
self.layer = QgsRasterLayer(self.path, self.name)
|
||||
def get_actions(self):
|
||||
actions = super().get_actions()
|
||||
show_in_table = QAction(IconInstance().TABLE, '显示在表格中')
|
||||
actions.insert(0, show_in_table)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data, parent, root = None):
|
||||
result = ResultLayer(data['name'], parent, data['layer_type'])
|
||||
result.wkt = data['wkt']
|
||||
if root is not None:
|
||||
result.load_file(str(Path(root) / data['path']))
|
||||
else:
|
||||
result.load_file(data['path'])
|
||||
return result
|
||||
def show_to_table():
|
||||
Project().result_table.show_result(self)
|
||||
|
||||
show_in_table.triggered.connect(show_to_table)
|
||||
|
||||
def to_dict(self, root=None):
|
||||
return {
|
||||
'name': self.name,
|
||||
'layer_type': self.layer_type,
|
||||
'wkt': self.wkt,
|
||||
'path': self.path if root is None else str(Path(self.path).relative_to(root))
|
||||
}
|
||||
return actions
|
||||
# def load_file(self, path):
|
||||
|
||||
|
||||
class PairLayer:
|
||||
class PairLayer(BasicLayer):
|
||||
|
||||
def to_dict(self, root = None):
|
||||
if root is None:
|
||||
return {
|
||||
'pth1': self.pth1,
|
||||
'pth2': self.pth2,
|
||||
'l1_name': self.l1_name,
|
||||
'l2_name': self.l2_name,
|
||||
'cell_size': self.cell_size,
|
||||
'results': [r.to_dict(root) for r in self.results],
|
||||
'name': self.name
|
||||
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'pth1': relative_path(self.pth1, root),
|
||||
'pth2': relative_path(self.pth2, root),
|
||||
'name': self.name,
|
||||
'l1_name': self.l1_name,
|
||||
'l2_name': self.l2_name,
|
||||
'cell_size': self.cell_size,
|
||||
'results': [r.to_dict(root) for r in self.results]
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data, root = None):
|
||||
if root is None:
|
||||
layer = PairLayer(data['pth1'], data['pth2'], data['cell_size'])
|
||||
else:
|
||||
layer = PairLayer(os.path.join(root, data['pth1']), os.path.join(root, data['pth2']), data['cell_size'])
|
||||
layer.l1_name = data['l1_name']
|
||||
layer.l2_name = data['l2_name']
|
||||
layer.name = data['name']
|
||||
|
||||
for r in data['results']:
|
||||
layer.results.append(ResultLayer.from_dict(r, layer, root))
|
||||
# layer.grid_layer = GridLayer.from_dict(data['grid_layer'])
|
||||
return layer
|
||||
|
||||
def save(self):
|
||||
for r in self.results:
|
||||
r.save()
|
||||
|
||||
def __init__(self, pth1, pth2, cell_size) -> None:
|
||||
self.pth1 = pth1
|
||||
self.pth2 = pth2
|
||||
self.enable = True
|
||||
self.l1_enable = True
|
||||
self.l2_enable = True
|
||||
self.grid_enable = True
|
||||
def __init__(self, pth1, pth2) -> None:
|
||||
|
||||
self.layers:List[BasicLayer] = []
|
||||
self.id = str(uuid.uuid1())
|
||||
self.name = '{}-{}'.format(os.path.basename(pth1), os.path.basename(pth2))
|
||||
self.l1_name = os.path.basename(pth1)
|
||||
self.l2_name = os.path.basename(pth2)
|
||||
|
||||
self.l1_pres = [] # 预处理数据
|
||||
self.l2_pres = []
|
||||
|
||||
self.cell_size = cell_size
|
||||
self.msg = ''
|
||||
self.checked = False
|
||||
self.main_l1 = RasterLayer(path = pth1, enable=True, view_mode=BasicLayer.LEFT_VIEW)
|
||||
self.main_l2 = RasterLayer(path = pth2, enable=True, view_mode=BasicLayer.RIGHT_VIEW)
|
||||
self.main_l1.set_layer_parent(self)
|
||||
self.main_l2.set_layer_parent(self)
|
||||
self.grid = None
|
||||
self.cell_size = Project().cell_size
|
||||
name = os.path.basename(pth1)[:4] + '-' + os.path.basename(pth2)[:4]
|
||||
# self.layer_update.connect(Project().layer_updated)
|
||||
|
||||
self.xsize = 0
|
||||
self.ysize = 0
|
||||
self.xres = 0
|
||||
self.yres = 0
|
||||
|
||||
self.wkt = None
|
||||
|
||||
self.results:List[ResultLayer] = []
|
||||
|
||||
super().__init__(name, True, ':/icons/document.png')
|
||||
self.layer = self.main_l1.layer
|
||||
if self.check():
|
||||
self.geo = self.main_l1.geo
|
||||
self.proj = self.main_l1.proj
|
||||
self.size = self.main_l1.size
|
||||
self.layers.append(self.main_l1)
|
||||
self.layers.append(self.main_l2)
|
||||
self.grid = GridLayer(self.proj, self.geo, self.size[0], self.size[1], cell_size=Project().cell_size)
|
||||
self.grid.set_layer_parent(self)
|
||||
# self.layers.append(self.grid)
|
||||
|
||||
def check(self):
|
||||
if self.checked:
|
||||
return self.checked
|
||||
if not os.path.exists(self.pth1):
|
||||
self.msg = '图层1不存在'
|
||||
return False
|
||||
if not os.path.exists(self.pth2):
|
||||
self.msg = '图层2不存在'
|
||||
return False
|
||||
self.checked = self.main_l1.compare(self.main_l2)
|
||||
return True
|
||||
|
||||
def add_result_layer(self, result):
|
||||
result.set_layer_parent(self)
|
||||
self.layers.insert(0, result)
|
||||
self.layer_show_update.emit()
|
||||
self.layer_tree_update.emit()
|
||||
|
||||
def has_layer(self, layer):
|
||||
for ilayer in self.layers:
|
||||
if ilayer is layer:
|
||||
return True
|
||||
return False
|
||||
|
||||
def remove_layer(self, layer):
|
||||
idx = -1
|
||||
for ilayer in self.layers:
|
||||
idx += 1
|
||||
if ilayer is layer:
|
||||
break
|
||||
if idx >= len(self.layers):
|
||||
return
|
||||
|
||||
ds1 = gdal.Open(self.pth1)
|
||||
ds2 = gdal.Open(self.pth2)
|
||||
if ds1 is None or ds2 is None:
|
||||
self.msg = '图层打开失败'
|
||||
return False
|
||||
if layer is self.grid or layer is self.main_l1 or layer is self.main_l2:
|
||||
return
|
||||
|
||||
if ds1.RasterXSize != ds2.RasterXSize or ds1.RasterYSize != ds2.RasterYSize:
|
||||
self.msg = '图层尺寸不一致'
|
||||
return False
|
||||
self.layers.pop(idx)
|
||||
del layer
|
||||
|
||||
self.xsize = ds1.RasterXSize
|
||||
self.ysize = ds1.RasterYSize
|
||||
def to_dict(self):
|
||||
data=dict(
|
||||
name=self.name,
|
||||
enable=self.enable,
|
||||
pth1=self.main_l1.path,
|
||||
pth2=self.main_l2.path,
|
||||
layers=[to_dict(l) for l in self.layers if not (l is self.grid or l is self.main_l1 or l is self.main_l2) ]
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
self.xres = ds1.GetGeoTransform()[1]
|
||||
self.yres = ds1.GetGeoTransform()[5]
|
||||
|
||||
self.wkt = ds1.GetProjection()
|
||||
|
||||
self.grid_layer = GridLayer(self.cell_size, ds1)
|
||||
|
||||
del ds1
|
||||
del ds2
|
||||
|
||||
self.l1 = QgsRasterLayer(self.pth1, self.l1_name)
|
||||
self.l2 = QgsRasterLayer(self.pth2, self.l2_name)
|
||||
self.checked = True
|
||||
return True
|
||||
@staticmethod
|
||||
def from_dict(data):
|
||||
player = PairLayer(data['pth1'], data['pth2'])
|
||||
player.name = data['name']
|
||||
for layer in data['layers']:
|
||||
l = from_dict(layer)
|
||||
l.set_layer_parent(player)
|
||||
player.layers.insert(0,l)
|
||||
return player
|
@ -151,7 +151,7 @@ class Settings(QSettings):
|
||||
with Settings(Settings.General.PRE) as s:
|
||||
return s.value('auto_save', True)
|
||||
|
||||
@property.setter
|
||||
@auto_save.setter
|
||||
def auto_save(self, value):
|
||||
if isinstance(value, bool):
|
||||
pass
|
||||
@ -168,7 +168,7 @@ class Settings(QSettings):
|
||||
with Settings(Settings.General.PRE) as s:
|
||||
return s.value('auto_save_intervel', 30)
|
||||
|
||||
@property.setter
|
||||
@auto_save_intervel.setter
|
||||
def auto_save_intervel(self, value):
|
||||
if isinstance(value, int) and value > 0:
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user