change to plugin

This commit is contained in:
copper 2022-05-05 15:59:04 +08:00
parent d5c57a2402
commit 00ffe0c03f
51 changed files with 1113 additions and 505 deletions

View File

@ -9,4 +9,17 @@ Python3 + PyQt + QGIS?
pyqt qgis gdal numpy
# 打包方式
comming soon
comming soon
# 功能
1. 证书检查与生成
1. 基于MAC地址与过期时间进行证书生成启动时检查证书过期则退出
2. 项目管理
1. 以项目为单位进行数据管理与生产
2. 提供项目保存与导入功能
3. 提供多种格式的栅格数据导入TIF、PNG、BMP、JPG
4. 提供矢量数据导入
3. 基本工具
1. 双视图同步浏览
2. 格网展示

View File

@ -1,341 +0,0 @@
import logging
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog
from gui.about import AboutDialog
from gui.project import Create
from utils.project import Project
class ActionManager(QtCore.QObject):
def __init__(self,
double_map,
layer_tree,
follow_box,
result_box,
message_box,
parent=None):
super().__init__(parent)
self.w_parent = parent
self.actions = {}
self.action_groups = {}
self.action_group_actions = {}
self.double_map = double_map
self.layer_tree = layer_tree
self.follow_box = follow_box
self.result_box = result_box
self.message_box = message_box
self.allways_enable = []
self.init_enable = []
self.dataload_enable = []
self.toolbar = None
self.menubar = None
self.status_bar = None
def set_menus(self, menubar):
self.menubar = menubar
self.file_menu = menubar.addMenu('&文件')
# self.view_menu = menubar.addMenu('&视图')
self.basic_menu = menubar.addMenu('&基本工具')
self.preop_menu = menubar.addMenu('&预处理')
self.change_detection_menu = menubar.addMenu('&变化检测')
self.special_chagne_detec_menu = menubar.addMenu('&专题变化检测')
self.postop_menu = menubar.addMenu('&后处理')
self.eval_menu = menubar.addMenu('&评估')
self.help_menu = menubar.addMenu('&帮助')
def set_toolbar(self, toolbar):
self.toolbar = toolbar
self.toolbar.setIconSize(QtCore.QSize(24, 24))
def set_status_bar(self, status_bar):
self.status_bar = status_bar
def set_actions(self):
'''
File menu
'''
project_create = self.add_action(QAction('&工程创建', self.w_parent), 'File')
project_open = self.add_action(QAction('&打开工程', self.w_parent), 'File')
project_save = self.add_action(QAction('&保存工程', self.w_parent), 'File')
data_load = self.add_action(QAction('&数据加载', self.w_parent), 'File')
view_setting = self.add_action(QAction('&界面定制', self.w_parent), 'File')
exit_app = self.add_action(QAction('&退出', self.w_parent), 'File')
project_create.triggered.connect(self.project_create)
project_open.triggered.connect(self.project_open)
project_save.triggered.connect(self.project_save)
data_load.triggered.connect(self.data_load)
view_setting.triggered.connect(self.view_setting)
exit_app.triggered.connect(self.w_parent.close)
self.allways_enable.append(project_create, project_open, exit_app, view_setting)
self.init_enable.append(project_save, data_load)
self.file_menu.addAction(project_create)
self.file_menu.addAction(project_open)
self.file_menu.addAction(project_save)
self.file_menu.addAction(data_load)
self.file_menu.addAction(view_setting)
self.file_menu.addAction(exit_app)
if self.toolbar is not None:
self.toolbar.addAction(project_create)
self.toolbar.addAction(project_open)
self.toolbar.addAction(project_save)
'''
Basic menu
'''
grid_line = self.add_action(QAction('&网格线', self.w_parent), 'Basic')
grid_line.setCheckable(True)
grid_line.setChecked(True)
zomm_in = self.add_action(QAction('&放大', self.w_parent), 'Basic')
zomm_out = self.add_action(QAction('&缩小', self.w_parent), 'Basic')
pan = self.add_action(QAction('&漫游', self.w_parent), 'Basic')
locate = self.add_action(QAction('&定位', self.w_parent), 'Basic')
self.basic_menu.addAction(grid_line)
self.basic_menu.addAction(zomm_in)
self.basic_menu.addAction(zomm_out)
self.basic_menu.addAction(pan)
self.basic_menu.addAction(locate)
'''
Preop menu
'''
morphology_filter = self.add_action(QAction('&形态学滤波', self.w_parent), 'filter')
lee_filter = self.add_action(QAction('&Lee滤波', self.w_parent), 'filter')
auto_filter = self.add_action(QAction('&自适应滤波-自主', self.w_parent), 'filter')
auto_filter_no_params = self.add_action(QAction('自动滤波(无参自适应滤波)-自主', self.w_parent), 'filter')
double_filter = self.add_action(QAction('&双边滤波', self.w_parent), 'filter')
align_action = self.add_action(QAction('&配准', self.w_parent), 'align')
filter_action_group = self.get_action_group('filter')
filter_menu = self.preop_menu.addMenu('&滤波')
for action in filter_action_group.actions():
filter_menu.addAction(action)
# self.preop_menu.addActionGroup(filter_action_group)
self.preop_menu.addAction(align_action)
if self.toolbar is not None:
self.toolbar.addAction(morphology_filter)
self.toolbar.addAction(lee_filter)
self.toolbar.addAction(auto_filter)
self.toolbar.addAction(auto_filter_no_params)
self.toolbar.addAction(double_filter)
'''
Change detection menu
'''
diff_method = self.add_action(QAction('&差分法', self.w_parent), 'unsuper_change_detection')
log_diff = self.add_action(QAction('&对数差分法', self.w_parent), 'unsuper_change_detection')
lsts_ = self.add_action(QAction('&LSTS法', self.w_parent), 'unsuper_change_detection')
lhba = self.add_action(QAction('&LHBA法', self.w_parent), 'unsuper_change_detection')
aht = self.add_action(QAction('&AHT法', self.w_parent), 'unsuper_change_detection')
kpvd = self.add_action(QAction('&KPVD法', self.w_parent), 'unsuper_change_detection')
mohd = self.add_action(QAction('&MOHD法', self.w_parent), 'unsuper_change_detection')
sh = self.add_action(QAction('&SH法', self.w_parent), 'unsuper_change_detection')
cva = self.add_action(QAction('&CVA法', self.w_parent), 'unsuper_change_detection')
mls = self.add_action(QAction('&MLS法', self.w_parent), 'unsuper_change_detection')
pca_kmean = self.add_action(QAction('&PCA-KMean法', self.w_parent), 'unsuper_change_detection')
semi_fcm = self.add_action(QAction('&Semi-FCM法', self.w_parent), 'unsuper_change_detection')
mls_svm = self.add_action(QAction('&MLS-SVM法', self.w_parent), 'unsuper_change_detection')
cva_fcm = self.add_action(QAction('&CVA-FCM法', self.w_parent), 'unsuper_change_detection')
cva_emgmm = self.add_action(QAction('&CVA-EMGMM法', self.w_parent), 'unsuper_change_detection')
gwdm = self.add_action(QAction('&GWDM法', self.w_parent), 'unsuper_change_detection')
mrf = self.add_action(QAction('&MRF法', self.w_parent), 'super_change_detection')
mad = self.add_action(QAction('&MAD法', self.w_parent), 'super_change_detection')
irmad = self.add_action(QAction('&IRMAD法', self.w_parent), 'super_change_detection')
dcva = self.add_action(QAction('&DCVA法', self.w_parent), 'ai_change_detection')
dp_fcn = self.add_action(QAction('&DP-FCN法', self.w_parent), 'ai_change_detection')
rcnn = self.add_action(QAction('&RCNN法', self.w_parent), 'ai_change_detection')
if self.toolbar is not None:
self.toolbar.addAction(diff_method)
self.toolbar.addAction(log_diff)
self.toolbar.addAction(lsts_)
self.toolbar.addAction(lhba)
unsuper_change_detection = self.get_action_group('unsuper_change_detection')
super_change_detection = self.get_action_group('super_change_detection')
ai_change_detection = self.get_action_group('ai_change_detection')
unsuper_menu = self.change_detection_menu.addMenu('&非监督')
for action in unsuper_change_detection.actions():
unsuper_menu.addAction(action)
super_menu = self.change_detection_menu.addMenu('&监督')
for action in super_change_detection.actions():
super_menu.addAction(action)
ai_menu = self.change_detection_menu.addMenu('&AI')
for action in ai_change_detection.actions():
ai_menu.addAction(action)
# self.change_detection_menu.addActionGroup(super_change_detection)
# self.change_detection_menu.addActionGroup(ai_change_detection)
'''
Special change detection menu
'''
water_change = self.add_action(QAction('&水体变化', self.w_parent), 'special_change_detection')
vegetation_change = self.add_action(QAction('&植被变化', self.w_parent), 'special_change_detection')
build_change = self.add_action(QAction('&房屋变化', self.w_parent), 'special_change_detection')
self.special_chagne_detec_menu.addAction(water_change)
self.special_chagne_detec_menu.addAction(vegetation_change)
self.special_chagne_detec_menu.addAction(build_change)
'''
Postop menu
'''
slide_window = self.add_action(QAction('&滑动窗口法', self.w_parent), 'noise_reduction')
density = self.add_action(QAction('&密度法', self.w_parent), 'noise_reduction')
raster_export = self.add_action(QAction('&二值栅格数据导出', self.w_parent), 'export')
txt_pos_export = self.add_action(QAction('&兼容ArcMap的坐标Txt文件', self.w_parent), 'export')
render_export = self.add_action(QAction('&渲染图像导出', self.w_parent), 'export')
noise_reduction = self.get_action_group('noise_reduction')
export = self.get_action_group('export')
noise_reduction_menu = self.postop_menu.addMenu('&噪声抑制')
for action in noise_reduction.actions():
noise_reduction_menu.addAction(action)
export_menu = self.postop_menu.addMenu('&导出')
for action in export.actions():
export_menu.addAction(action)
# self.postop_menu.addActionGroup(noise_reduction)
# self.postop_menu.addActionGroup(export)
'''
Evaluation menu
'''
evaluation = self.add_action(QAction('&评估', self.w_parent), 'evaluation')
self.eval_menu.addAction(evaluation)
'''
Help menu
'''
about = self.add_action(QAction('&关于', self.w_parent), 'about')
about.triggered.connect(lambda : AboutDialog(self.w_parent).show())
self.help_menu.addAction(about)
self.message_box.info('Menu init finished')
self.message_box.info(self.actions.keys())
for group in self.action_groups.keys():
self.message_box.info('%s:' % (group))
for action in self.action_groups[group].actions():
action.setEnabled(False)
self.message_box.info('\t%s' % (action.text()))
'''
Enabled actions
'''
about.setEnabled(True)
project_create.setEnabled(True)
project_open.setEnabled(True)
Project().project_init.connect(self.project_init)
if self.status_bar is not None:
corr_widget = QLabel(self.status_bar)
# corr_widget.setLineWidth(200)
corr_widget.setFixedWidth(200)
self.status_bar.addWidget(corr_widget)
scale_widget = QLabel(self.status_bar)
scale_widget.setFixedWidth(200)
self.status_bar.addWidget(scale_widget)
self.double_map.corr_changed.connect(corr_widget.setText)
self.double_map.scale_changed.connect(scale_widget.setText)
def project_create(self):
project = Project()
if project.is_init:
project.save()
projec_create = Create(self.w_parent)
if(projec_create.exec_()):
project.setup(os.path.join(projec_create.file, projec_create.name + '.prj'))
project.is_init = True
project.cell_size = projec_create.cell_size
def project_init(self, state):
self.message_box.info('Project init')
for group in self.action_groups.keys():
# self.message_box.info('%s:' % (group))
for action in self.action_groups[group].actions():
action.setEnabled(state)
# self.message_box.info('\t%s' % (action.text()))
self.message_box.info('Project init finished')
def project_open(self):
if Project().is_init:
Project().save()
project_file = QFileDialog.getOpenFileName(self.w_parent, '打开工程', '.', '*.prj')
if project_file[0] != '':
Project().clear()
Project().setup(project_file[0])
def project_save(self):
if Project().is_init:
Project().save()
def data_load(self):
if Project().is_init:
Project().save()
def view_setting(self):
pass
def add_action(self, action, group=None):
if group is None:
self.actions[action.text()] = action
else:
if group not in self.action_groups:
self.action_groups[group] = QActionGroup(self.w_parent)
self.action_groups[group].setExclusive(True)
self.action_groups[group].addAction(action)
self.action_group_actions[group] = action
return action
def get_action(self, action_name, group_name=None):
if action_name in self.actions:
return self.actions[action_name]
else:
if group_name is None:
return None
else:
if group_name not in self.action_group_actions:
return None
else:
group = self.action_group_actions[group_name]
for action in group.actions():
if action.text() == action_name:
return action
return None
def get_action_group(self, group_name):
return self.action_groups[group_name]
def get_action_group_action(self, group_name):
return self.action_group_actions[group_name]
def get_action_group_actions(self, group_name):
return self.action_group_actions[group_name].actions()
def get_actions(self):
return self.actions

View File

@ -1,4 +1,4 @@
from mul.mulstart import MulStart
from rscder import MulStart
import logging
logging.basicConfig(level=logging.INFO, filename='log.txt', filemode='w', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

View File

@ -1,6 +1,8 @@
from PyQt5.QtWidgets import QDialog, QApplication, QLabel, QTextEdit, QVBoxLayout
from PyQt5.QtCore import Qt
from rscder.plugins.basic import BasicPlugin
from PyQt5.QtWidgets import QDialog, QAction, QApplication, QLabel, QTextEdit, QVBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
class AboutDialog(QDialog):
def __init__(self, parent=None):
@ -40,3 +42,17 @@ class AboutDialog(QDialog):
self.layout.addWidget(self.label4)
self.layout.addWidget(self.text)
self.setLayout(self.layout)
class AboutPlugin(BasicPlugin):
def set_action(self):
menu = self.ctx['help_menu']
action = QAction('&关于', self.ctx['menubar'])
action.triggered.connect(self.on_about)
menu.addAction(action)
def on_about(self):
dialog = AboutDialog(self.ctx['main_window'])
dialog.show()

View File

@ -0,0 +1,8 @@
from rscder.plugins.basic import BasicPlugin
class BasicMethod(BasicPlugin):
def set_action(self):
menubar = self.ctx['menubar']

1
rscder/__init__.py Normal file
View File

@ -0,0 +1 @@
from .mul.mulstart import MulStart

382
rscder/gui/actions.py Normal file
View File

@ -0,0 +1,382 @@
import logging
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog
from rscder.gui.project import Create
from rscder.utils.project import Project
from rscder.gui.plugins import PluginDialog
class ActionManager(QtCore.QObject):
def __init__(self,
double_map,
layer_tree,
follow_box,
result_box,
message_box,
parent=None):
super().__init__(parent)
self.w_parent = parent
self.actions = {}
self.action_groups = {}
self.action_group_actions = {}
self.double_map = double_map
self.layer_tree = layer_tree
self.follow_box = follow_box
self.result_box = result_box
self.message_box = message_box
self.allways_enable = []
self.init_enable = []
self.dataload_enable = []
self.toolbar = None
self.menubar = None
self.status_bar = None
def set_menus(self, menubar):
self.menubar = menubar
self.file_menu = menubar.addMenu('&文件')
self.basic_menu = menubar.addMenu('&基本工具')
self.change_detection_menu = menubar.addMenu('&通用变化检测')
self.special_chagne_detec_menu = menubar.addMenu('&专题变化检测')
self.seg_chagne_detec_menu = menubar.addMenu('&分类后变化检测')
self.postop_menu = menubar.addMenu('&检测后处理')
self.view_menu = menubar.addMenu('&视图')
self.plugin_menu = menubar.addMenu('&插件')
self.help_menu = menubar.addMenu('&帮助')
def set_toolbar(self, toolbar):
self.toolbar = toolbar
self.toolbar.setIconSize(QtCore.QSize(24, 24))
def set_status_bar(self, status_bar):
self.status_bar = status_bar
def set_actions(self):
'''
File menu
'''
project_create = self.add_action(QAction('&工程创建', self.w_parent), 'File')
project_open = self.add_action(QAction('&打开工程', self.w_parent), 'File')
project_save = self.add_action(QAction('&保存工程', self.w_parent), 'File')
data_load = self.add_action(QAction('&数据加载', self.w_parent), 'File')
view_setting = self.add_action(QAction('&界面定制', self.w_parent), 'File')
exit_app = self.add_action(QAction('&退出', self.w_parent), 'File')
project_create.triggered.connect(self.project_create)
project_open.triggered.connect(self.project_open)
project_save.triggered.connect(self.project_save)
data_load.triggered.connect(self.data_load)
view_setting.triggered.connect(self.view_setting)
exit_app.triggered.connect(self.w_parent.close)
self.allways_enable.extend([project_create, project_open, exit_app, view_setting])
self.init_enable.extend([project_save, data_load])
self.file_menu.addAction(project_create)
self.file_menu.addAction(project_open)
self.file_menu.addAction(project_save)
self.file_menu.addAction(data_load)
self.file_menu.addAction(view_setting)
self.file_menu.addAction(exit_app)
if self.toolbar is not None:
self.toolbar.addAction(project_create)
self.toolbar.addAction(project_open)
self.toolbar.addAction(project_save)
'''
Basic menu
'''
grid_line = self.add_action(QAction('&网格线', self.w_parent), 'Basic Line')
grid_line.setCheckable(True)
grid_line.setChecked(True)
zomm_in = self.add_action(QAction('&放大', self.w_parent), 'Basic')
zomm_out = self.add_action(QAction('&缩小', self.w_parent), 'Basic')
pan = self.add_action(QAction('&漫游', self.w_parent), 'Basic')
locate = self.add_action(QAction('&定位', self.w_parent), 'Basic')
pan.setCheckable(True)
pan.setChecked(True)
zomm_out.setCheckable(True)
zomm_out.setChecked(False)
zomm_in.setCheckable(True)
zomm_in.setChecked(False)
self.double_map.connect_map_tool(pan, zomm_in, zomm_out)
self.double_map.connect_grid_show(grid_line)
self.view_menu.addAction(grid_line)
self.view_menu.addSeparator()
self.view_menu.addAction(pan)
self.view_menu.addAction(zomm_in)
self.view_menu.addAction(zomm_out)
self.view_menu.addAction(locate)
'''
Plugin menu
'''
plugin_list = self.add_action(QAction('&插件列表', self.w_parent), 'Plugin')
plugin_list.triggered.connect(self.plugin_list)
self.plugin_menu.addAction(plugin_list)
# morphology_filter = self.add_action(QAction('&形态学滤波', self.w_parent), 'filter')
# lee_filter = self.add_action(QAction('&Lee滤波', self.w_parent), 'filter')
# auto_filter = self.add_action(QAction('&自适应滤波-自主', self.w_parent), 'filter')
# auto_filter_no_params = self.add_action(QAction('自动滤波(无参自适应滤波)-自主', self.w_parent), 'filter')
# double_filter = self.add_action(QAction('&双边滤波', self.w_parent), 'filter')
# filter_action_group = self.get_action_group('filter')
# filter_menu = self.basic_menu.addMenu('&滤波处理')
# for action in filter_action_group.actions():
# filter_menu.addAction(action)
# rgb2rgb = self.add_action(QAction('&光学-影像', self.w_parent), 'align')
# sar2sar = self.add_action(QAction('&SAR-影像', self.w_parent), 'align')
# multi_source = self.add_action(QAction('&多源影像', self.w_parent), 'align')
# align_menu = self.basic_menu.addMenu('&图像配准')
# align_menu.addAction(rgb2rgb)
# align_menu.addAction(sar2sar)
# align_menu.addAction(multi_source)
# cloud_menu = self.basic_menu.addMenu('&去云处理')
# defogging_menu = self.basic_menu.addMenu('&去雾处理')
# # self.preop_menu.addActionGroup(filter_action_group)
# # self.basic_menu.addAction(align_action)
# if self.toolbar is not None:
# self.toolbar.addAction(morphology_filter)
# self.toolbar.addAction(lee_filter)
# self.toolbar.addAction(auto_filter)
# self.toolbar.addAction(auto_filter_no_params)
# self.toolbar.addAction(double_filter)
# '''
# Change detection menu
# '''
# diff_method = self.add_action(QAction('&差分法', self.w_parent), 'unsuper_change_detection')
# log_diff = self.add_action(QAction('&对数差分法', self.w_parent), 'unsuper_change_detection')
# lsts_ = self.add_action(QAction('&LSTS法', self.w_parent), 'unsuper_change_detection')
# lhba = self.add_action(QAction('&LHBA法', self.w_parent), 'unsuper_change_detection')
# aht = self.add_action(QAction('&AHT法', self.w_parent), 'unsuper_change_detection')
# kpvd = self.add_action(QAction('&KPVD法', self.w_parent), 'unsuper_change_detection')
# mohd = self.add_action(QAction('&MOHD法', self.w_parent), 'unsuper_change_detection')
# sh = self.add_action(QAction('&SH法', self.w_parent), 'unsuper_change_detection')
# cva = self.add_action(QAction('&CVA法', self.w_parent), 'unsuper_change_detection')
# mls = self.add_action(QAction('&MLS法', self.w_parent), 'unsuper_change_detection')
# pca_kmean = self.add_action(QAction('&PCA-KMean法', self.w_parent), 'unsuper_change_detection')
# semi_fcm = self.add_action(QAction('&Semi-FCM法', self.w_parent), 'unsuper_change_detection')
# mls_svm = self.add_action(QAction('&MLS-SVM法', self.w_parent), 'unsuper_change_detection')
# cva_fcm = self.add_action(QAction('&CVA-FCM法', self.w_parent), 'unsuper_change_detection')
# cva_emgmm = self.add_action(QAction('&CVA-EMGMM法', self.w_parent), 'unsuper_change_detection')
# gwdm = self.add_action(QAction('&GWDM法', self.w_parent), 'unsuper_change_detection')
# mrf = self.add_action(QAction('&MRF法', self.w_parent), 'super_change_detection')
# mad = self.add_action(QAction('&MAD法', self.w_parent), 'super_change_detection')
# irmad = self.add_action(QAction('&IRMAD法', self.w_parent), 'super_change_detection')
# dcva = self.add_action(QAction('&DCVA法', self.w_parent), 'ai_change_detection')
# dp_fcn = self.add_action(QAction('&DP-FCN法', self.w_parent), 'ai_change_detection')
# rcnn = self.add_action(QAction('&RCNN法', self.w_parent), 'ai_change_detection')
# if self.toolbar is not None:
# self.toolbar.addAction(diff_method)
# self.toolbar.addAction(log_diff)
# self.toolbar.addAction(lsts_)
# self.toolbar.addAction(lhba)
# unsuper_change_detection = self.get_action_group('unsuper_change_detection')
# super_change_detection = self.get_action_group('super_change_detection')
# ai_change_detection = self.get_action_group('ai_change_detection')
# unsuper_menu = self.change_detection_menu.addMenu('&非监督')
# for action in unsuper_change_detection.actions():
# unsuper_menu.addAction(action)
# super_menu = self.change_detection_menu.addMenu('&监督')
# for action in super_change_detection.actions():
# super_menu.addAction(action)
# ai_menu = self.change_detection_menu.addMenu('&AI')
# for action in ai_change_detection.actions():
# ai_menu.addAction(action)
# # self.change_detection_menu.addActionGroup(super_change_detection)
# # self.change_detection_menu.addActionGroup(ai_change_detection)
# '''
# Special change detection menu
# '''
# water_change = self.add_action(QAction('&水体变化', self.w_parent), 'special_change_detection')
# vegetation_change = self.add_action(QAction('&植被变化', self.w_parent), 'special_change_detection')
# build_change = self.add_action(QAction('&房屋变化', self.w_parent), 'special_change_detection')
# self.special_chagne_detec_menu.addAction(water_change)
# self.special_chagne_detec_menu.addAction(vegetation_change)
# self.special_chagne_detec_menu.addAction(build_change)
# '''
# Postop menu
# '''
# slide_window = self.add_action(QAction('&滑动窗口法', self.w_parent), 'noise_reduction')
# density = self.add_action(QAction('&密度法', self.w_parent), 'noise_reduction')
# raster_export = self.add_action(QAction('&二值栅格数据导出', self.w_parent), 'export')
# txt_pos_export = self.add_action(QAction('&兼容ArcMap的坐标Txt文件', self.w_parent), 'export')
# render_export = self.add_action(QAction('&渲染图像导出', self.w_parent), 'export')
# noise_reduction = self.get_action_group('noise_reduction')
# export = self.get_action_group('export')
# noise_reduction_menu = self.postop_menu.addMenu('&噪声抑制')
# for action in noise_reduction.actions():
# noise_reduction_menu.addAction(action)
# export_menu = self.postop_menu.addMenu('&导出')
# for action in export.actions():
# export_menu.addAction(action)
# # self.postop_menu.addActionGroup(noise_reduction)
# # self.postop_menu.addActionGroup(export)
# '''
# Evaluation menu
# '''
# evaluation = self.add_action(QAction('&评估', self.w_parent), 'evaluation')
# self.postop_menu.addAction(evaluation)
'''
Help menu
'''
# about = self.add_action(QAction('&关于', self.w_parent), 'about')
# about.triggered.connect(lambda : AboutDialog(self.w_parent).show())
# self.help_menu.addAction(about)
self.message_box.info('Menu init finished')
self.message_box.info(self.actions.keys())
# for group in self.action_groups.keys():
# self.message_box.info('%s:' % (group))
# for action in self.action_groups[group].actions():
# action.setEnabled(False)
# self.message_box.info('\t%s' % (action.text()))
'''
Enabled actions
'''
# about.setEnabled(True)
project_create.setEnabled(True)
project_open.setEnabled(True)
Project().project_init.connect(self.project_init)
if self.status_bar is not None:
corr_widget = QLabel(self.status_bar)
# corr_widget.setLineWidth(200)
corr_widget.setFixedWidth(200)
self.status_bar.addWidget(corr_widget)
scale_widget = QLabel(self.status_bar)
scale_widget.setFixedWidth(200)
self.status_bar.addWidget(scale_widget)
self.double_map.corr_changed.connect(corr_widget.setText)
self.double_map.scale_changed.connect(scale_widget.setText)
def plugin_list(self):
dialog = PluginDialog(self.w_parent)
dialog.show()
def project_create(self):
project = Project()
projec_create = Create(self.w_parent)
if(projec_create.exec_()):
if project.is_init:
project.save()
project.clear()
project.setup(os.path.join(projec_create.file, projec_create.name + '.prj'))
project.is_init = True
project.cell_size = projec_create.cell_size
project.max_memory = projec_create.max_memory
project.save()
self.message_box.info('Project created')
def project_init(self, state):
self.message_box.info('Project init')
for group in self.action_groups.keys():
# self.message_box.info('%s:' % (group))
for action in self.action_groups[group].actions():
action.setEnabled(state)
# self.message_box.info('\t%s' % (action.text()))
self.message_box.info('Project init finished')
def project_open(self):
if Project().is_init:
Project().save()
project_file = QFileDialog.getOpenFileName(self.w_parent, '打开工程', '.', '*.prj')
if project_file[0] != '':
Project().clear()
Project().setup(project_file[0])
def project_save(self):
if Project().is_init:
Project().save()
def data_load(self):
if Project().is_init:
Project().save()
file_open = QFileDialog.getOpenFileNames(self.w_parent, '打开数据', Project().root, '*.*')
if file_open[0] != '':
if len(file_open[0]) != 2:
self.message_box.warning('请选择两个数据文件')
return
Project().add_layer(file_open[0][0], file_open[0][1])
self.message_box.info('Data loaded')
def view_setting(self):
pass
def add_action(self, action, group=None):
if group is None:
self.actions[action.text()] = action
else:
if group not in self.action_groups:
self.action_groups[group] = QActionGroup(self.w_parent)
self.action_groups[group].setExclusive(True)
self.action_groups[group].addAction(action)
self.action_group_actions[group] = action
return action
def get_action(self, action_name, group_name=None):
if action_name in self.actions:
return self.actions[action_name]
else:
if group_name is None:
return None
else:
if group_name not in self.action_group_actions:
return None
else:
group = self.action_group_actions[group_name]
for action in group.actions():
if action.text() == action_name:
return action
return None
def get_action_group(self, group_name):
return self.action_groups[group_name]
def get_action_group_action(self, group_name):
return self.action_group_actions[group_name]
def get_action_group_actions(self, group_name):
return self.action_group_actions[group_name].actions()
def get_actions(self):
return self.actions

View File

@ -4,7 +4,7 @@ from PyQt5.QtCore import Qt,QModelIndex
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
from utils.project import PairLayer
from rscder.utils.project import PairLayer, Project
class LayerTree(QtWidgets.QWidget):
@ -18,13 +18,13 @@ class LayerTree(QtWidgets.QWidget):
self.root=QTreeWidgetItem(self.tree)
self.tree.setHeaderHidden(True)
# self.tree.setHeaderLabels(['图层'])
self.root.setText(0,'Root')
self.root.setText(0,'图层')
child1=QTreeWidgetItem()
child1.setText(0,'child1')
child1.setCheckState(0,Qt.Checked)
# child1=QTreeWidgetItem()
# child1.setText(0,'child1')
# child1.setCheckState(0,Qt.Checked)
self.root.addChild(child1)
# self.root.addChild(child1)
self.tree.expandAll()
self.tree.addTopLevelItem(self.root)
@ -39,9 +39,25 @@ class LayerTree(QtWidgets.QWidget):
def onClicked(self,index):
print(index.row())
def add_layer(self, layer:PairLayer):
pass
def add_layer(self, layer:str):
layer:PairLayer = Project().layers[layer]
item1 = QtWidgets.QTreeWidgetItem(self.root)
item1.setText(0, layer.l1_name)
item1.setCheckState(0, Qt.Checked)
item2 = QtWidgets.QTreeWidgetItem(self.root)
item2.setText(0, layer.l2_name)
item2.setCheckState(0, Qt.Checked)
item1.setData(0, Qt.UserRole, layer.id)
item2.setData(0, Qt.UserRole, layer.id)
self.tree.expandAll()
def clear(self):
self.tree.clear()
self.root = QTreeWidgetItem(self.tree)
self.root.setText(0,'图层')
self.tree.addTopLevelItem(self.root)
def right_menu_show(self, position):
rightMenu = QtWidgets.QMenu(self)
# QAction = QtWidgets.QAction(self.menuBar1)

View File

@ -4,7 +4,7 @@ from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
import os
from utils.license import LicenseHelper
from rscder.utils.license import LicenseHelper
class License(QtWidgets.QDialog):

View File

@ -4,13 +4,13 @@ from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon
from PyQt5 import QtGui
from PyQtAds import QtAds
from actions.actions import ActionManager
from gui.layertree import LayerTree
from gui.mapcanvas import DoubleCanvas
from gui.messagebox import MessageBox
from gui.result import ResultTable
from utils import Settings
from utils.project import Project
from rscder.gui.actions import ActionManager
from rscder.gui.layertree import LayerTree
from rscder.gui.mapcanvas import DoubleCanvas
from rscder.gui.messagebox import MessageBox
from rscder.gui.result import ResultTable
from rscder.utils import Settings
from rscder.utils.project import Project
class MainWindow(QMainWindow):
@ -41,7 +41,6 @@ class MainWindow(QMainWindow):
self.action_manager.set_menus(self.menuBar())
self.action_manager.set_toolbar(self.toolbar)
self.action_manager.set_status_bar(self.statusBar())
self.action_manager.set_actions()
self.resize(*Settings.General().size)

View File

@ -12,13 +12,15 @@ from PyQt5.QtWidgets import QMessageBox, QWidget, QHBoxLayout
from PyQt5.QtGui import QColor, QDragEnterEvent, QDropEvent
from qgis.core import QgsPointXY, QgsRasterLayer, QgsVectorLayer, QgsFeature, QgsGeometry, QgsCategorizedSymbolRenderer, QgsRendererCategory, QgsFillSymbol, QgsPalLayerSettings, QgsRuleBasedLabeling, QgsTextFormat
from qgis.gui import QgsMapCanvas
from qgis.core import QgsVectorLayerExporter, QgsVectorFileWriter, QgsProject, QgsField, QgsRasterFileWriter, QgsRasterPipe
from qgis.gui import QgsMapCanvas, QgsMapToolPan, QgsMapToolZoom
from qgis.core import QgsRectangle, QgsVectorFileWriter, QgsProject, QgsField, QgsRasterFileWriter, QgsRasterPipe
import threading
import tempfile
import cv2
import os
from rscder.utils.project import PairLayer, Project
class DoubleCanvas(QWidget):
corr_changed = pyqtSignal(str)
scale_changed = pyqtSignal(str)
@ -35,6 +37,16 @@ class DoubleCanvas(QWidget):
self.mapcanva1.update_coordinates_text.connect(self.corr_changed)
self.mapcanva2.update_coordinates_text.connect(self.corr_changed)
def set_map1_extent():
self.mapcanva1.set_extent(self.mapcanva2.extent())
def set_map2_extent():
self.mapcanva2.set_extent(self.mapcanva1.extent())
self.mapcanva1.extentsChanged.connect(set_map2_extent)
self.mapcanva2.extentsChanged.connect(set_map1_extent)
self.set_pan_tool(True)
self.mapcanva1.update_scale_text.connect(self.scale_changed)
self.mapcanva2.update_scale_text.connect(self.scale_changed)
@ -43,16 +55,117 @@ class DoubleCanvas(QWidget):
layout.addWidget(self.mapcanva2)
self.setLayout(layout)
self.grid_show = True
def connect_grid_show(self, action):
def show_grid(_):
self.grid_show = not self.grid_show
action.setChecked(self.grid_show)
if self.grid_show:
for layer in Project().layers.values():
self.mapcanva1.add_grid_layer(layer.grid_layer.grid_layer)
self.mapcanva2.add_grid_layer(layer.grid_layer.grid_layer)
else:
self.mapcanva1.remove_grid_layer()
self.mapcanva2.remove_grid_layer()
action.triggered.connect(show_grid)
def connect_map_tool(self, pan, zoom_in, zoom_out):
pan.triggered.connect(self.set_pan_tool)
zoom_in.triggered.connect(self.set_zoom_in)
zoom_out.triggered.connect( self.set_zoom_out)
def set_pan_tool(self, s):
print('set pan tool')
if s:
self.mapcanva1.setMapTool(QgsMapToolPan(self.mapcanva1))
self.mapcanva2.setMapTool(QgsMapToolPan(self.mapcanva2))
def set_zoom_in(self, s):
print('set zoom in')
if s:
self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, False))
self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, False))
def set_zoom_out(self, s):
print('set zoom out')
if s:
self.mapcanva1.setMapTool(QgsMapToolZoom(self.mapcanva1, True))
self.mapcanva2.setMapTool(QgsMapToolZoom(self.mapcanva2, True))
def add_layer(self, layer:str):
layer = Project().layers[layer]
if not self.mapcanva1.is_main and not self.mapcanva2.is_main:
self.mapcanva1.is_main = True
self.mapcanva1.add_layer(layer.l1)
self.mapcanva2.add_layer(layer.l2)
if self.grid_show:
self.mapcanva1.add_grid_layer(layer.grid_layer.grid_layer)
self.mapcanva2.add_grid_layer(layer.grid_layer.grid_layer)
def clear(self):
self.mapcanva1.clear()
self.mapcanva2.clear()
class CanvasWidget(QgsMapCanvas):
update_coordinates_text = pyqtSignal(str)
update_scale_text = pyqtSignal(str)
def add_layer(self, layer) -> None:
self.layers.insert(0, layer)
self.setLayers(self.layers)
self.zoomToFeatureExtent(layer.extent())
def add_grid_layer(self, layer):
self.grid_layers.append(layer)
self.layers.insert(0, layer)
self.setLayers(self.layers)
def remove_grid_layer(self):
layers = []
for layer in self.layers:
if layer in self.grid_layers:
continue
layers.append(layer)
self.layers = layers
self.setLayers(self.layers)
def enterEvent(self,e):
self.is_main = True
# print(e)
pass
def leaveEvent(self, e):
self.is_main = False
pass
def set_extent(self, extent:QgsRectangle):
'''
Zoom to extent
'''
# print(extent)
if self.is_main:
return
else:
self.zoomToFeatureExtent(extent)
def clear(self) -> None:
self.setTheme('')
self.layers = []
self.is_main = False
self.setLayers([])
self.clearCache()
self.refresh()
def __init__(self, parent):
super().__init__(parent)
self.current_raster_layer = None
self.current_vector_layer = None
self.layers = []
self.grid_layers = []
self.is_main = False
self.setCanvasColor(Qt.white)
self.enableAntiAliasing(True)
self.setAcceptDrops(False)

97
rscder/gui/plugins.py Normal file
View File

@ -0,0 +1,97 @@
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon, Qt
from rscder.utils.setting import Settings
class PluginDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Plugins')
self.setWindowIcon(QIcon(":/icons/logo.svg"))
self.setMinimumWidth(800)
self.setMinimumHeight(600)
self.plugins = Settings.Plugin().plugins
self.plugin_table = QTableWidget(len(self.plugins), 2, self)
self.plugin_table.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.plugin_table.setColumnWidth(0, 200)
self.plugin_table.setColumnWidth(1, 500)
self.plugin_table.setHorizontalHeaderLabels(['Name', 'Path', 'Enabled'])
self.plugin_table.setEditTriggers(QAbstractItemView.DoubleClicked)
self.plugin_table.cellDoubleClicked.connect(self.edit_plugin)
for idx, plugin in enumerate(self.plugins):
name_item = QTableWidgetItem(plugin['name'])
path_item = QTableWidgetItem(plugin['path'])
enabled_item = QTableWidgetItem()
enabled_item.setCheckState(Qt.Checked if plugin['enabled'] else Qt.Unchecked)
self.plugin_table.setItem(idx, 0, name_item)
self.plugin_table.setItem(idx, 1, path_item)
self.plugin_table.setItem(idx, 2, enabled_item)
self.add_button = QPushButton('Add', self)
self.add_button.clicked.connect(self.add_plugin)
self.remove_button = QPushButton('Remove', self)
self.remove_button.clicked.connect(self.remove_plugin)
self.save_button = QPushButton('Save', self)
self.save_button.clicked.connect(self.save_plugin)
self.cancel_button = QPushButton('Cancel', self)
self.cancel_button.clicked.connect(self.close)
layout = QVBoxLayout(self)
layout.addWidget(self.plugin_table)
hlayout = QHBoxLayout()
hlayout.addWidget(self.add_button)
hlayout.addWidget(self.remove_button)
hlayout.addWidget(self.save_button)
hlayout.addWidget(self.cancel_button)
layout.addLayout(hlayout)
self.setLayout(layout)
self.has_change = False
def add_plugin(self):
self.has_change = True
self.plugin_table.insertRow(self.plugin_table.rowCount())
def remove_plugin(self):
self.has_change = True
for row in self.plugin_table.selectedItems():
self.plugin_table.removeRow(row.row())
# for idx in self.plugins
def edit_plugin(self, row, column):
self.has_change = True
if column == 0:
self.plugin_table.item(row, column).setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
elif column == 1:
open_file = QFileDialog.getOpenFileName(self, 'Open File', '', 'Python Files (*.py)')
if open_file[0]:
self.plugin_table.item(row, column).setText(open_file[0])
else:
pass
elif column == 2:
self.plugin_table.item(row, column).setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
# self.plugin_list.setFixedWidth(200)
def save_plugin(self):
plugins = []
for idx in range(self.plugin_table.rowCount()):
name = self.plugin_table.item(idx, 0).text()
path = self.plugin_table.item(idx, 1).text()
enabled = self.plugin_table.item(idx, 2).checkState() == Qt.Checked
plugins.append({'name': name, 'path': path, 'enabled': enabled})
Settings.Plugin().plugins = plugins
self.close()
def closeEvent(self, event):
if self.has_change:
reply = QMessageBox.question(self, 'Message', "Do you want to save the changes?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
self.save_plugin()
event.accept()
else:
event.accept()
else:
event.accept()

View File

@ -1,7 +1,7 @@
from PyQt5.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QMessageBox
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QMessageBox
from PyQt5.QtGui import QIcon, QIntValidator
from PyQt5.QtCore import Qt
from utils.setting import Settings
from rscder.utils.setting import Settings
class Create(QDialog):
def __init__(self, parent=None) -> None:
@ -21,12 +21,21 @@ class Create(QDialog):
file_input.setToolTip('Project Dir')
file_input.setReadOnly(True)
file_input.setText(self.file)
self.file_input = file_input
file_open = QPushButton('...', self)
file_open.setFixedWidth(30)
file_open.clicked.connect(self.open_file)
name_label = QLabel('Project Name:')
name_label.setFixedWidth(100)
name_input = QLineEdit()
name_input.setPlaceholderText('Project Name')
name_input.setToolTip('Project Name')
name_input.setText(self.name)
self.name_input = name_input
name_input_layout = QHBoxLayout()
name_input_layout.addWidget(name_label)
@ -35,6 +44,7 @@ class Create(QDialog):
file_input_layout = QHBoxLayout()
file_input_layout.addWidget(file_label)
file_input_layout.addWidget(file_input)
file_input_layout.addWidget(file_open)
cell_size_label = QLabel('Cell Size:')
cell_size_label.setFixedWidth(100)
@ -43,9 +53,16 @@ class Create(QDialog):
cell_size_x_input = QLineEdit()
cell_size_y_input = QLineEdit()
cell_size_x_input.setPlaceholderText('Cell Size X')
cell_size_x_input.setValidator(QIntValidator())
cell_size_y_input.setPlaceholderText('Cell Size Y')
cell_size_y_input.setValidator(QIntValidator())
cell_size_x_input.setToolTip('Cell Size X')
cell_size_y_input.setToolTip('Cell Size Y')
cell_size_x_input.setText(str(self.cell_size[0]))
cell_size_y_input.setText(str(self.cell_size[1]))
self.cell_size_x_input = cell_size_x_input
self.cell_size_y_input = cell_size_y_input
cell_input_layout = QHBoxLayout()
cell_input_layout.addWidget(cell_size_label)
@ -54,8 +71,20 @@ class Create(QDialog):
cell_input_layout.addWidget(cell_size_y_label)
cell_input_layout.addWidget(cell_size_y_input)
max_memory_label = QLabel('Max Memory (MB):')
max_memory_label.setFixedWidth(100)
max_memory_input = QLineEdit()
max_memory_input.setPlaceholderText('Max Memory')
max_memory_input.setToolTip('Max Memory')
max_memory_input.setText(str(self.max_memory))
max_memory_input.setValidator(QIntValidator())
self.max_memory_input = max_memory_input
ok_button = QPushButton('OK')
cancel_button = QPushButton('Cancel')
ok_button.clicked.connect(self.ok)
cancel_button.clicked.connect(self.cancel)
button_layout = QHBoxLayout()
button_layout.setDirection(QHBoxLayout.RightToLeft)
@ -70,3 +99,29 @@ class Create(QDialog):
self.setLayout(main_layout)
def open_file(self):
file = QFileDialog.getExistingDirectory(self, 'Open Directory', self.file)
if file:
self.file = file
self.file_input.setText(self.file)
def ok(self):
self.name = self.name_input.text()
self.max_memory = self.max_memory_input.text()
self.cell_size = (self.cell_size_x_input.text(), self.cell_size_y_input.text())
if self.name == '':
QMessageBox.warning(self, 'Warning', 'Please input project name!')
return
if self.max_memory == '':
QMessageBox.warning(self, 'Warning', 'Please input max memory!')
return
if self.cell_size == ('', ''):
QMessageBox.warning(self, 'Warning', 'Please input cell size!')
return
self.max_memory = int(self.max_memory)
self.cell_size = (int(self.cell_size[0]), int(self.cell_size[1]))
self.accept()
def cancel(self):
self.reject()

View File

@ -4,7 +4,7 @@ from PyQt5.QtCore import Qt,QModelIndex
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
from utils.project import PairLayer
from rscder.utils.project import PairLayer
class ResultTable(QtWidgets.QWidget):
@ -34,6 +34,9 @@ class ResultTable(QtWidgets.QWidget):
layout.addWidget(self.tree)
self.setLayout(layout)
def clear(self):
pass
def onClicked(self,index):
print(index.row())

View File

Before

Width:  |  Height:  |  Size: 638 B

After

Width:  |  Height:  |  Size: 638 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 622 B

After

Width:  |  Height:  |  Size: 622 B

View File

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 606 B

View File

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 508 B

View File

Before

Width:  |  Height:  |  Size: 632 B

After

Width:  |  Height:  |  Size: 632 B

View File

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 689 B

View File

Before

Width:  |  Height:  |  Size: 642 B

After

Width:  |  Height:  |  Size: 642 B

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 699 B

After

Width:  |  Height:  |  Size: 699 B

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 593 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View File

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 514 B

View File

Before

Width:  |  Height:  |  Size: 654 B

After

Width:  |  Height:  |  Size: 654 B

View File

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 756 B

View File

Before

Width:  |  Height:  |  Size: 730 B

After

Width:  |  Height:  |  Size: 730 B

54
rscder/plugins/basic.py Normal file
View File

@ -0,0 +1,54 @@
from PyQt5.QtCore import QObject, pyqtSignal
from rscder.utils.project import PairLayer
class BasicPlugin(QObject):
'''
插件基类
ctx:
layer_tree: layer tree
pair_canvas: pair canvas
message_box: message box
result_table: result table
project: project instance
mainwindow: mainwindow
toolbar: toolbar
statusbar: statusbar
menu: menu
file_menu: file menu
'''
def __init__(self, ctx:dict) -> None:
super().__init__()
self.ctx = ctx
self.layer_tree = ctx['layer_tree']
self.pair_canvas = ctx['pair_canvas']
self.message_box = ctx['message_box']
self.result_table = ctx['result_table']
self.project = ctx['project']
self.mainwindow = ctx['mainwindow']
self.set_action()
self.project.layer_load.connect(self.on_data_load)
self.project.project_created.connect(self.setup)
def set_action(self):
'''
When App start
'''
pass
def setup(self):
'''
When project create
'''
pass
def get_layer(self, layer_id)-> PairLayer:
return self.project.layers[layer_id]
def on_data_load(self, layer_id):
'''
When data load
'''
pass

30
rscder/plugins/loader.py Normal file
View File

@ -0,0 +1,30 @@
from rscder.utils.setting import Settings
from PyQt5.QtCore import QObject, pyqtSignal
from rscder.plugins.basic import BasicPlugin
import importlib
import os
import sys
import inspect
class PluginLoader(QObject):
plugin_loaded = pyqtSignal()
def __init__(self, ctx):
self.ctx = ctx
def load_plugin(self):
plugins = Settings.Plugin().plugins
for plugin in plugins:
name = plugin['name']
path = plugin['path']
try:
module = importlib.import_module(path)
for oname, obj in inspect.getmembers(module):
if inspect.isclass(obj) and issubclass(obj, BasicPlugin) and obj != BasicPlugin and obj != PluginLoader and oname == name:
obj(self.ctx)
except Exception as e:
self.ctx['message_box'].error(f'{name} load error: {e}')
# print(e)
self.plugin_loaded.emit()

262
rscder/utils/project.py Normal file
View File

@ -0,0 +1,262 @@
import os
from pathlib import Path
from typing import Dict, List
import uuid
from osgeo import gdal, gdal_array
from utils.setting import Settings
from qgis.core import QgsRasterLayer, QgsLineSymbol, QgsSingleSymbolRenderer, QgsSimpleLineSymbolLayer, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsGeometry, QgsPointXY
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtGui import QColor
import yaml
def singleton(cls):
_instance = {}
def inner(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return inner
@singleton
class Project(QObject):
project_init = pyqtSignal(bool)
layer_load = pyqtSignal(str)
def __init__(self,
parent=None):
super().__init__(parent)
self.is_init = False
self.cell_size = Settings.Project().cell_size
self.max_memory = Settings.Project().max_memory
self.max_threads = Settings.Project().max_threads
self.root = Settings.General().root
self.layers:Dict = dict()
# self.layers:List[PairLayer] = []
def connect(self, pair_canvas,
layer_tree,
message_box,
result_table):
self.pair_canvas = pair_canvas
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)
# self.layer_load.connect(message_box.add_layer)
def setup(self, file=None):
self.is_init = True
self.file = file
if file is None:
self.file = Path(self.root)/'project'/'untitled.prj'
self.root = str(Path(self.file).parent)
dir_name = os.path.dirname(self.file)
if not os.path.exists(dir_name):
os.makedirs(dir_name, exist_ok=True)
if not os.path.exists(self.file):
with open(self.file, 'w') as f:
pass
else:
self.load()
# self.project_created.emit()
self.project_init.emit(True)
def save(self):
data_dict = {
'cell_size': self.cell_size,
'max_memory': self.max_memory,
'max_threads': self.max_threads,
'root': self.root,
'layers': [ layer.to_dict() for layer in self.layers.values() ],
'results': []
}
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.layer_tree.clear()
self.pair_canvas.clear()
self.message_box.clear()
self.result_table.clear()
def load(self):
with open(self.file, 'r') as f:
data = yaml.safe_load(f)
if data is None:
return
# data = yaml.safe_load(open(self.file, 'r'))
self.cell_size = data['cell_size']
self.max_memory = data['max_memory']
self.max_threads = data['max_threads']
self.root = data['root']
self.layers = dict()
for layer in data['layers']:
player = PairLayer.from_dict(layer)
if player.check():
self.layers[player.id] = player
self.layer_load.emit(player.id)
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 VectorLayer:
pass
class GridLayer:
def set_render(self):
symbol_layer = QgsSimpleLineSymbolLayer()
symbol_layer.setWidth(1)
symbol_layer.setColor(QColor.fromRgb(255,255,255, 100))
symbol = QgsLineSymbol()
symbol.changeSymbolLayer(0, symbol_layer)
render = QgsSingleSymbolRenderer(symbol)
self.lines_layer.setRenderer(render)
def __init__(self, cell_size, ds):
self.cell_size = cell_size
self.ds = ds
proj = ds.GetProjection()
geo = ds.GetGeoTransform()
self.proj = proj
self.geo = geo
self.x_size = ds.RasterXSize
self.y_size = ds.RasterYSize
self.x_min = geo[0]
self.y_min = geo[3]
self.x_res = geo[1]
self.y_res = geo[5]
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]):
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]):
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()))
# print(crs)
lines_layer = QgsVectorLayer('LineString?crs={}'.format(crs.toProj()), 'temp-grid-outline', "memory")
if not lines_layer.isValid():
Project().message_box.error('Failed to create grid outline layer')
return
lines_layer.setLabelsEnabled(False)
lines_layer.startEditing()
features = []
for x in self.x_lines:
line = QgsFeature()
line.setGeometry(QgsGeometry.fromPolylineXY([QgsPointXY(x, self.y_min), QgsPointXY(x, self.y_max)]))
features.append(line)
for y in self.y_lines:
line = QgsFeature()
line.setGeometry(QgsGeometry.fromPolylineXY([QgsPointXY(self.x_min, y), QgsPointXY(self.x_max, y)]))
features.append(line)
lines_layer.addFeatures(features)
lines_layer.commitChanges()
self.lines_layer = lines_layer
self.set_render()
# self.x_lines = [ self.x_min + i * self.x_res for i in range(self.x_size) ]
@property
def grid_layer(self):
return self.lines_layer
def to_dict(self):
return {
'cell_size': self.cell_size
}
@staticmethod
def from_dict(data):
return GridLayer()
class PairLayer:
def to_dict(self):
return {
'pth1': self.pth1,
'pth2': self.pth2,
'l1_name': self.l1_name,
'l2_name': self.l2_name,
'cell_size': self.cell_size,
}
@staticmethod
def from_dict(data):
layer = PairLayer(data['pth1'], data['pth2'], data['cell_size'])
layer.l1_name = data['l1_name']
layer.l2_name = data['l2_name']
# layer.grid_layer = GridLayer.from_dict(data['grid_layer'])
return layer
def __init__(self, pth1, pth2, cell_size) -> None:
self.pth1 = pth1
self.pth2 = pth2
self.id = str(uuid.uuid1())
self.l1_name = os.path.basename(pth1)
self.l2_name = os.path.basename(pth2)
self.cell_size = cell_size
# self.grid_layer = GridLayer(cell_size)
self.msg = ''
def check(self):
if not os.path.exists(self.pth1):
self.msg = '图层1不存在'
return False
if not os.path.exists(self.pth2):
self.msg = '图层2不存在'
return False
ds1 = gdal.Open(self.pth1)
ds2 = gdal.Open(self.pth2)
if ds1 is None or ds2 is None:
self.msg = '图层打开失败'
return False
if ds1.RasterXSize != ds2.RasterXSize or ds1.RasterYSize != ds2.RasterYSize:
self.msg = '图层尺寸不一致'
return False
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)
return True

View File

@ -2,7 +2,7 @@ from datetime import datetime
import os
from typing import Tuple
from PyQt5.QtCore import QSettings
from utils.license import LicenseHelper
from rscder.utils.license import LicenseHelper
class Settings(QSettings):
@ -16,6 +16,25 @@ class Settings(QSettings):
def __exit__(self, *args, **kargs):
self.endGroup()
class Plugin:
PRE='plugin'
@property
def root(self):
return './3rd'
@property
def plugins(self):
with Settings(Settings.Plugin.PRE) as s:
return s.value('plugins', [])
@plugins.setter
def plugins(self, value):
with Settings(Settings.Plugin.PRE) as s:
s.setValue('plugins', value)
class Project:
PRE= 'project'

View File

@ -1,11 +0,0 @@
from functools import wraps
def as_menu(D, name, icon=None, shortcut=None, tip=None, checkable=False, signal=None, callback=None, enabled=True):
def func(f):
@wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
D.addMenu(name, icon, shortcut, tip, checkable, signal, callback, enabled, wrapper)
return f
return func

View File

@ -1,121 +0,0 @@
import os
from pathlib import Path
from osgeo import gdal, gdal_array
from utils.setting import Settings
from qgis.core import QgsRasterLayer
from PyQt5.QtCore import QObject, pyqtSignal
def singleton(cls):
_instance = {}
def inner(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return inner
@singleton
class Project(QObject):
project_init = pyqtSignal(bool)
def __init__(self,
parent=None):
super().__init__(parent)
self.is_init = False
self.cell_size = Settings.Project().cell_size
self.max_memory = Settings.Project().max_memory
self.max_threads = Settings.Project().max_threads
self.root = Settings.General().root
def connect(self, pair_canvas,
layer_tree,
message_box,
result_table):
self.pair_canvas = pair_canvas
self.layer_tree = layer_tree
self.message_box = message_box
self.result_table = result_table
def setup(self, file=None):
self.is_init = True
if file is None:
self.file = Path(self.root)/'project'/'untitled.cdp'
dir_name = os.path.dirname(self.file)
if not os.path.exists(dir_name):
os.makedirs(dir_name, exist_ok=True)
if not self.file.exists():
f = self.file.open('w')
f.close()
else:
self.load()
# self.project_created.emit()
self.project_init.emit(True)
def save(self):
pass
def clear(self):
'''
clear all layers
'''
self.layer_tree.clear()
self.pair_canvas.clear()
self.message_box.clear()
self.result_table.clear()
def load(self):
pass
def add_layer(self, pth1, pth2):
player = PairLayer(pth1, pth2)
if player.check():
self.layer_tree.add_layer(player)
else:
self.message_box.show_message(player.msg)
class VectorLayer:
pass
class GridLayer:
pass
class PairLayer:
def __init__(self, pth1, pth2) -> None:
self.pth1 = pth1
self.pth2 = pth2
self.l1_name = os.path.basename(pth1)
self.l2_name = os.path.basename(pth2)
self.grid_layer = GridLayer()
self.msg = ''
def check(self):
if not os.path.exists(self.pth1):
self.msg = '图层1不存在'
return False
if not os.path.exists(self.pth2):
self.msg = '图层2不存在'
return False
ds1 = gdal.Open(self.pth1)
ds2 = gdal.Open(self.pth2)
if ds1 is None or ds2 is None:
self.msg = '图层打开失败'
return False
if ds1.RasterXSize != ds2.RasterXSize or ds1.RasterYSize != ds2.RasterYSize:
self.msg = '图层尺寸不一致'
return False
del ds1
del ds2
self.l1 = QgsRasterLayer(self.pth1, self.l1_name)
self.l2 = QgsRasterLayer(self.pth2, self.l2_name)
return True

13
未命名.prj Normal file
View File

@ -0,0 +1,13 @@
cell_size: &id001
- 100
- 100
layers:
- cell_size: *id001
l1_name: p122_r032_l5_20090915.tif
l2_name: p122_r032_l8_20170804.tif
pth1: F:/LZY_DATA/p122r032/p122_r032_l5_20090915.tif
pth2: F:/LZY_DATA/p122r032/p122_r032_l8_20170804.tif
max_memory: 100
max_threads: 4
results: []
root: F:\LZY_DATA\p122r032