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 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):
|
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):
|
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 PyQt5.QtWidgets import QAction, QActionGroup, QLabel, QFileDialog
|
||||||
from rscder.gui.project import Create
|
from rscder.gui.project import Create
|
||||||
from rscder.utils.project import Project
|
from rscder.utils.project import Project
|
||||||
|
from rscder.utils.misc import singleton
|
||||||
from rscder.gui.plugins import PluginDialog
|
from rscder.gui.plugins import PluginDialog
|
||||||
|
from rscder.utils.setting import Settings
|
||||||
|
|
||||||
|
def get_action_manager() -> 'ActionManager':
|
||||||
|
return ActionManager()
|
||||||
|
|
||||||
|
@singleton
|
||||||
class ActionManager(QtCore.QObject):
|
class ActionManager(QtCore.QObject):
|
||||||
|
|
||||||
|
instance = None
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
double_map,
|
double_map,
|
||||||
layer_tree,
|
layer_tree,
|
||||||
@ -137,147 +146,9 @@ class ActionManager(QtCore.QObject):
|
|||||||
plugin_list.triggered.connect(self.plugin_list)
|
plugin_list.triggered.connect(self.plugin_list)
|
||||||
|
|
||||||
self.plugin_menu.addAction(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('Menu init finished')
|
||||||
self.message_box.info(self.actions.keys())
|
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
|
Enabled actions
|
||||||
@ -299,6 +170,11 @@ class ActionManager(QtCore.QObject):
|
|||||||
self.double_map.corr_changed.connect(corr_widget.setText)
|
self.double_map.corr_changed.connect(corr_widget.setText)
|
||||||
self.double_map.scale_changed.connect(scale_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):
|
def plugin_list(self):
|
||||||
dialog = PluginDialog(self.w_parent)
|
dialog = PluginDialog(self.w_parent)
|
||||||
dialog.show()
|
dialog.show()
|
||||||
@ -365,7 +241,7 @@ class ActionManager(QtCore.QObject):
|
|||||||
self.action_groups[group] = QActionGroup(self.w_parent)
|
self.action_groups[group] = QActionGroup(self.w_parent)
|
||||||
self.action_groups[group].setExclusive(True)
|
self.action_groups[group].setExclusive(True)
|
||||||
self.action_groups[group].addAction(action)
|
self.action_groups[group].addAction(action)
|
||||||
self.action_group_actions[group] = action
|
|
||||||
return action
|
return action
|
||||||
|
|
||||||
def get_action(self, action_name, group_name=None):
|
def get_action(self, action_name, group_name=None):
|
||||||
@ -375,10 +251,10 @@ class ActionManager(QtCore.QObject):
|
|||||||
if group_name is None:
|
if group_name is None:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if group_name not in self.action_group_actions:
|
if group_name not in self.action_groups:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
group = self.action_group_actions[group_name]
|
group = self.action_groups[group_name]
|
||||||
for action in group.actions():
|
for action in group.actions():
|
||||||
if action.text() == action_name:
|
if action.text() == action_name:
|
||||||
return action
|
return action
|
||||||
@ -387,11 +263,5 @@ class ActionManager(QtCore.QObject):
|
|||||||
def get_action_group(self, group_name):
|
def get_action_group(self, group_name):
|
||||||
return self.action_groups[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):
|
def get_actions(self):
|
||||||
return self.actions
|
return self.actions
|
@ -3,6 +3,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||||||
from PyQt5.QtCore import Qt,QModelIndex
|
from PyQt5.QtCore import Qt,QModelIndex
|
||||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||||
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
|
from PyQt5.QtWidgets import (QTreeView, QTreeWidgetItem, QAbstractItemView, QHeaderView, QStyleFactory)
|
||||||
|
from rscder.gui.actions import get_action_manager
|
||||||
|
|
||||||
from rscder.utils.project import PairLayer, Project
|
from rscder.utils.project import PairLayer, Project
|
||||||
|
|
||||||
@ -10,8 +11,9 @@ class LayerTree(QtWidgets.QWidget):
|
|||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.tree_view = QTreeView(self)
|
# self.tree_view = QTreeView(self)
|
||||||
self.tree = QtWidgets.QTreeWidget(self)
|
self.tree = QtWidgets.QTreeWidget(self)
|
||||||
|
|
||||||
self.tree.setColumnCount(1)
|
self.tree.setColumnCount(1)
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
self.customContextMenuRequested.connect(self.right_menu_show)
|
self.customContextMenuRequested.connect(self.right_menu_show)
|
||||||
@ -38,6 +40,13 @@ class LayerTree(QtWidgets.QWidget):
|
|||||||
|
|
||||||
def onClicked(self,index):
|
def onClicked(self,index):
|
||||||
print(index.row())
|
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):
|
def add_layer(self, layer:str):
|
||||||
layer:PairLayer = Project().layers[layer]
|
layer:PairLayer = Project().layers[layer]
|
||||||
@ -61,10 +70,17 @@ class LayerTree(QtWidgets.QWidget):
|
|||||||
def right_menu_show(self, position):
|
def right_menu_show(self, position):
|
||||||
rightMenu = QtWidgets.QMenu(self)
|
rightMenu = QtWidgets.QMenu(self)
|
||||||
# QAction = QtWidgets.QAction(self.menuBar1)
|
# QAction = QtWidgets.QAction(self.menuBar1)
|
||||||
self.actionreboot = QtWidgets.QAction('zhangji')
|
item = self.tree.currentItem()
|
||||||
self.actionreboot.setObjectName("actionreboot")
|
action_manager = get_action_manager()
|
||||||
self.actionreboot.setText('aaa')
|
actions = []
|
||||||
rightMenu.addAction(self.actionreboot)
|
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))
|
rightMenu.exec_(self.mapToGlobal(position))
|
||||||
|
|
||||||
|
@ -69,6 +69,8 @@ class License(QtWidgets.QDialog):
|
|||||||
if not os.path.exists(pth):
|
if not os.path.exists(pth):
|
||||||
QtWidgets.QMessageBox.warning(self, "Warning", "The selected file does not exist.")
|
QtWidgets.QMessageBox.warning(self, "Warning", "The selected file does not exist.")
|
||||||
else:
|
else:
|
||||||
|
if not os.path.exists('lic'):
|
||||||
|
os.mkdir('lic')
|
||||||
shutil.copy(pth, os.path.join("lic", "license.lic"))
|
shutil.copy(pth, os.path.join("lic", "license.lic"))
|
||||||
self.accept()
|
self.accept()
|
||||||
self.close()
|
self.close()
|
@ -1,5 +1,5 @@
|
|||||||
import pdb
|
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.QtCore import Qt, QSize
|
||||||
from PyQt5.QtGui import QIcon
|
from PyQt5.QtGui import QIcon
|
||||||
from PyQt5 import QtGui
|
from PyQt5 import QtGui
|
||||||
@ -63,11 +63,10 @@ class MainWindow(QMainWindow):
|
|||||||
self.toolbar = self.addToolBar('Toolbar')
|
self.toolbar = self.addToolBar('Toolbar')
|
||||||
self.toolbar.setMovable(False)
|
self.toolbar.setMovable(False)
|
||||||
self.toolbar.setFloatable(False)
|
self.toolbar.setFloatable(False)
|
||||||
self.toolbar.setIconSize(QSize(16, 16))
|
self.toolbar.setIconSize(QSize(32, 32))
|
||||||
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||||
self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
|
self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||||
self.toolbar.setLayoutDirection(Qt.LeftToRight)
|
self.toolbar.setLayoutDirection(Qt.LeftToRight)
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def set_pannels(self):
|
def set_pannels(self):
|
||||||
@ -82,8 +81,17 @@ class MainWindow(QMainWindow):
|
|||||||
central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
|
central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
|
||||||
|
|
||||||
self.double_map.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.double_map.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
|
|
||||||
self.layer_tree = LayerTree(self)
|
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)
|
# self.layer_tree.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
|
|
||||||
def set_docker_fixed(docker):
|
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.DockWidgetMovable , False)
|
||||||
docker.setFeature(QtAds.ads.CDockWidget.DockWidgetFeature.DockWidgetFloatable , 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)
|
left_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, self.layer_tree_dock, central_dock_area)
|
||||||
self.left_arre = left_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_dock = QtAds.CDockWidget(self.tr("结果"))
|
||||||
self.result_box = ResultTable(self)
|
self.result_box = ResultTable(self)
|
||||||
@ -109,11 +113,9 @@ class MainWindow(QMainWindow):
|
|||||||
self.message_box = MessageBox(self, MessageBox.INFO)
|
self.message_box = MessageBox(self, MessageBox.INFO)
|
||||||
self.message_dock.setWidget(self.message_box)
|
self.message_dock.setWidget(self.message_box)
|
||||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, self.message_dock, bottom_area)
|
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, self.message_dock, bottom_area)
|
||||||
# bottom_area.setCurrentDockWidget(self.result_dock)
|
|
||||||
self.bottom_area = bottom_area
|
self.bottom_area = bottom_area
|
||||||
|
|
||||||
set_docker_fixed(self.layer_tree_dock)
|
set_docker_fixed(self.layer_tree_dock)
|
||||||
set_docker_fixed(self.follow_dock)
|
|
||||||
set_docker_fixed(self.result_dock)
|
set_docker_fixed(self.result_dock)
|
||||||
set_docker_fixed(self.message_dock)
|
set_docker_fixed(self.message_dock)
|
||||||
|
|
||||||
|
@ -60,10 +60,17 @@ class PluginDialog(QDialog):
|
|||||||
print(info)
|
print(info)
|
||||||
|
|
||||||
if info is not None:
|
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['module'] = os.path.basename(plugin_directory)
|
||||||
info['enabled'] = True
|
info['enabled'] = True
|
||||||
|
info['path'] = dst
|
||||||
self.has_change = True
|
self.has_change = True
|
||||||
self.plugins.append(info)
|
|
||||||
self.plugin_table.insertRow(self.plugin_table.rowCount())
|
self.plugin_table.insertRow(self.plugin_table.rowCount())
|
||||||
name_item = QTableWidgetItem(info['name'])
|
name_item = QTableWidgetItem(info['name'])
|
||||||
module_item = QTableWidgetItem(info['module'])
|
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, 0, name_item)
|
||||||
self.plugin_table.setItem(self.plugin_table.rowCount() - 1, 1, module_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)
|
self.plugin_table.setItem(self.plugin_table.rowCount() - 1, 2, enabled_item)
|
||||||
|
self.plugins.append(info)
|
||||||
dst = PluginLoader.copy_plugin_to_3rd(plugin_directory)
|
|
||||||
if dst is not None:
|
|
||||||
self.plugins[-1]['path'] = dst
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ from PyQt5.QtWidgets import QDialog, QFileDialog, QLineEdit, QPushButton, QVBoxL
|
|||||||
from PyQt5.QtGui import QIcon, QIntValidator
|
from PyQt5.QtGui import QIcon, QIntValidator
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from rscder.utils.setting import Settings
|
from rscder.utils.setting import Settings
|
||||||
|
|
||||||
class Create(QDialog):
|
class Create(QDialog):
|
||||||
|
|
||||||
def __init__(self, parent=None) -> None:
|
def __init__(self, parent=None) -> None:
|
||||||
|
@ -1,44 +1,72 @@
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
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.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):
|
class ResultTable(QtWidgets.QWidget):
|
||||||
|
|
||||||
|
on_item_click = pyqtSignal(dict)
|
||||||
|
on_item_changed = pyqtSignal(dict)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(ResultTable, self).__init__(parent)
|
super(ResultTable, self).__init__(parent)
|
||||||
self.tree_view = QTreeView(self)
|
# self.tableview = QTableView(self)
|
||||||
self.tree = QtWidgets.QTreeWidget(self)
|
self.tablewidget = QTableWidget(self)
|
||||||
self.tree.setColumnCount(1)
|
self.tablewidget.setColumnCount(5)
|
||||||
self.tree.setColumnWidth(0,150)
|
self.tablewidget.setRowCount(0)
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.tablewidget.setHorizontalHeaderLabels(['序号', 'X', 'Y', '概率', '变化'])
|
||||||
self.root=QTreeWidgetItem(self.tree)
|
self.tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||||
self.tree.setHeaderLabels(['图层'])
|
|
||||||
self.root.setText(0,'Root')
|
|
||||||
|
|
||||||
child1=QTreeWidgetItem()
|
self.tablewidget.cellDoubleClicked.connect(self.onDoubleClicked)
|
||||||
child1.setText(0,'child1')
|
self.tablewidget.cellClicked.connect(self.onClicked)
|
||||||
child1.setCheckState(0,Qt.Checked)
|
self.tablewidget.cellChanged.connect(self.onChanged)
|
||||||
|
|
||||||
self.root.addChild(child1)
|
|
||||||
self.tree.expandAll()
|
|
||||||
|
|
||||||
self.tree.addTopLevelItem(self.root)
|
|
||||||
|
|
||||||
self.tree.clicked.connect(self.onClicked)
|
|
||||||
|
|
||||||
|
# self.tablewidget.setModel(self.tableview)
|
||||||
|
# self.tableview
|
||||||
layout = QtWidgets.QVBoxLayout(self)
|
layout = QtWidgets.QVBoxLayout(self)
|
||||||
layout.addWidget(self.tree)
|
layout.addWidget(self.tablewidget)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def onClicked(self,index):
|
def onChanged(self, row, col):
|
||||||
print(index.row())
|
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 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')
|
f.write(f'</RCC>\n')
|
||||||
|
|
||||||
subprocess.run(['pyrcc5', 'res.qrc', '-o', 'rc.py'], cwd=os.path.join(path, '..'))
|
subprocess.run(['pyrcc5', 'res.qrc', '-o', 'rc.py'], cwd=os.path.join(path, '..'))
|
||||||
|
|
||||||
shutil.rmtree(icon_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.QtCore import QObject, pyqtSignal
|
||||||
from PyQt5.QtGui import QColor
|
from PyQt5.QtGui import QColor
|
||||||
import yaml
|
import yaml
|
||||||
def singleton(cls):
|
from .misc import singleton
|
||||||
_instance = {}
|
|
||||||
|
|
||||||
def inner(*args, **kargs):
|
def relative_path(path: str, root:str) -> str:
|
||||||
if cls not in _instance:
|
return os.path.relpath(path, root)
|
||||||
_instance[cls] = cls(*args, **kargs)
|
|
||||||
return _instance[cls]
|
|
||||||
return inner
|
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class Project(QObject):
|
class Project(QObject):
|
||||||
|
|
||||||
project_init = pyqtSignal(bool)
|
project_init = pyqtSignal(bool)
|
||||||
|
|
||||||
layer_load = pyqtSignal(str)
|
layer_load = pyqtSignal(str)
|
||||||
|
|
||||||
|
ABSOLUTE_MODE = 'absolute'
|
||||||
|
RELATIVE_MODE = 'relative'
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
parent=None):
|
parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@ -31,9 +29,9 @@ class Project(QObject):
|
|||||||
self.cell_size = Settings.Project().cell_size
|
self.cell_size = Settings.Project().cell_size
|
||||||
self.max_memory = Settings.Project().max_memory
|
self.max_memory = Settings.Project().max_memory
|
||||||
self.max_threads = Settings.Project().max_threads
|
self.max_threads = Settings.Project().max_threads
|
||||||
self.root = Settings.General().root
|
self.root = str(Path(Settings.General().root)/'default')
|
||||||
self.layers:Dict = dict()
|
self.file_mode = Project.ABSOLUTE_MODE
|
||||||
# self.layers:List[PairLayer] = []
|
self.layers:Dict[str, PairLayer] = dict()
|
||||||
|
|
||||||
def connect(self, pair_canvas,
|
def connect(self, pair_canvas,
|
||||||
layer_tree,
|
layer_tree,
|
||||||
@ -48,16 +46,15 @@ class Project(QObject):
|
|||||||
self.layer_load.connect(pair_canvas.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, path = None, name = None):
|
||||||
def setup(self, file=None):
|
|
||||||
self.is_init = True
|
self.is_init = True
|
||||||
self.file = file
|
if path is not None:
|
||||||
if file is None:
|
self.root = path
|
||||||
self.file = Path(self.root)/'project'/'untitled.prj'
|
if name is None:
|
||||||
self.root = str(Path(self.file).parent)
|
self.file = str(Path(self.root)/'default.prj')
|
||||||
dir_name = os.path.dirname(self.file)
|
|
||||||
if not os.path.exists(dir_name):
|
if not os.path.exists(self.root):
|
||||||
os.makedirs(dir_name, exist_ok=True)
|
os.makedirs(self.root, exist_ok=True)
|
||||||
if not os.path.exists(self.file):
|
if not os.path.exists(self.file):
|
||||||
with open(self.file, 'w') as f:
|
with open(self.file, 'w') as f:
|
||||||
pass
|
pass
|
||||||
@ -72,7 +69,7 @@ class Project(QObject):
|
|||||||
'max_memory': self.max_memory,
|
'max_memory': self.max_memory,
|
||||||
'max_threads': self.max_threads,
|
'max_threads': self.max_threads,
|
||||||
'root': self.root,
|
'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': []
|
'results': []
|
||||||
}
|
}
|
||||||
with open(self.file, 'w') as f:
|
with open(self.file, 'w') as f:
|
||||||
@ -102,13 +99,14 @@ class Project(QObject):
|
|||||||
self.root = data['root']
|
self.root = data['root']
|
||||||
self.layers = dict()
|
self.layers = dict()
|
||||||
for layer in data['layers']:
|
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():
|
if player.check():
|
||||||
self.layers[player.id] = player
|
self.layers[player.id] = player
|
||||||
self.layer_load.emit(player.id)
|
self.layer_load.emit(player.id)
|
||||||
|
|
||||||
def add_layer(self, pth1, pth2):
|
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)
|
player = PairLayer(pth1, pth2, self.cell_size)
|
||||||
if player.check():
|
if player.check():
|
||||||
# self.layers.append(player)
|
# self.layers.append(player)
|
||||||
@ -201,20 +199,41 @@ class GridLayer:
|
|||||||
def from_dict(data):
|
def from_dict(data):
|
||||||
return GridLayer()
|
return GridLayer()
|
||||||
|
|
||||||
|
class ResultLayer:
|
||||||
|
|
||||||
|
POINT = 0
|
||||||
|
RASTER = 1
|
||||||
|
|
||||||
|
def __init__(self, layer_type):
|
||||||
|
self.layer_type = layer_type
|
||||||
|
self.data = []
|
||||||
|
|
||||||
class PairLayer:
|
class PairLayer:
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self, root = None):
|
||||||
return {
|
if root is None:
|
||||||
'pth1': self.pth1,
|
return {
|
||||||
'pth2': self.pth2,
|
'pth1': self.pth1,
|
||||||
'l1_name': self.l1_name,
|
'pth2': self.pth2,
|
||||||
'l2_name': self.l2_name,
|
'l1_name': self.l1_name,
|
||||||
'cell_size': self.cell_size,
|
'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
|
@staticmethod
|
||||||
def from_dict(data):
|
def from_dict(data, root = None):
|
||||||
layer = PairLayer(data['pth1'], data['pth2'], data['cell_size'])
|
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.l1_name = data['l1_name']
|
||||||
layer.l2_name = data['l2_name']
|
layer.l2_name = data['l2_name']
|
||||||
# layer.grid_layer = GridLayer.from_dict(data['grid_layer'])
|
# layer.grid_layer = GridLayer.from_dict(data['grid_layer'])
|
||||||
@ -232,8 +251,11 @@ class PairLayer:
|
|||||||
# self.grid_layer = GridLayer(cell_size)
|
# self.grid_layer = GridLayer(cell_size)
|
||||||
|
|
||||||
self.msg = ''
|
self.msg = ''
|
||||||
|
self.checked = False
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
|
if self.checked:
|
||||||
|
return self.checked
|
||||||
if not os.path.exists(self.pth1):
|
if not os.path.exists(self.pth1):
|
||||||
self.msg = '图层1不存在'
|
self.msg = '图层1不存在'
|
||||||
return False
|
return False
|
||||||
@ -258,5 +280,5 @@ class PairLayer:
|
|||||||
|
|
||||||
self.l1 = QgsRasterLayer(self.pth1, self.l1_name)
|
self.l1 = QgsRasterLayer(self.pth1, self.l1_name)
|
||||||
self.l2 = QgsRasterLayer(self.pth2, self.l2_name)
|
self.l2 = QgsRasterLayer(self.pth2, self.l2_name)
|
||||||
|
self.checked = True
|
||||||
return True
|
return True
|
@ -3,7 +3,7 @@ import os
|
|||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
from rscder.utils.license import LicenseHelper
|
from rscder.utils.license import LicenseHelper
|
||||||
|
import yaml
|
||||||
class Settings(QSettings):
|
class Settings(QSettings):
|
||||||
|
|
||||||
def __init__(self, key):
|
def __init__(self, key):
|
||||||
@ -22,20 +22,25 @@ class Settings(QSettings):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def root(self):
|
def root(self):
|
||||||
return './3rd'
|
_r = './3rd'
|
||||||
|
if not os.path.exists(_r):
|
||||||
|
os.makedirs(_r)
|
||||||
|
return _r
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def plugins(self):
|
def plugins(self):
|
||||||
with Settings(Settings.Plugin.PRE) as s:
|
plugins_file = os.path.join(self.root, 'plugins.yaml')
|
||||||
pl = s.value('plugins', [])
|
if not os.path.exists(plugins_file):
|
||||||
if pl is None:
|
with open(plugins_file, 'w') as f:
|
||||||
return []
|
yaml.safe_dump([], f)
|
||||||
return pl
|
with open(plugins_file, 'r') as f:
|
||||||
|
return yaml.safe_load(f)
|
||||||
|
|
||||||
@plugins.setter
|
@plugins.setter
|
||||||
def plugins(self, value):
|
def plugins(self, value):
|
||||||
with Settings(Settings.Plugin.PRE) as s:
|
plugins_file = os.path.join(self.root, 'plugins.yaml')
|
||||||
s.setValue('plugins', value)
|
with open(plugins_file, 'w') as f:
|
||||||
|
yaml.safe_dump(value, f)
|
||||||
|
|
||||||
class Project:
|
class Project:
|
||||||
|
|
||||||
@ -85,6 +90,16 @@ class Settings(QSettings):
|
|||||||
with Settings(Settings.General.PRE) as s:
|
with Settings(Settings.General.PRE) as s:
|
||||||
s.setValue('size', value)
|
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
|
@property
|
||||||
def end_date(self):
|
def end_date(self):
|
||||||
if not os.path.exists('lic/license.lic'):
|
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
|
||||||
- 100
|
- 100
|
||||||
layers:
|
layers: []
|
||||||
- cell_size: *id001
|
|
||||||
l1_name: p122_r032_l5_20090915.tif
|
|
||||||
l2_name: p122_r032_l8_20170804.tif
|
|
||||||
pth1: F:/LZY_DATA/p122r032/p122_r032_l5_20090915.tif
|
|
||||||
pth2: F:/LZY_DATA/p122r032/p122_r032_l8_20170804.tif
|
|
||||||
max_memory: 100
|
max_memory: 100
|
||||||
max_threads: 4
|
max_threads: 4
|
||||||
results: []
|
results: []
|
||||||
|