完成联动
This commit is contained in:
parent
0843a369be
commit
da8d1f178e
@ -2,16 +2,60 @@ import math
|
||||
import os
|
||||
import pdb
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
from PyQt5.QtWidgets import QAction
|
||||
from PyQt5.QtWidgets import QAction, QDialog, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from rscder.utils.project import PairLayer, ResultLayer
|
||||
from PyQt5.QtGui import QIcon
|
||||
from rscder.utils.project import Project, PairLayer, ResultLayer
|
||||
from rscder.gui.layercombox import LayerCombox
|
||||
from osgeo import gdal, gdal_array
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
|
||||
class MyDialog(QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setWindowTitle('BasicChange')
|
||||
self.setWindowIcon(QIcon(":/icons/logo.svg"))
|
||||
|
||||
self.setFixedWidth(500)
|
||||
|
||||
self.layer_select = LayerCombox(self)
|
||||
self.layer_select.setFixedWidth(400)
|
||||
|
||||
# self.number_input = QLineEdit(self)
|
||||
|
||||
self.ok_button = QPushButton('OK', self)
|
||||
self.ok_button.setIcon(QIcon(":/icons/ok.svg"))
|
||||
self.ok_button.clicked.connect(self.on_ok)
|
||||
|
||||
self.cancel_button = QPushButton('Cancel', self)
|
||||
self.cancel_button.setIcon(QIcon(":/icons/cancel.svg"))
|
||||
self.cancel_button.clicked.connect(self.on_cancel)
|
||||
|
||||
self.button_layout = QHBoxLayout()
|
||||
self.button_layout.addWidget(self.ok_button)
|
||||
self.button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.main_layout.addWidget(self.layer_select)
|
||||
# self.main_layout.addWidget(self.number_input)
|
||||
self.main_layout.addLayout(self.button_layout)
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
def on_ok(self):
|
||||
self.accept()
|
||||
|
||||
def on_cancel(self):
|
||||
self.reject()
|
||||
|
||||
|
||||
|
||||
class BasicMethod(BasicPlugin):
|
||||
|
||||
message_send = pyqtSignal(str)
|
||||
table_result_ok = pyqtSignal(str)
|
||||
result_ok = pyqtSignal(dict)
|
||||
|
||||
@staticmethod
|
||||
def info():
|
||||
@ -33,34 +77,31 @@ class BasicMethod(BasicPlugin):
|
||||
basic_diff_method.triggered.connect(self.basic_diff_alg)
|
||||
|
||||
self.message_send.connect(self.send_message)
|
||||
self.table_result_ok.connect(self.on_table_result_ok)
|
||||
|
||||
self.result_ok.connect(self.on_result_ok)
|
||||
# self.result_ok.connect(self.on_result_ok)
|
||||
self.gap = 128
|
||||
|
||||
|
||||
def on_data_load(self, layer_id):
|
||||
self.basic_diff_method.setEnabled(True)
|
||||
|
||||
def send_message(self, s):
|
||||
self.message_box.info(s)
|
||||
|
||||
def on_table_result_ok(self, s):
|
||||
with open(s, 'r') as f:
|
||||
lines = f.readlines()
|
||||
data_lines = lines[1:]
|
||||
def on_result_ok(self, data):
|
||||
layer = Project().layers[data['layer_id']]
|
||||
csv_result = ResultLayer('basic_diff_result', ResultLayer.POINT)
|
||||
csv_result.load_file(data['csv_file'])
|
||||
layer.results.append(csv_result)
|
||||
self.layer_tree.update_layer(layer.id)
|
||||
|
||||
def run_basic_diff_alg(self, layer:PairLayer, out):
|
||||
|
||||
if len(data_lines) > 0:
|
||||
data_table = []
|
||||
for l in data_lines:
|
||||
l = l.strip()
|
||||
ls = l.split(',')
|
||||
ls = [float(i) for i in ls]
|
||||
data_table.append(ls)
|
||||
result = ResultLayer(ResultLayer.POINT)
|
||||
result.data = data_table
|
||||
self.result_table.set_data(result)
|
||||
pth1 = layer.pth1
|
||||
pth2 = layer.pth2
|
||||
|
||||
cell_size = layer.cell_size
|
||||
|
||||
def run_basic_diff_alg(self, pth1, pth2, cell_size, out):
|
||||
self.message_send.emit('开始计算差分法')
|
||||
|
||||
ds1 = gdal.Open(pth1)
|
||||
@ -125,7 +166,7 @@ class BasicMethod(BasicPlugin):
|
||||
self.message_send.emit('完成归一化概率')
|
||||
|
||||
self.message_send.emit('计算变化表格中...')
|
||||
out_csv = os.path.join(out, 'diff_table.csv')
|
||||
out_csv = os.path.join(out, '{}.csv'.format(int(np.random.rand() * 100000)))
|
||||
xblocks = xsize // cell_size[0]
|
||||
|
||||
normal_in_ds = gdal.Open(out_normal_tif)
|
||||
@ -151,7 +192,11 @@ class BasicMethod(BasicPlugin):
|
||||
center_y = center_y * geo[5] + geo [3]
|
||||
f.write(f'{center_x},{center_y},{block_data_xy.mean()},1\n')
|
||||
|
||||
self.table_result_ok.emit(out_csv)
|
||||
|
||||
self.result_ok.emit({
|
||||
'layer_id': layer.id,
|
||||
'csv_file': out_csv,
|
||||
})
|
||||
|
||||
self.message_send.emit('完成计算变化表格')
|
||||
|
||||
@ -159,10 +204,13 @@ class BasicMethod(BasicPlugin):
|
||||
|
||||
def basic_diff_alg(self):
|
||||
# layer_select =
|
||||
layer:PairLayer = list(self.project.layers.values())[0]
|
||||
|
||||
img1 = layer.pth1
|
||||
img2 = layer.pth2
|
||||
layer = None
|
||||
layer_select = MyDialog(self.mainwindow)
|
||||
if(layer_select.exec_()):
|
||||
layer = layer_select.layer_select.current_layer
|
||||
else:
|
||||
return
|
||||
# layer:PairLayer = list(self.project.layers.values())[0]
|
||||
|
||||
if not layer.check():
|
||||
return
|
||||
@ -170,7 +218,7 @@ class BasicMethod(BasicPlugin):
|
||||
if not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
|
||||
t = Thread(target=self.run_basic_diff_alg, args=(img1, img2, layer.cell_size, out_dir))
|
||||
t = Thread(target=self.run_basic_diff_alg, args=(layer, out_dir))
|
||||
t.start()
|
||||
|
||||
|
||||
|
247
pyinstaller.help
247
pyinstaller.help
@ -1,247 +0,0 @@
|
||||
usage: pyinstaller [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME]
|
||||
[--add-data <SRC;DEST or SRC:DEST>]
|
||||
[--add-binary <SRC;DEST or SRC:DEST>] [-p DIR]
|
||||
[--hidden-import MODULENAME]
|
||||
[--collect-submodules MODULENAME]
|
||||
[--collect-data MODULENAME] [--collect-binaries MODULENAME]
|
||||
[--collect-all MODULENAME] [--copy-metadata PACKAGENAME]
|
||||
[--recursive-copy-metadata PACKAGENAME]
|
||||
[--additional-hooks-dir HOOKSPATH]
|
||||
[--runtime-hook RUNTIME_HOOKS] [--exclude-module EXCLUDES]
|
||||
[--key KEY] [--splash IMAGE_FILE]
|
||||
[-d {all,imports,bootloader,noarchive}] [-s] [--noupx]
|
||||
[--upx-exclude FILE] [-c] [-w]
|
||||
[-i <FILE.ico or FILE.exe,ID or FILE.icns or "NONE">]
|
||||
[--disable-windowed-traceback] [--version-file FILE]
|
||||
[-m <FILE or XML>] [-r RESOURCE] [--uac-admin]
|
||||
[--uac-uiaccess] [--win-private-assemblies]
|
||||
[--win-no-prefer-redirects]
|
||||
[--osx-bundle-identifier BUNDLE_IDENTIFIER]
|
||||
[--target-architecture ARCH] [--codesign-identity IDENTITY]
|
||||
[--osx-entitlements-file FILENAME] [--runtime-tmpdir PATH]
|
||||
[--bootloader-ignore-signals] [--distpath DIR]
|
||||
[--workpath WORKPATH] [-y] [--upx-dir UPX_DIR] [-a]
|
||||
[--clean] [--log-level LEVEL]
|
||||
scriptname [scriptname ...]
|
||||
|
||||
positional arguments:
|
||||
scriptname name of scriptfiles to be processed or exactly one
|
||||
.spec-file. If a .spec-file is specified, most options
|
||||
are unnecessary and are ignored.
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --version Show program version info and exit.
|
||||
--distpath DIR Where to put the bundled app (default: .\dist)
|
||||
--workpath WORKPATH Where to put all the temporary work files, .log, .pyz
|
||||
and etc. (default: .\build)
|
||||
-y, --noconfirm Replace output directory (default:
|
||||
SPECPATH\dist\SPECNAME) without asking for
|
||||
confirmation
|
||||
--upx-dir UPX_DIR Path to UPX utility (default: search the execution
|
||||
path)
|
||||
-a, --ascii Do not include unicode encoding support (default:
|
||||
included if available)
|
||||
--clean Clean PyInstaller cache and remove temporary files
|
||||
before building.
|
||||
--log-level LEVEL Amount of detail in build-time console messages. LEVEL
|
||||
may be one of TRACE, DEBUG, INFO, WARN, ERROR,
|
||||
CRITICAL (default: INFO).
|
||||
|
||||
What to generate:
|
||||
-D, --onedir Create a one-folder bundle containing an executable
|
||||
(default)
|
||||
-F, --onefile Create a one-file bundled executable.
|
||||
--specpath DIR Folder to store the generated spec file (default:
|
||||
current directory)
|
||||
-n NAME, --name NAME Name to assign to the bundled app and spec file
|
||||
(default: first script's basename)
|
||||
|
||||
What to bundle, where to search:
|
||||
--add-data <SRC;DEST or SRC:DEST>
|
||||
Additional non-binary files or folders to be added to
|
||||
the executable. The path separator is platform
|
||||
specific, ``os.pathsep`` (which is ``;`` on Windows
|
||||
and ``:`` on most unix systems) is used. This option
|
||||
can be used multiple times.
|
||||
--add-binary <SRC;DEST or SRC:DEST>
|
||||
Additional binary files to be added to the executable.
|
||||
See the ``--add-data`` option for more details. This
|
||||
option can be used multiple times.
|
||||
-p DIR, --paths DIR A path to search for imports (like using PYTHONPATH).
|
||||
Multiple paths are allowed, separated by ``';'``, or
|
||||
use this option multiple times. Equivalent to
|
||||
supplying the ``pathex`` argument in the spec file.
|
||||
--hidden-import MODULENAME, --hiddenimport MODULENAME
|
||||
Name an import not visible in the code of the
|
||||
script(s). This option can be used multiple times.
|
||||
--collect-submodules MODULENAME
|
||||
Collect all submodules from the specified package or
|
||||
module. This option can be used multiple times.
|
||||
--collect-data MODULENAME, --collect-datas MODULENAME
|
||||
Collect all data from the specified package or module.
|
||||
This option can be used multiple times.
|
||||
--collect-binaries MODULENAME
|
||||
Collect all binaries from the specified package or
|
||||
module. This option can be used multiple times.
|
||||
--collect-all MODULENAME
|
||||
Collect all submodules, data files, and binaries from
|
||||
the specified package or module. This option can be
|
||||
used multiple times.
|
||||
--copy-metadata PACKAGENAME
|
||||
Copy metadata for the specified package. This option
|
||||
can be used multiple times.
|
||||
--recursive-copy-metadata PACKAGENAME
|
||||
Copy metadata for the specified package and all its
|
||||
dependencies. This option can be used multiple times.
|
||||
--additional-hooks-dir HOOKSPATH
|
||||
An additional path to search for hooks. This option
|
||||
can be used multiple times.
|
||||
--runtime-hook RUNTIME_HOOKS
|
||||
Path to a custom runtime hook file. A runtime hook is
|
||||
code that is bundled with the executable and is
|
||||
executed before any other code or module to set up
|
||||
special features of the runtime environment. This
|
||||
option can be used multiple times.
|
||||
--exclude-module EXCLUDES
|
||||
Optional module or package (the Python name, not the
|
||||
path name) that will be ignored (as though it was not
|
||||
found). This option can be used multiple times.
|
||||
--key KEY The key used to encrypt Python bytecode.
|
||||
--splash IMAGE_FILE (EXPERIMENTAL) Add an splash screen with the image
|
||||
IMAGE_FILE to the application. The splash screen can
|
||||
show progress updates while unpacking.
|
||||
|
||||
How to generate:
|
||||
-d {all,imports,bootloader,noarchive}, --debug {all,imports,bootloader,noarchive}
|
||||
Provide assistance with debugging a frozen
|
||||
application. This argument may be provided multiple
|
||||
times to select several of the following options.
|
||||
|
||||
- all: All three of the following options.
|
||||
|
||||
- imports: specify the -v option to the underlying
|
||||
Python interpreter, causing it to print a message
|
||||
each time a module is initialized, showing the
|
||||
place (filename or built-in module) from which it
|
||||
is loaded. See
|
||||
https://docs.python.org/3/using/cmdline.html#id4.
|
||||
|
||||
- bootloader: tell the bootloader to issue progress
|
||||
messages while initializing and starting the
|
||||
bundled app. Used to diagnose problems with
|
||||
missing imports.
|
||||
|
||||
- noarchive: instead of storing all frozen Python
|
||||
source files as an archive inside the resulting
|
||||
executable, store them as files in the resulting
|
||||
output directory.
|
||||
|
||||
-s, --strip Apply a symbol-table strip to the executable and
|
||||
shared libs (not recommended for Windows)
|
||||
--noupx Do not use UPX even if it is available (works
|
||||
differently between Windows and *nix)
|
||||
--upx-exclude FILE Prevent a binary from being compressed when using upx.
|
||||
This is typically used if upx corrupts certain
|
||||
binaries during compression. FILE is the filename of
|
||||
the binary without path. This option can be used
|
||||
multiple times.
|
||||
|
||||
Windows and Mac OS X specific options:
|
||||
-c, --console, --nowindowed
|
||||
Open a console window for standard i/o (default). On
|
||||
Windows this option will have no effect if the first
|
||||
script is a '.pyw' file.
|
||||
-w, --windowed, --noconsole
|
||||
Windows and Mac OS X: do not provide a console window
|
||||
for standard i/o. On Mac OS X this also triggers
|
||||
building an OS X .app bundle. On Windows this option
|
||||
will be set if the first script is a '.pyw' file. This
|
||||
option is ignored in *NIX systems.
|
||||
-i <FILE.ico or FILE.exe,ID or FILE.icns or "NONE">, --icon <FILE.ico or FILE.exe,ID or FILE.icns or "NONE">
|
||||
FILE.ico: apply that icon to a Windows executable.
|
||||
FILE.exe,ID, extract the icon with ID from an exe.
|
||||
FILE.icns: apply the icon to the .app bundle on Mac OS
|
||||
X. Use "NONE" to not apply any icon, thereby making
|
||||
the OS to show some default (default: apply
|
||||
PyInstaller's icon)
|
||||
--disable-windowed-traceback
|
||||
Disable traceback dump of unhandled exception in
|
||||
windowed (noconsole) mode (Windows and macOS only),
|
||||
and instead display a message that this feature is
|
||||
disabled.
|
||||
|
||||
Windows specific options:
|
||||
--version-file FILE add a version resource from FILE to the exe
|
||||
-m <FILE or XML>, --manifest <FILE or XML>
|
||||
add manifest FILE or XML to the exe
|
||||
-r RESOURCE, --resource RESOURCE
|
||||
Add or update a resource to a Windows executable. The
|
||||
RESOURCE is one to four items,
|
||||
FILE[,TYPE[,NAME[,LANGUAGE]]]. FILE can be a data file
|
||||
or an exe/dll. For data files, at least TYPE and NAME
|
||||
must be specified. LANGUAGE defaults to 0 or may be
|
||||
specified as wildcard * to update all resources of the
|
||||
given TYPE and NAME. For exe/dll files, all resources
|
||||
from FILE will be added/updated to the final
|
||||
executable if TYPE, NAME and LANGUAGE are omitted or
|
||||
specified as wildcard *.This option can be used
|
||||
multiple times.
|
||||
--uac-admin Using this option creates a Manifest which will
|
||||
request elevation upon application restart.
|
||||
--uac-uiaccess Using this option allows an elevated application to
|
||||
work with Remote Desktop.
|
||||
|
||||
Windows Side-by-side Assembly searching options (advanced):
|
||||
--win-private-assemblies
|
||||
Any Shared Assemblies bundled into the application
|
||||
will be changed into Private Assemblies. This means
|
||||
the exact versions of these assemblies will always be
|
||||
used, and any newer versions installed on user
|
||||
machines at the system level will be ignored.
|
||||
--win-no-prefer-redirects
|
||||
While searching for Shared or Private Assemblies to
|
||||
bundle into the application, PyInstaller will prefer
|
||||
not to follow policies that redirect to newer
|
||||
versions, and will try to bundle the exact versions of
|
||||
the assembly.
|
||||
|
||||
Mac OS X specific options:
|
||||
--osx-bundle-identifier BUNDLE_IDENTIFIER
|
||||
Mac OS X .app bundle identifier is used as the default
|
||||
unique program name for code signing purposes. The
|
||||
usual form is a hierarchical name in reverse DNS
|
||||
notation. For example:
|
||||
com.mycompany.department.appname (default: first
|
||||
script's basename)
|
||||
--target-architecture ARCH, --target-arch ARCH
|
||||
Target architecture (macOS only; valid values: x86_64,
|
||||
arm64, universal2). Enables switching between
|
||||
universal2 and single-arch version of frozen
|
||||
application (provided python installation supports the
|
||||
target architecture). If not target architecture is
|
||||
not specified, the current running architecture is
|
||||
targeted.
|
||||
--codesign-identity IDENTITY
|
||||
Code signing identity (macOS only). Use the provided
|
||||
identity to sign collected binaries and generated
|
||||
executable. If signing identity is not provided, ad-
|
||||
hoc signing is performed instead.
|
||||
--osx-entitlements-file FILENAME
|
||||
Entitlements file to use when code-signing the
|
||||
collected binaries (macOS only).
|
||||
|
||||
Rarely used special options:
|
||||
--runtime-tmpdir PATH
|
||||
Where to extract libraries and support files in
|
||||
`onefile`-mode. If this option is given, the
|
||||
bootloader will ignore any temp-folder location
|
||||
defined by the run-time OS. The ``_MEIxxxxxx``-folder
|
||||
will be created here. Please use this option only if
|
||||
you know what you are doing.
|
||||
--bootloader-ignore-signals
|
||||
Tell the bootloader to ignore signals rather than
|
||||
forwarding them to the child process. Useful in
|
||||
situations where e.g. a supervisor process signals
|
||||
both the bootloader and child (e.g. via a process
|
||||
group) to avoid signalling the child twice.
|
0
rscder/gui/__init__.py
Normal file
0
rscder/gui/__init__.py
Normal file
22
rscder/gui/layercombox.py
Normal file
22
rscder/gui/layercombox.py
Normal file
@ -0,0 +1,22 @@
|
||||
from PyQt5.QtWidgets import QComboBox
|
||||
from rscder.utils.project import Project
|
||||
class LayerCombox(QComboBox):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.addItem('---', None)
|
||||
|
||||
for layer in Project().layers.values():
|
||||
self.addItem(layer.name, layer.id)
|
||||
|
||||
self.currentIndexChanged.connect(self.on_changed)
|
||||
|
||||
self.current_layer = None
|
||||
|
||||
def on_changed(self, index):
|
||||
if index == 0:
|
||||
self.current_layer = None
|
||||
else:
|
||||
self.current_layer = Project().layers[self.itemData(index)]
|
||||
|
@ -1,7 +1,8 @@
|
||||
|
||||
import pdb
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import Qt,QModelIndex
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QCursor
|
||||
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||
from rscder.gui.actions import get_action_manager
|
||||
|
||||
@ -9,6 +10,15 @@ from rscder.utils.project import PairLayer, Project
|
||||
|
||||
class LayerTree(QtWidgets.QWidget):
|
||||
|
||||
LAYER_TOOT = 0
|
||||
SUB_RASTER = 1
|
||||
RESULT = 2
|
||||
LEFT_RASTER = 0
|
||||
RIGHT_RASTER = 1
|
||||
GRID = 3
|
||||
|
||||
tree_changed = QtCore.pyqtSignal(str)
|
||||
result_clicked = QtCore.pyqtSignal(str, int)
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
# self.tree_view = QTreeView(self)
|
||||
@ -16,7 +26,8 @@ class LayerTree(QtWidgets.QWidget):
|
||||
|
||||
self.tree.setColumnCount(1)
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(self.right_menu_show)
|
||||
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.tree.customContextMenuRequested.connect(self.right_menu_show)
|
||||
self.root=QTreeWidgetItem(self.tree)
|
||||
self.tree.setHeaderHidden(True)
|
||||
# self.tree.setHeaderLabels(['图层'])
|
||||
@ -31,35 +42,122 @@ class LayerTree(QtWidgets.QWidget):
|
||||
|
||||
self.tree.addTopLevelItem(self.root)
|
||||
|
||||
self.tree.clicked.connect(self.onClicked)
|
||||
# self.tree.clicked.connect(self.onClicked)
|
||||
self.tree.itemClicked.connect(self.onItemClicked)
|
||||
self.tree.itemChanged.connect(self.onItemChanged)
|
||||
|
||||
layout = QtWidgets.QGridLayout()
|
||||
layout.addWidget(self.tree)
|
||||
self.setLayout(layout)
|
||||
self.setLayoutDirection(Qt.LeftToRight)
|
||||
self.is_in_add_layer = False
|
||||
|
||||
def onClicked(self,index):
|
||||
print(index.row())
|
||||
item = self.tree.currentItem()
|
||||
def onItemClicked(self, item:QtWidgets.QTreeWidgetItem, column):
|
||||
if item == self.root:
|
||||
return
|
||||
layer_id = str(item.data(0, Qt.UserRole))
|
||||
layer = Project().layers[layer_id]
|
||||
print(layer.l1_name)
|
||||
print(layer.l2_name)
|
||||
root = item
|
||||
if item.data(0, Qt.UserRole) != LayerTree.LAYER_TOOT:
|
||||
root = item.parent()
|
||||
if item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
|
||||
return
|
||||
layer = Project().layers[root.data(0, Qt.UserRole + 1)]
|
||||
Project().current_layer = layer
|
||||
if item.data(0, Qt.UserRole) == LayerTree.RESULT:
|
||||
# result = layer.results[item.data(0, Qt.UserRole + 1)]
|
||||
self.result_clicked.emit(layer.id, item.data(0, Qt.UserRole + 1))
|
||||
|
||||
|
||||
def onItemChanged(self, item:QtWidgets.QTreeWidgetItem, column):
|
||||
if self.is_in_add_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(layer.id)
|
||||
|
||||
def add_layer(self, layer:str):
|
||||
# self.tree.it
|
||||
self.is_in_add_layer = True
|
||||
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)
|
||||
item_root = QtWidgets.QTreeWidgetItem(self.root)
|
||||
item_root.setText(0,layer.name)
|
||||
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)
|
||||
|
||||
item1.setData(0, Qt.UserRole, layer.id)
|
||||
item2.setData(0, Qt.UserRole, layer.id)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
item2 = QtWidgets.QTreeWidgetItem(item_root)
|
||||
item2.setText(0, layer.l2_name)
|
||||
item2.setCheckState(0, Qt.Checked if layer.l2_enable else Qt.Unchecked)
|
||||
item1.setData(0, Qt.UserRole, LayerTree.SUB_RASTER)
|
||||
item1.setData(0, Qt.UserRole + 1, LayerTree.RIGHT_RASTER)
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
print(layer_root.text(0))
|
||||
if layer_root is None:
|
||||
self.add_layer(layer.id)
|
||||
return
|
||||
|
||||
layer_root.setText(0,layer.name)
|
||||
|
||||
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 clear(self):
|
||||
self.tree.clear()
|
||||
@ -70,17 +168,37 @@ class LayerTree(QtWidgets.QWidget):
|
||||
def right_menu_show(self, position):
|
||||
rightMenu = QtWidgets.QMenu(self)
|
||||
# QAction = QtWidgets.QAction(self.menuBar1)
|
||||
item = self.tree.currentItem()
|
||||
item = self.tree.itemAt(position)
|
||||
|
||||
action_manager = get_action_manager()
|
||||
actions = []
|
||||
if item == self.root:
|
||||
data_load_action = action_manager.get_action('&数据加载', 'File')
|
||||
actions.append(data_load_action)
|
||||
data_load_action = action_manager.get_action('&数据加载', 'File')
|
||||
actions.append(data_load_action)
|
||||
if item is None:
|
||||
print('nothing')
|
||||
else:
|
||||
pass
|
||||
|
||||
if item == self.root:
|
||||
pass
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.LAYER_TOOT:
|
||||
actions.append(QtWidgets.QAction('&缩放至该图层', self))
|
||||
|
||||
actions.append(QtWidgets.QAction('&重命名', self))
|
||||
actions.append(QtWidgets.QAction('&删除', self))
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.SUB_RASTER:
|
||||
actions.append(QtWidgets.QAction('&缩放至该图层', self))
|
||||
|
||||
actions.append(QtWidgets.QAction('&重命名', self))
|
||||
actions.append(QtWidgets.QAction('&删除', self))
|
||||
elif item.data(0, Qt.UserRole) == LayerTree.RESULT:
|
||||
actions.append(QtWidgets.QAction('&缩放至该图层', self))
|
||||
|
||||
actions.append(QtWidgets.QAction('&重命名', self))
|
||||
actions.append(QtWidgets.QAction('&导出', self))
|
||||
actions.append(QtWidgets.QAction('&删除', self))
|
||||
|
||||
|
||||
|
||||
for action in actions:
|
||||
rightMenu.addAction(action)
|
||||
|
||||
rightMenu.exec_(self.mapToGlobal(position))
|
||||
|
||||
rightMenu.exec_(QCursor.pos())
|
@ -33,6 +33,11 @@ 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.action_manager = ActionManager(
|
||||
self.double_map,
|
||||
self.layer_tree,
|
||||
|
@ -66,8 +66,9 @@ class DoubleCanvas(QWidget):
|
||||
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)
|
||||
if layer.grid_enable:
|
||||
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()
|
||||
@ -99,16 +100,48 @@ class DoubleCanvas(QWidget):
|
||||
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:
|
||||
layer:PairLayer = Project().layers[layer]
|
||||
if not layer.enable:
|
||||
return
|
||||
self.clear()
|
||||
|
||||
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:
|
||||
|
||||
if layer.l1_enable:
|
||||
self.mapcanva1.add_layer(layer.l1)
|
||||
if layer.l2_enable:
|
||||
self.mapcanva2.add_layer(layer.l2)
|
||||
if layer.grid_enable and self.grid_show:
|
||||
self.mapcanva1.add_grid_layer(layer.grid_layer.grid_layer)
|
||||
self.mapcanva2.add_grid_layer(layer.grid_layer.grid_layer)
|
||||
|
||||
|
||||
for r in layer.results:
|
||||
if r.enable:
|
||||
self.mapcanva1.add_layer(r.layer)
|
||||
self.mapcanva2.add_layer(r.layer)
|
||||
# self.mapcanva1.set_extent(layer.l1.extent())
|
||||
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)
|
||||
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 layer_changed(self, layer:str):
|
||||
self.add_layer(layer)
|
||||
|
||||
def clear(self):
|
||||
self.mapcanva1.clear()
|
||||
self.mapcanva2.clear()
|
||||
|
@ -4,7 +4,7 @@ from PyQt5.QtCore import Qt,QModelIndex, pyqtSignal
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtWidgets import (QTableWidgetItem, QTableWidget, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||
|
||||
from rscder.utils.project import PairLayer, ResultLayer
|
||||
from rscder.utils.project import PairLayer, Project, ResultLayer
|
||||
|
||||
class ResultTable(QtWidgets.QWidget):
|
||||
|
||||
@ -29,11 +29,15 @@ class ResultTable(QtWidgets.QWidget):
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(self.tablewidget)
|
||||
self.setLayout(layout)
|
||||
self.result = None
|
||||
self.is_in_set_data = False
|
||||
|
||||
def clear(self):
|
||||
pass
|
||||
self.tablewidget.clear()
|
||||
|
||||
def onChanged(self, row, col):
|
||||
if self.is_in_set_data:
|
||||
return
|
||||
if col == 3:
|
||||
item_idx = row
|
||||
item_status = self.tablewidget.item(row, col).checkState() == Qt.Checked
|
||||
@ -41,7 +45,8 @@ class ResultTable(QtWidgets.QWidget):
|
||||
self.tablewidget.item(row, col).setBackground(Qt.yellow)
|
||||
else:
|
||||
self.tablewidget.item(row, col).setBackground(Qt.green)
|
||||
self.on_item_changed.emit({'idx':item_idx, 'status':item_status})
|
||||
# print(item_idx, item_status)
|
||||
self.result.update({'row':item_idx, 'value':item_status})
|
||||
|
||||
def onClicked(self, row, col):
|
||||
if col == 3:
|
||||
@ -50,9 +55,18 @@ class ResultTable(QtWidgets.QWidget):
|
||||
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':x, 'y':y})
|
||||
self.on_item_click.emit({'x':float(x), 'y':float(y)})
|
||||
|
||||
def on_result(self, layer_id, result_id):
|
||||
self.is_in_set_data = True
|
||||
result = Project().layers[layer_id].results[result_id]
|
||||
self.result = result
|
||||
self.clear()
|
||||
self.set_data(result)
|
||||
def set_data(self, data:ResultLayer):
|
||||
self.is_in_set_data = True
|
||||
if data.layer_type != ResultLayer.POINT:
|
||||
return
|
||||
self.tablewidget.setRowCount(len(data.data))
|
||||
# print(len(data.data))
|
||||
self.tablewidget.setVerticalHeaderLabels([ str(i+1) for i in range(len(data.data))])
|
||||
@ -73,5 +87,4 @@ class ResultTable(QtWidgets.QWidget):
|
||||
self.tablewidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
self.tablewidget.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
|
||||
|
||||
|
||||
self.is_in_set_data = False
|
@ -2,9 +2,10 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
import uuid
|
||||
import numpy as np
|
||||
from osgeo import gdal, gdal_array
|
||||
from rscder.utils.setting import Settings
|
||||
from qgis.core import QgsRasterLayer, QgsLineSymbol, QgsSingleSymbolRenderer, QgsSimpleLineSymbolLayer, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsGeometry, QgsPointXY
|
||||
from qgis.core import QgsRasterLayer, QgsMarkerSymbol, QgsPalLayerSettings, QgsRuleBasedLabeling, QgsTextFormat, QgsLineSymbol, QgsSingleSymbolRenderer, QgsSimpleLineSymbolLayer, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsFeature, QgsGeometry, QgsPointXY
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
from PyQt5.QtGui import QColor
|
||||
import yaml
|
||||
@ -32,6 +33,7 @@ class Project(QObject):
|
||||
self.root = str(Path(Settings.General().root)/'default')
|
||||
self.file_mode = Project.ABSOLUTE_MODE
|
||||
self.layers:Dict[str, PairLayer] = dict()
|
||||
self.current_layer = None
|
||||
|
||||
def connect(self, pair_canvas,
|
||||
layer_tree,
|
||||
@ -44,8 +46,17 @@ class Project(QObject):
|
||||
|
||||
self.layer_load.connect(layer_tree.add_layer)
|
||||
self.layer_load.connect(pair_canvas.add_layer)
|
||||
# self.layer_load.connect(message_box.add_layer)
|
||||
|
||||
# self.layer_load.connect(message_box.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
|
||||
|
||||
def setup(self, path = None, name = None):
|
||||
self.is_init = True
|
||||
if path is not None:
|
||||
@ -71,7 +82,6 @@ class Project(QObject):
|
||||
'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() ],
|
||||
'results': []
|
||||
}
|
||||
with open(self.file, 'w') as f:
|
||||
yaml.safe_dump(data_dict, f)
|
||||
@ -89,22 +99,25 @@ class Project(QObject):
|
||||
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, None if self.file_mode == Project.ABSOLUTE_MODE else self.root)
|
||||
if player.check():
|
||||
self.layers[player.id] = player
|
||||
self.layer_load.emit(player.id)
|
||||
|
||||
try:
|
||||
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, None if self.file_mode == Project.ABSOLUTE_MODE else self.root)
|
||||
if player.check():
|
||||
self.layers[player.id] = player
|
||||
self.layer_load.emit(player.id)
|
||||
except Exception as e:
|
||||
self.message_box.error(str(e))
|
||||
self.clear()
|
||||
def add_layer(self, pth1, pth2):
|
||||
# self.root = str(Path(pth1).parent)
|
||||
|
||||
@ -205,9 +218,142 @@ class ResultLayer:
|
||||
POINT = 0
|
||||
RASTER = 1
|
||||
|
||||
def __init__(self, layer_type):
|
||||
def __init__(self, name, layer_type = POINT):
|
||||
self.layer_type = layer_type
|
||||
self.data = []
|
||||
self.data = None
|
||||
self.layer = None
|
||||
self.name = name
|
||||
self.path = None
|
||||
self.wkt = None
|
||||
self.enable = False
|
||||
|
||||
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()
|
||||
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')
|
||||
|
||||
def format_point_layer(self, layer):
|
||||
layer.setLabelsEnabled(True)
|
||||
lyr = QgsPalLayerSettings()
|
||||
lyr.enabled = True
|
||||
lyr.fieldName = 'id'
|
||||
lyr.placement = QgsPalLayerSettings.OverPoint
|
||||
lyr.textNamedStyle = 'Medium'
|
||||
text_format = QgsTextFormat()
|
||||
text_format.color = QColor('#ffffff')
|
||||
text_format.background().color = QColor('#000000')
|
||||
text_format.buffer().setEnabled(True)
|
||||
text_format.buffer().setSize(1)
|
||||
text_format.buffer().setOpacity(0.5)
|
||||
lyr.setFormat(text_format)
|
||||
root = QgsRuleBasedLabeling.Rule(QgsPalLayerSettings())
|
||||
rule = QgsRuleBasedLabeling.Rule(lyr)
|
||||
rule.setDescription('label')
|
||||
root.appendChild(rule)
|
||||
#Apply label configuration
|
||||
rules = QgsRuleBasedLabeling(root)
|
||||
layer.setLabeling(rules)
|
||||
|
||||
def set_render(self, layer):
|
||||
symbol = QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '5'})
|
||||
render = QgsSingleSymbolRenderer(symbol)
|
||||
layer.setRenderer(render)
|
||||
|
||||
def load_point_file(self):
|
||||
data = np.loadtxt(self.path, delimiter=',', skiprows=1)
|
||||
if data is None:
|
||||
return
|
||||
self.data = data
|
||||
self.make_point_layer()
|
||||
|
||||
def make_point_layer(self):
|
||||
if self.wkt is not None:
|
||||
crs = QgsCoordinateReferenceSystem()
|
||||
crs.createFromString('WKT:{}'.format(self.wkt))
|
||||
else:
|
||||
crs = QgsCoordinateReferenceSystem()
|
||||
|
||||
uri = 'Point?crs={}'.format(crs.toProj())
|
||||
layer = QgsVectorLayer(uri, self.name, "memory")
|
||||
if not layer.isValid():
|
||||
Project().message_box.error('Failed to create layer')
|
||||
return
|
||||
self.format_point_layer(layer)
|
||||
layer.startEditing()
|
||||
features = []
|
||||
for i, d in enumerate(self.data):
|
||||
point = QgsFeature(i)
|
||||
point.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(d[0], d[1])))
|
||||
# point.setAttribute('id', i)
|
||||
features.append(point)
|
||||
layer.addFeatures(features)
|
||||
layer.commitChanges()
|
||||
self.set_render(layer)
|
||||
self.layer = layer
|
||||
|
||||
def update_point_layer(self):
|
||||
if self.layer is None:
|
||||
return
|
||||
self.layer.startEditing()
|
||||
add_features = []
|
||||
delete_features = []
|
||||
for i, d in enumerate(self.data):
|
||||
feature = self.layer.getFeature(i+1)
|
||||
if d[-1]:
|
||||
if feature is None:
|
||||
feature = QgsFeature(i)
|
||||
feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(d[0], d[1])))
|
||||
# feature.setAttribute('id', i)
|
||||
add_features.append(feature)
|
||||
else:
|
||||
if feature is not None:
|
||||
delete_features.append(feature.id())
|
||||
if len(add_features) > 0:
|
||||
self.layer.addFeatures(add_features)
|
||||
if len(delete_features) > 0:
|
||||
self.layer.deleteFeatures(delete_features)
|
||||
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(data, root = None):
|
||||
result = ResultLayer(data['name'], 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 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))
|
||||
}
|
||||
# def load_file(self, path):
|
||||
|
||||
|
||||
class PairLayer:
|
||||
|
||||
@ -219,14 +365,19 @@ class PairLayer:
|
||||
'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
|
||||
@ -237,23 +388,37 @@ class PairLayer:
|
||||
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, root))
|
||||
# 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.enable = True
|
||||
self.l1_enable = True
|
||||
self.l2_enable = True
|
||||
self.grid_enable = True
|
||||
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.cell_size = cell_size
|
||||
|
||||
# self.grid_layer = GridLayer(cell_size)
|
||||
|
||||
self.msg = ''
|
||||
self.checked = False
|
||||
|
||||
|
||||
self.xsize = 0
|
||||
self.ysize = 0
|
||||
self.xres = 0
|
||||
self.yres = 0
|
||||
|
||||
self.wkt = None
|
||||
|
||||
self.results:List[ResultLayer] = []
|
||||
|
||||
def check(self):
|
||||
if self.checked:
|
||||
return self.checked
|
||||
@ -274,6 +439,14 @@ class PairLayer:
|
||||
self.msg = '图层尺寸不一致'
|
||||
return False
|
||||
|
||||
self.xsize = ds1.RasterXSize
|
||||
self.ysize = ds1.RasterYSize
|
||||
|
||||
self.xres = ds1.GetGeoTransform()[1]
|
||||
self.yres = ds1.GetGeoTransform()[5]
|
||||
|
||||
self.wkt = ds1.GetProjection()
|
||||
|
||||
self.grid_layer = GridLayer(self.cell_size, ds1)
|
||||
|
||||
del ds1
|
||||
|
Loading…
x
Reference in New Issue
Block a user