change build
8
build.bat
Normal file
@ -0,0 +1,8 @@
|
||||
nuitka run.py --standalone --plugin-enable=qt-plugins --plugin-enable=numpy --show-progress --include-package=qgis --plugin-enable=pylint-warnings --output-dir=package --windows-disable-console --windows-icon-from-ico=logo.ico --no-pyi-file
|
||||
|
||||
|
||||
REM Win7 with console
|
||||
REM nuitka gui.py --mingw64 --standalone --plugin-enable=qt-plugins --plugin-enable=numpy --recurse-all --show-progress --include-package=qgis --output-dir=package --windows-icon=icons/logo.ico
|
||||
|
||||
REM Win7
|
||||
@REM nuitka gui.py --mingw64 --standalone --plugin-enable=qt-plugins --plugin-enable=numpy --recurse-all --show-progress --include-package=qgis --output-dir=package --windows-disable-console --windows-icon=icons/logo.ico
|
Before Width: | Height: | Size: 638 B After Width: | Height: | Size: 638 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 622 B After Width: | Height: | Size: 622 B |
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 508 B |
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 632 B |
Before Width: | Height: | Size: 689 B After Width: | Height: | Size: 689 B |
Before Width: | Height: | Size: 642 B After Width: | Height: | Size: 642 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 699 B After Width: | Height: | Size: 699 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 593 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 514 B After Width: | Height: | Size: 514 B |
Before Width: | Height: | Size: 654 B After Width: | Height: | Size: 654 B |
Before Width: | Height: | Size: 756 B After Width: | Height: | Size: 756 B |
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 730 B |
1
plugins/basic_change/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from basic_change.main import *
|
9112
plugins/basic_change/main.c
Normal file
@ -1,8 +1,148 @@
|
||||
import math
|
||||
import os
|
||||
from rscder.plugins.basic import BasicPlugin
|
||||
|
||||
from PyQt5.QtWidgets import QAction
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from rscder.utils.project import PairLayer
|
||||
from osgeo import gdal, gdal_array
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
class BasicMethod(BasicPlugin):
|
||||
|
||||
message_send = pyqtSignal(str)
|
||||
|
||||
@staticmethod
|
||||
def info():
|
||||
return {
|
||||
'name': 'BasicMethod',
|
||||
'description': 'BasicMethod',
|
||||
'author': 'RSCDER',
|
||||
'version': '1.0.0',
|
||||
}
|
||||
|
||||
def set_action(self):
|
||||
menubar = self.ctx['menubar']
|
||||
basic_change_detection_menu = self.ctx['basic_change_detection_menu']
|
||||
|
||||
basic_diff_method = QAction('差分法')
|
||||
basic_change_detection_menu.addAction(basic_diff_method)
|
||||
|
||||
basic_diff_method.setEnabled(False)
|
||||
self.basic_diff_method = basic_diff_method
|
||||
|
||||
self.message_send.connect(self.send_message)
|
||||
|
||||
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 run_basic_diff_alg(self, pth1, pth2, cell_size, out):
|
||||
self.message_send.emit('开始计算差分法')
|
||||
|
||||
ds1 = gdal.Open(pth1)
|
||||
ds2 = gdal.Open(pth2)
|
||||
xsize = ds1.RasterXSize
|
||||
ysize = ds1.RasterYSize
|
||||
band = ds1.RasterCount
|
||||
yblocks = ysize // cell_size[1]
|
||||
|
||||
geo = ds1.GetGeoTransform()
|
||||
|
||||
driver = gdal.GetDriverByName('GTiff')
|
||||
out_tif = os.path.join(out, 'temp.tif')
|
||||
out_ds = driver.Create(out_tif, xsize, ysize, 1, gdal.GDT_Float32)
|
||||
out_ds.SetGeoTransform(ds1.GetGeoTransform())
|
||||
out_ds.SetProjection(ds1.GetProjection())
|
||||
max_diff = 0
|
||||
min_diff = math.inf
|
||||
for j in range(yblocks):
|
||||
self.message_send.emit(f'计算{j}/{yblocks}')
|
||||
block_xy = (0, j * cell_size[1])
|
||||
block_size = (xsize, cell_size[1])
|
||||
if block_xy[1] + block_size[1] > ysize:
|
||||
block_size = (xsize, ysize - block_xy[1])
|
||||
block_data1 = ds1.ReadAsArray(*block_xy, *block_size)
|
||||
block_data2 = ds2.ReadAsArray(*block_xy, *block_size)
|
||||
|
||||
if band == 1:
|
||||
block_data1 = block_data1[None, ...]
|
||||
block_data2 = block_data2[None, ...]
|
||||
|
||||
block_diff = block_data1 - block_data2
|
||||
block_diff = block_diff.astype(np.float32)
|
||||
block_diff = block_diff.abs().sum(0)
|
||||
|
||||
min_diff = min(min_diff, block_diff.min())
|
||||
max_diff = max(max_diff, block_diff.max())
|
||||
out_ds.GetRasterBand(1).WriteArray(block_diff, *block_xy)
|
||||
|
||||
self.message_send.emit(f'完成{j}/{yblocks}')
|
||||
|
||||
out_ds.FlushCache()
|
||||
out_ds = None
|
||||
self.message_send.emit('归一化概率中...')
|
||||
temp_in_ds = gdal.Open(out_tif)
|
||||
|
||||
out_normal_tif = os.path.join(out, 'diff_0_255.tif')
|
||||
out_normal_ds = driver.Create(out_normal_tif, xsize, ysize, 1, gdal.GDT_Byte)
|
||||
|
||||
for j in range(yblocks):
|
||||
block_xy = (0, j * cell_size[1])
|
||||
block_size = (xsize, cell_size[1])
|
||||
if block_xy[1] + block_size[1] > ysize:
|
||||
block_size = (xsize, ysize - block_xy[1])
|
||||
block_data = temp_in_ds.ReadAsArray(*block_xy, *block_size)
|
||||
block_data = (block_data - min_diff) / (max_diff - min_diff) * 255
|
||||
block_data = block_data.astype(np.uint8)
|
||||
out_normal_ds.GetRasterBand(1).WriteArray(block_data, *block_xy)
|
||||
|
||||
out_normal_ds.FlushCache()
|
||||
out_normal_ds = None
|
||||
self.message_send.emit('完成归一化概率')
|
||||
|
||||
self.message_send.emit('计算变化表格中...')
|
||||
out_csv = os.path.join(out, 'diff_table.csv')
|
||||
xblocks = xsize // cell_size[0]
|
||||
with open(out_csv, 'w') as f:
|
||||
f.write('x,y,diff,status\n')
|
||||
for j in range(yblocks):
|
||||
block_xy = (0, j * cell_size[1])
|
||||
block_size = (xsize, cell_size[1])
|
||||
if block_xy[1] + block_size[1] > ysize:
|
||||
block_size = (xsize, ysize - block_xy[1])
|
||||
block_data = temp_in_ds.ReadAsArray(*block_xy, *block_size)
|
||||
for i in range(xblocks):
|
||||
start_x = i * cell_size[0]
|
||||
end_x = start_x + cell_size[0]
|
||||
if end_x > xsize:
|
||||
end_x = xsize
|
||||
block_data_xy = block_data[:, start_x:end_x]
|
||||
if block_data_xy.mean() > self.gap:
|
||||
center_x = start_x + cell_size[0] // 2
|
||||
center_y = j * cell_size[1] + cell_size[1] // 2
|
||||
center_x = center_x * geo[1] + geo [0]
|
||||
center_y = center_y * geo[5] + geo [3]
|
||||
f.write(f'{center_x},{center_y},{block_data_xy.mean()},1\n')
|
||||
|
||||
self.message_send.emit('完成计算变化表格')
|
||||
|
||||
self.message_send.emit('差分法计算完成')
|
||||
|
||||
def basic_diff_alg(self):
|
||||
# layer_select =
|
||||
layer:PairLayer = self.project.layers.values()[0]
|
||||
|
||||
img1 = layer.pth2
|
||||
img2 = layer.pth2
|
||||
|
||||
if not layer.check():
|
||||
return
|
||||
|
||||
t = Thread(target=self.run_basic_diff_alg, args=(img1, img2, layer.pth1))
|
||||
t.start()
|
||||
|
||||
|
||||
|
247
pyinstaller.help
Normal file
@ -0,0 +1,247 @@
|
||||
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.
|
@ -4,9 +4,18 @@ 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.utils.misc import singleton
|
||||
from rscder.gui.plugins import PluginDialog
|
||||
from rscder.utils.setting import Settings
|
||||
|
||||
def get_action_manager() -> 'ActionManager':
|
||||
return ActionManager()
|
||||
|
||||
@singleton
|
||||
class ActionManager(QtCore.QObject):
|
||||
|
||||
instance = None
|
||||
|
||||
def __init__(self,
|
||||
double_map,
|
||||
layer_tree,
|
||||
@ -137,147 +146,9 @@ class ActionManager(QtCore.QObject):
|
||||
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
|
||||
@ -299,6 +170,11 @@ class ActionManager(QtCore.QObject):
|
||||
self.double_map.corr_changed.connect(corr_widget.setText)
|
||||
self.double_map.scale_changed.connect(scale_widget.setText)
|
||||
|
||||
lic_end_date = QLabel(self.status_bar)
|
||||
lic_end_date.setFixedWidth(200)
|
||||
lic_end_date.setText('有效期至:%s' % (Settings.General().end_date))
|
||||
self.status_bar.addPermanentWidget(lic_end_date)
|
||||
|
||||
def plugin_list(self):
|
||||
dialog = PluginDialog(self.w_parent)
|
||||
dialog.show()
|
||||
@ -365,7 +241,7 @@ class ActionManager(QtCore.QObject):
|
||||
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):
|
||||
@ -375,10 +251,10 @@ class ActionManager(QtCore.QObject):
|
||||
if group_name is None:
|
||||
return None
|
||||
else:
|
||||
if group_name not in self.action_group_actions:
|
||||
if group_name not in self.action_groups:
|
||||
return None
|
||||
else:
|
||||
group = self.action_group_actions[group_name]
|
||||
group = self.action_groups[group_name]
|
||||
for action in group.actions():
|
||||
if action.text() == action_name:
|
||||
return action
|
||||
@ -387,11 +263,5 @@ class ActionManager(QtCore.QObject):
|
||||
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
|
@ -3,6 +3,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import Qt,QModelIndex
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||
from rscder.gui.actions import get_action_manager
|
||||
|
||||
from rscder.utils.project import PairLayer, Project
|
||||
|
||||
@ -10,8 +11,9 @@ class LayerTree(QtWidgets.QWidget):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.tree_view = QTreeView(self)
|
||||
# self.tree_view = QTreeView(self)
|
||||
self.tree = QtWidgets.QTreeWidget(self)
|
||||
|
||||
self.tree.setColumnCount(1)
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(self.right_menu_show)
|
||||
@ -38,6 +40,13 @@ class LayerTree(QtWidgets.QWidget):
|
||||
|
||||
def onClicked(self,index):
|
||||
print(index.row())
|
||||
item = self.tree.currentItem()
|
||||
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)
|
||||
|
||||
def add_layer(self, layer:str):
|
||||
layer:PairLayer = Project().layers[layer]
|
||||
@ -61,10 +70,17 @@ class LayerTree(QtWidgets.QWidget):
|
||||
def right_menu_show(self, position):
|
||||
rightMenu = QtWidgets.QMenu(self)
|
||||
# QAction = QtWidgets.QAction(self.menuBar1)
|
||||
self.actionreboot = QtWidgets.QAction('zhangji')
|
||||
self.actionreboot.setObjectName("actionreboot")
|
||||
self.actionreboot.setText('aaa')
|
||||
rightMenu.addAction(self.actionreboot)
|
||||
item = self.tree.currentItem()
|
||||
action_manager = get_action_manager()
|
||||
actions = []
|
||||
if item == self.root:
|
||||
data_load_action = action_manager.get_action('&数据加载', 'File')
|
||||
actions.append(data_load_action)
|
||||
else:
|
||||
pass
|
||||
|
||||
for action in actions:
|
||||
rightMenu.addAction(action)
|
||||
|
||||
rightMenu.exec_(self.mapToGlobal(position))
|
||||
|
||||
|
@ -69,6 +69,8 @@ class License(QtWidgets.QDialog):
|
||||
if not os.path.exists(pth):
|
||||
QtWidgets.QMessageBox.warning(self, "Warning", "The selected file does not exist.")
|
||||
else:
|
||||
if not os.path.exists('lic'):
|
||||
os.mkdir('lic')
|
||||
shutil.copy(pth, os.path.join("lic", "license.lic"))
|
||||
self.accept()
|
||||
self.close()
|
@ -1,5 +1,5 @@
|
||||
import pdb
|
||||
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow
|
||||
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QToolBox
|
||||
from PyQt5.QtCore import Qt, QSize
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5 import QtGui
|
||||
@ -63,11 +63,10 @@ class MainWindow(QMainWindow):
|
||||
self.toolbar = self.addToolBar('Toolbar')
|
||||
self.toolbar.setMovable(False)
|
||||
self.toolbar.setFloatable(False)
|
||||
self.toolbar.setIconSize(QSize(16, 16))
|
||||
self.toolbar.setIconSize(QSize(32, 32))
|
||||
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||
self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||
self.toolbar.setLayoutDirection(Qt.LeftToRight)
|
||||
pass
|
||||
|
||||
|
||||
def set_pannels(self):
|
||||
@ -82,8 +81,17 @@ class MainWindow(QMainWindow):
|
||||
central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
|
||||
|
||||
self.double_map.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
self.layer_tree = LayerTree(self)
|
||||
left_tool_box = QToolBox(self)
|
||||
|
||||
self.follow_box = QWidget(self)
|
||||
self.eye_box = QWidget(self)
|
||||
left_tool_box.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
left_tool_box.addItem(self.layer_tree, self.tr("图层树"))
|
||||
left_tool_box.addItem(self.follow_box, self.tr("流程"))
|
||||
left_tool_box.addItem(self.eye_box, self.tr("鹰眼"))
|
||||
|
||||
|
||||
# self.layer_tree.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
def set_docker_fixed(docker):
|
||||
@ -91,15 +99,11 @@ class MainWindow(QMainWindow):
|
||||
docker.setFeature(QtAds.ads.CDockWidget.DockWidgetFeature.DockWidgetMovable , False)
|
||||
docker.setFeature(QtAds.ads.CDockWidget.DockWidgetFeature.DockWidgetFloatable , False)
|
||||
|
||||
self.layer_tree_dock = QtAds.CDockWidget(self.tr("图层树"), self)
|
||||
self.layer_tree_dock = QtAds.CDockWidget(self.tr("面板"), self)
|
||||
|
||||
self.layer_tree_dock.setWidget(self.layer_tree)
|
||||
self.layer_tree_dock.setWidget(left_tool_box)
|
||||
left_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, self.layer_tree_dock, central_dock_area)
|
||||
self.left_arre = left_area
|
||||
self.follow_dock = QtAds.CDockWidget(self.tr("流程"))
|
||||
self.follow_box = QWidget(self)
|
||||
self.follow_dock.setWidget(self.follow_box)
|
||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, self.follow_dock, left_area)
|
||||
|
||||
self.result_dock = QtAds.CDockWidget(self.tr("结果"))
|
||||
self.result_box = ResultTable(self)
|
||||
@ -109,11 +113,9 @@ class MainWindow(QMainWindow):
|
||||
self.message_box = MessageBox(self, MessageBox.INFO)
|
||||
self.message_dock.setWidget(self.message_box)
|
||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, self.message_dock, bottom_area)
|
||||
# bottom_area.setCurrentDockWidget(self.result_dock)
|
||||
self.bottom_area = bottom_area
|
||||
|
||||
set_docker_fixed(self.layer_tree_dock)
|
||||
set_docker_fixed(self.follow_dock)
|
||||
set_docker_fixed(self.result_dock)
|
||||
set_docker_fixed(self.message_dock)
|
||||
|
||||
|
@ -60,10 +60,17 @@ class PluginDialog(QDialog):
|
||||
print(info)
|
||||
|
||||
if info is not None:
|
||||
try:
|
||||
dst = PluginLoader.copy_plugin_to_3rd(plugin_directory)
|
||||
except:
|
||||
QMessageBox.warning(self, 'Warning', 'Failed to copy plugin to 3rd party directory')
|
||||
return
|
||||
|
||||
info['module'] = os.path.basename(plugin_directory)
|
||||
info['enabled'] = True
|
||||
info['path'] = dst
|
||||
self.has_change = True
|
||||
self.plugins.append(info)
|
||||
|
||||
self.plugin_table.insertRow(self.plugin_table.rowCount())
|
||||
name_item = QTableWidgetItem(info['name'])
|
||||
module_item = QTableWidgetItem(info['module'])
|
||||
@ -72,11 +79,7 @@ class PluginDialog(QDialog):
|
||||
self.plugin_table.setItem(self.plugin_table.rowCount() - 1, 0, name_item)
|
||||
self.plugin_table.setItem(self.plugin_table.rowCount() - 1, 1, module_item)
|
||||
self.plugin_table.setItem(self.plugin_table.rowCount() - 1, 2, enabled_item)
|
||||
|
||||
dst = PluginLoader.copy_plugin_to_3rd(plugin_directory)
|
||||
if dst is not None:
|
||||
self.plugins[-1]['path'] = dst
|
||||
|
||||
self.plugins.append(info)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
@ -2,6 +2,7 @@ from PyQt5.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton, QVBoxL
|
||||
from PyQt5.QtGui import QIcon, QIntValidator
|
||||
from PyQt5.QtCore import Qt
|
||||
from rscder.utils.setting import Settings
|
||||
|
||||
class Create(QDialog):
|
||||
|
||||
def __init__(self, parent=None) -> None:
|
||||
|
@ -1,44 +1,72 @@
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import Qt,QModelIndex
|
||||
from PyQt5.QtCore import Qt,QModelIndex, pyqtSignal
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||
from PyQt5.QtWidgets import (QTableWidgetItem, QTableWidget, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||
|
||||
from rscder.utils.project import PairLayer
|
||||
from rscder.utils.project import PairLayer, ResultLayer
|
||||
|
||||
class ResultTable(QtWidgets.QWidget):
|
||||
|
||||
on_item_click = pyqtSignal(dict)
|
||||
on_item_changed = pyqtSignal(dict)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ResultTable, self).__init__(parent)
|
||||
self.tree_view = QTreeView(self)
|
||||
self.tree = QtWidgets.QTreeWidget(self)
|
||||
self.tree.setColumnCount(1)
|
||||
self.tree.setColumnWidth(0,150)
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.root=QTreeWidgetItem(self.tree)
|
||||
self.tree.setHeaderLabels(['图层'])
|
||||
self.root.setText(0,'Root')
|
||||
# self.tableview = QTableView(self)
|
||||
self.tablewidget = QTableWidget(self)
|
||||
self.tablewidget.setColumnCount(5)
|
||||
self.tablewidget.setRowCount(0)
|
||||
self.tablewidget.setHorizontalHeaderLabels(['序号', 'X', 'Y', '概率', '变化'])
|
||||
self.tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||
|
||||
child1=QTreeWidgetItem()
|
||||
child1.setText(0,'child1')
|
||||
child1.setCheckState(0,Qt.Checked)
|
||||
|
||||
self.root.addChild(child1)
|
||||
self.tree.expandAll()
|
||||
|
||||
self.tree.addTopLevelItem(self.root)
|
||||
|
||||
self.tree.clicked.connect(self.onClicked)
|
||||
self.tablewidget.cellDoubleClicked.connect(self.onDoubleClicked)
|
||||
self.tablewidget.cellClicked.connect(self.onClicked)
|
||||
self.tablewidget.cellChanged.connect(self.onChanged)
|
||||
|
||||
# self.tablewidget.setModel(self.tableview)
|
||||
# self.tableview
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.addWidget(self.tree)
|
||||
layout.addWidget(self.tablewidget)
|
||||
self.setLayout(layout)
|
||||
|
||||
def clear(self):
|
||||
pass
|
||||
|
||||
def onChanged(self, row, col):
|
||||
if col == 4:
|
||||
item_idx = row
|
||||
item_status = self.tablewidget.item(row, col).checkState() == Qt.Checked
|
||||
self.on_item_changed.emit({'idx':item_idx, 'status':item_status})
|
||||
|
||||
def onClicked(self, row, col):
|
||||
if col == 4:
|
||||
self.tablewidget.item(row, col).setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
|
||||
|
||||
def onDoubleClicked(self, row, col):
|
||||
x = self.tablewidget.item(row, 1).text()
|
||||
y = self.tablewidget.item(row, 2).text()
|
||||
self.on_item_click.emit({'x':x, 'y':y})
|
||||
|
||||
def set_data(self, data:ResultLayer):
|
||||
self.tablewidget.setRowCount(len(data.data))
|
||||
for i, d in enumerate(data.data):
|
||||
self.tablewidget.setItem(i, 0, QTableWidgetItem(str(i+1)))
|
||||
self.tablewidget.setItem(i, 1, QTableWidgetItem(str(d[0]))) # X
|
||||
self.tablewidget.setItem(i, 2, QTableWidgetItem(str(d[1]))) # Y
|
||||
self.tablewidget.setItem(i, 3, QTableWidgetItem(str(d[2]))) # 概率
|
||||
status_item = QTableWidgetItem('变化')
|
||||
if d[3] == 0:
|
||||
status_item.setBackground(Qt.green)
|
||||
status_item.setCheckState(Qt.Unchecked)
|
||||
elif d[3] == 1:
|
||||
status_item.setBackground(Qt.yellow)
|
||||
status_item.setCheckState(Qt.Checked)
|
||||
self.tablewidget.setItem(i, 4, status_item) # 变化
|
||||
self.tablewidget.resizeColumnsToContents()
|
||||
self.tablewidget.resizeRowsToContents()
|
||||
self.tablewidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
self.tablewidget.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
|
||||
|
||||
def onClicked(self,index):
|
||||
print(index.row())
|
||||
|
||||
def add_layer(self, layer:PairLayer):
|
||||
pass
|
||||
|
@ -12,5 +12,4 @@ with open(os.path.join(path, '..', 'res.qrc'), 'w') as f:
|
||||
f.write(f'</RCC>\n')
|
||||
|
||||
subprocess.run(['pyrcc5', 'res.qrc', '-o', 'rc.py'], cwd=os.path.join(path, '..'))
|
||||
|
||||
shutil.rmtree(icon_path)
|
12
rscder/utils/misc.py
Normal file
@ -0,0 +1,12 @@
|
||||
from functools import wraps
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
@wraps(cls)
|
||||
def inner(*args, **kargs):
|
||||
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls(*args, **kargs)
|
||||
cls.instance = _instance[cls]
|
||||
return _instance[cls]
|
||||
return inner
|
@ -8,22 +8,20 @@ from qgis.core import QgsRasterLayer, QgsLineSymbol, QgsSingleSymbolRenderer, Qg
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
from PyQt5.QtGui import QColor
|
||||
import yaml
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
from .misc import singleton
|
||||
|
||||
def inner(*args, **kargs):
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls(*args, **kargs)
|
||||
return _instance[cls]
|
||||
return inner
|
||||
def relative_path(path: str, root:str) -> str:
|
||||
return os.path.relpath(path, root)
|
||||
|
||||
@singleton
|
||||
class Project(QObject):
|
||||
|
||||
project_init = pyqtSignal(bool)
|
||||
|
||||
layer_load = pyqtSignal(str)
|
||||
|
||||
ABSOLUTE_MODE = 'absolute'
|
||||
RELATIVE_MODE = 'relative'
|
||||
|
||||
def __init__(self,
|
||||
parent=None):
|
||||
super().__init__(parent)
|
||||
@ -31,9 +29,9 @@ class Project(QObject):
|
||||
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] = []
|
||||
self.root = str(Path(Settings.General().root)/'default')
|
||||
self.file_mode = Project.ABSOLUTE_MODE
|
||||
self.layers:Dict[str, PairLayer] = dict()
|
||||
|
||||
def connect(self, pair_canvas,
|
||||
layer_tree,
|
||||
@ -46,18 +44,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 setup(self, file=None):
|
||||
def setup(self, path = None, name = 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 path is not None:
|
||||
self.root = path
|
||||
if name is None:
|
||||
self.file = str(Path(self.root)/'default.prj')
|
||||
|
||||
if not os.path.exists(self.root):
|
||||
os.makedirs(self.root, exist_ok=True)
|
||||
if not os.path.exists(self.file):
|
||||
with open(self.file, 'w') as f:
|
||||
pass
|
||||
@ -72,7 +69,7 @@ class Project(QObject):
|
||||
'max_memory': self.max_memory,
|
||||
'max_threads': self.max_threads,
|
||||
'root': self.root,
|
||||
'layers': [ layer.to_dict() for layer in self.layers.values() ],
|
||||
'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:
|
||||
@ -94,7 +91,7 @@ class Project(QObject):
|
||||
with open(self.file, 'r') as f:
|
||||
data = yaml.safe_load(f)
|
||||
if data is None:
|
||||
return
|
||||
return
|
||||
# data = yaml.safe_load(open(self.file, 'r'))
|
||||
self.cell_size = data['cell_size']
|
||||
self.max_memory = data['max_memory']
|
||||
@ -102,13 +99,14 @@ class Project(QObject):
|
||||
self.root = data['root']
|
||||
self.layers = dict()
|
||||
for layer in data['layers']:
|
||||
player = PairLayer.from_dict(layer)
|
||||
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)
|
||||
|
||||
def add_layer(self, pth1, pth2):
|
||||
self.root = str(Path(pth1).parent)
|
||||
# self.root = str(Path(pth1).parent)
|
||||
|
||||
player = PairLayer(pth1, pth2, self.cell_size)
|
||||
if player.check():
|
||||
# self.layers.append(player)
|
||||
@ -201,20 +199,41 @@ class GridLayer:
|
||||
def from_dict(data):
|
||||
return GridLayer()
|
||||
|
||||
class ResultLayer:
|
||||
|
||||
POINT = 0
|
||||
RASTER = 1
|
||||
|
||||
def __init__(self, layer_type):
|
||||
self.layer_type = layer_type
|
||||
self.data = []
|
||||
|
||||
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,
|
||||
}
|
||||
def to_dict(self, root = None):
|
||||
if root is None:
|
||||
return {
|
||||
'pth1': self.pth1,
|
||||
'pth2': self.pth2,
|
||||
'l1_name': self.l1_name,
|
||||
'l2_name': self.l2_name,
|
||||
'cell_size': self.cell_size,
|
||||
}
|
||||
else:
|
||||
return {
|
||||
'pth1': relative_path(self.pth1, root),
|
||||
'pth2': relative_path(self.pth2, root),
|
||||
'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'])
|
||||
def from_dict(data, root = None):
|
||||
if root is None:
|
||||
layer = PairLayer(data['pth1'], data['pth2'], data['cell_size'])
|
||||
else:
|
||||
layer = PairLayer(os.path.join(root, data['pth1']), os.path.join(root, data['pth2']), data['cell_size'])
|
||||
layer.l1_name = data['l1_name']
|
||||
layer.l2_name = data['l2_name']
|
||||
# layer.grid_layer = GridLayer.from_dict(data['grid_layer'])
|
||||
@ -232,8 +251,11 @@ class PairLayer:
|
||||
# self.grid_layer = GridLayer(cell_size)
|
||||
|
||||
self.msg = ''
|
||||
self.checked = False
|
||||
|
||||
def check(self):
|
||||
if self.checked:
|
||||
return self.checked
|
||||
if not os.path.exists(self.pth1):
|
||||
self.msg = '图层1不存在'
|
||||
return False
|
||||
@ -258,5 +280,5 @@ class PairLayer:
|
||||
|
||||
self.l1 = QgsRasterLayer(self.pth1, self.l1_name)
|
||||
self.l2 = QgsRasterLayer(self.pth2, self.l2_name)
|
||||
|
||||
self.checked = True
|
||||
return True
|
@ -3,7 +3,7 @@ import os
|
||||
from typing import Tuple
|
||||
from PyQt5.QtCore import QSettings
|
||||
from rscder.utils.license import LicenseHelper
|
||||
|
||||
import yaml
|
||||
class Settings(QSettings):
|
||||
|
||||
def __init__(self, key):
|
||||
@ -22,20 +22,25 @@ class Settings(QSettings):
|
||||
|
||||
@property
|
||||
def root(self):
|
||||
return './3rd'
|
||||
_r = './3rd'
|
||||
if not os.path.exists(_r):
|
||||
os.makedirs(_r)
|
||||
return _r
|
||||
|
||||
@property
|
||||
def plugins(self):
|
||||
with Settings(Settings.Plugin.PRE) as s:
|
||||
pl = s.value('plugins', [])
|
||||
if pl is None:
|
||||
return []
|
||||
return pl
|
||||
plugins_file = os.path.join(self.root, 'plugins.yaml')
|
||||
if not os.path.exists(plugins_file):
|
||||
with open(plugins_file, 'w') as f:
|
||||
yaml.safe_dump([], f)
|
||||
with open(plugins_file, 'r') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
@plugins.setter
|
||||
def plugins(self, value):
|
||||
with Settings(Settings.Plugin.PRE) as s:
|
||||
s.setValue('plugins', value)
|
||||
|
||||
plugins_file = os.path.join(self.root, 'plugins.yaml')
|
||||
with open(plugins_file, 'w') as f:
|
||||
yaml.safe_dump(value, f)
|
||||
|
||||
class Project:
|
||||
|
||||
@ -85,6 +90,16 @@ class Settings(QSettings):
|
||||
with Settings(Settings.General.PRE) as s:
|
||||
s.setValue('size', value)
|
||||
|
||||
@property
|
||||
def last_path(self):
|
||||
with Settings(Settings.General.PRE) as s:
|
||||
return s.value('last_path', '')
|
||||
|
||||
@last_path.setter
|
||||
def last_path(self, value):
|
||||
with Settings(Settings.General.PRE) as s:
|
||||
s.setValue('last_path', value)
|
||||
|
||||
@property
|
||||
def end_date(self):
|
||||
if not os.path.exists('lic/license.lic'):
|
||||
|
15
setup.py
Normal file
@ -0,0 +1,15 @@
|
||||
from distutils.core import setup
|
||||
import shutil
|
||||
from Cython.Build import cythonize
|
||||
import sys
|
||||
import os
|
||||
|
||||
for plugin in os.listdir('plugins'):
|
||||
if os.path.isdir(os.path.join('plugins', plugin)):
|
||||
setup(
|
||||
name = plugin,
|
||||
ext_modules = cythonize(os.path.join('plugins', plugin, '*.py'), exclude=[ f'plugins/{plugin}/__init__.py']),
|
||||
script_args = ['build_ext', '-b', 'plugin-build'],
|
||||
)
|
||||
shutil.copy(os.path.join('plugins', plugin, '__init__.py'), os.path.join('plugin-build', plugin, '__init__.py'))
|
||||
|
9
未命名.prj
@ -1,12 +1,7 @@
|
||||
cell_size: &id001
|
||||
cell_size:
|
||||
- 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
|
||||
layers: []
|
||||
max_memory: 100
|
||||
max_threads: 4
|
||||
results: []
|
||||
|