diff --git a/README.md b/README.md index e582639e3bf69a2e7d851cbd40634ad7de4e8e0e..8bf223286d49a76d34378843647143ad9191f23a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,35 @@ -CSPOV -===== +SIFT +==== -TODO +Satellite Information Familiarization Tool (SIFT) was designed by the SSEC to +support scientists during forecaster training events. It provides a graphical +interface for visualization and basic analysis of geostationary satellite data. -[GDAL reprojection moved here](gdal-reprojection) \ No newline at end of file +The Project Wiki and Git repository can be accessed at +https://gitlab.ssec.wisc.edu/rayg/CSPOV/wikis/home. + +SIFT is built on open source technologies like Python, OpenGL, and PyQt4. It +can be run from Mac, Windows, and Linux. + +Data Access +----------- + +Currently SIFT requires input data to be preprocessed. In the future this +process will be included internally in the SIFT GUI. For now input data files +are preprocessed by the development team at the SSEC. Please contact +Jordan Gerth, Ray Garcia, or David Hoese to get access to this early release +data set. + +Run from Windows +---------------- + +When installed via the `setup.exe` installer, SIFT can be run from the "SIFT" +shortcut in the start menu. By default SIFT stores temporary and cache files +in a "Workspace" located at the user's "Documents/sift_workspace". + +Installing and Running from Linux or Mac +---------------------------------------- + +Currently running SIFT on Linux or Mac can be accomplished by installing the +python software in an Anaconda environment on those platforms. For more +details see the Wiki. diff --git a/conda-recipe/cspov/meta.yaml b/conda-recipe/cspov/meta.yaml index 888bf380c9510c205c0ca7d62efd8709b826cc2b..6e305c14d483f43b5c2fe868c76aae69fc8e8bda 100644 --- a/conda-recipe/cspov/meta.yaml +++ b/conda-recipe/cspov/meta.yaml @@ -1,6 +1,6 @@ package: name: cspov - version: "0.7.1" + version: "0.7.2" source: path: ../../py diff --git a/conda-recipe/vispy/meta.yaml b/conda-recipe/vispy/meta.yaml index 670337622c0a22979c3d61aec539f8d8e2be29b3..f0d0f4df972ecbca2e6f21e2d66f388ae919958b 100644 --- a/conda-recipe/vispy/meta.yaml +++ b/conda-recipe/vispy/meta.yaml @@ -4,12 +4,12 @@ package: source: git_url: https://github.com/vispy/vispy.git - git_rev: 65edc3245aaf1e2e55d60d9c3c4abb68564b5972 + git_rev: 236fa011ef5d57fecb3ab96a1d97bf8e1b08f2b7 # patches: # List any patch files here # - fix.patch -# build: +build: # noarch_python: True # preserve_egg_dir: True # entry_points: @@ -23,7 +23,7 @@ source: # If this is a new build for the same version, increment the build # number. If you do not include this key, it defaults to 0. - # number: 1 + number: 1 requirements: build: diff --git a/py/__init__.py b/py/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/py/cspov/__main__.py b/py/cspov/__main__.py index 52457a917d3fd17e3c2fa8bc677c27b6ef414a04..47a0328d5024e87d7652fc02de81e6b5874b99f6 100644 --- a/py/cspov/__main__.py +++ b/py/cspov/__main__.py @@ -484,7 +484,14 @@ class Main(QtGui.QMainWindow): self.layerSetsManager = LayerSetsManager(self.ui.layerSetTabs, self.ui.layerInfoContents, self.document) self.behaviorLayersList = self.layerSetsManager.getLayerStackListViewModel() - def update_probe_point(uuid, xy_pos): + def update_probe_point(uuid=None, xy_pos=None): + if uuid is None: + uuid = self.document.current_visible_layer + if xy_pos is None: + xy_pos = self.scene_manager.point_probe_location("default_probe_name") + if xy_pos is None: + return + lon, lat = DEFAULT_PROJ_OBJ(xy_pos[0], xy_pos[1], inverse=True) lon_str = "{:.02f} {}".format(abs(lon), "W" if lon < 0 else "E") lat_str = "{:.02f} {}".format(abs(lat), "S" if lat < 0 else "N") @@ -499,6 +506,21 @@ class Main(QtGui.QMainWindow): self.ui.cursorProbeText.setText("Probe Value: {} ".format(data_str)) self.scene_manager.newProbePoint.connect(update_probe_point) self.scene_manager.newProbePoint.connect(self.document.update_equalizer_values) + # FIXME: These were added as a simple fix to update the proble value on layer changes, but this should really + # have its own manager-like object + def _blackhole(*args, **kwargs): + return update_probe_point() + self.document.didChangeLayerVisibility.connect(_blackhole) + self.document.didAddLayer.connect(_blackhole) + self.document.didRemoveLayers.connect(_blackhole) + self.document.didReorderLayers.connect(_blackhole) + if False: + # XXX: Disable the below line if updating during animation is too much work + # self.scene_manager.didChangeFrame.connect(lambda frame_info: update_probe_point(uuid=frame_info[-1])) + pass + else: + # XXX: Disable the below line if updating the probe value during animation isn't a performance problem + self.scene_manager.didChangeFrame.connect(lambda frame_info: self.ui.cursorProbeText.setText("Probe Value: <animating>")) def update_probe_polygon(uuid, points, layerlist=self.behaviorLayersList): top_uuids = list(self.document.current_visible_layers(2)) @@ -625,11 +647,11 @@ class Main(QtGui.QMainWindow): prev_time.triggered.connect(prev_slot) # self.ui.animBack.clicked.connect(prev_slot) - focus_prev_band = QtGui.QAction("Previous Band", self) + focus_prev_band = QtGui.QAction("Next Band", self) focus_prev_band.setShortcut(QtCore.Qt.Key_Up) focus_prev_band.triggered.connect(partial(self.next_last_band, direction=-1)) - focus_next_band = QtGui.QAction("Next Band", self) + focus_next_band = QtGui.QAction("Previous Band", self) focus_next_band.setShortcut(QtCore.Qt.Key_Down) focus_next_band.triggered.connect(partial(self.next_last_band, direction=1)) @@ -715,9 +737,14 @@ class Main(QtGui.QMainWindow): def main(): + if "win" in sys.platform: + default_workspace = os.path.expanduser(os.path.join("~", "Documents", "sift_workspace")) + else: + default_workspace = os.path.expanduser(os.path.join("~", "sift_workspace")) + import argparse parser = argparse.ArgumentParser(description="Run CSPOV") - parser.add_argument("-w", "--workspace", default='.', + parser.add_argument("-w", "--workspace", default=default_workspace, help="Specify workspace base directory") parser.add_argument("-s", "--space", default=256, type=int, help="Specify max amount of data to hold in workspace in Gigabytes") @@ -738,6 +765,10 @@ def main(): logging.getLogger().setLevel(level) # logging.getLogger('vispy').setLevel(level) + if not os.path.exists(args.workspace): + LOG.info("Creating SIFT Workspace: %s", args.workspace) + os.makedirs(args.workspace) + app.create() # app = QApplication(sys.argv) window = Main( diff --git a/py/cspov/ui/pov_main.ui b/py/cspov/ui/pov_main.ui index 6d08cc2373119a3bb45661f1776b75810971a5f5..26f828831b0f35aa86196a1f0e9cbeab954700d9 100644 --- a/py/cspov/ui/pov_main.ui +++ b/py/cspov/ui/pov_main.ui @@ -14,7 +14,7 @@ <bool>true</bool> </property> <property name="windowTitle"> - <string>SIFT Beta 0.7.1</string> + <string>SIFT Beta 0.7.2</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout_2"> diff --git a/py/cspov/ui/pov_main_ui.py b/py/cspov/ui/pov_main_ui.py index 9adf2c9afb049a8568e29393838dd30879e4bd63..4dd00df45a4cd4625cf17efe12f748064c76a722 100644 --- a/py/cspov/ui/pov_main_ui.py +++ b/py/cspov/ui/pov_main_ui.py @@ -2,7 +2,8 @@ # Form implementation generated from reading ui file 'pov_main.ui' # -# Created by: PyQt4 UI code generator 4.11.4 +# Created: Wed Dec 9 13:58:01 2015 +# by: PyQt4 UI code generator 4.10.4 # # WARNING! All changes made in this file will be lost! @@ -268,7 +269,7 @@ class Ui_MainWindow(object): QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(_translate("MainWindow", "SIFT Beta 0.7.1", None)) + MainWindow.setWindowTitle(_translate("MainWindow", "SIFT Beta 0.7.2", None)) self.panZoomToolButton.setToolTip(_translate("MainWindow", "Pan/Zoom Tool", None)) self.panZoomToolButton.setStatusTip(_translate("MainWindow", "Left mouse click and drag pans the scene", None)) self.panZoomToolButton.setText(_translate("MainWindow", "Pan/Zoom", None)) diff --git a/py/cspov/view/SceneGraphManager.py b/py/cspov/view/SceneGraphManager.py index 6b26969ede58ff13a016573b9f6dbd85f9f44ca3..d1507a327550d2c5f2edd8fcbeeeb9f49a319dea 100644 --- a/py/cspov/view/SceneGraphManager.py +++ b/py/cspov/view/SceneGraphManager.py @@ -546,9 +546,14 @@ class SceneGraphManager(QObject): if probe_name not in self.point_probes: color = kwargs.get("color", np.array([0.5, 0., 0., 1.])) point_visual = FakeMarker(parent=self.main_map, symbol="x", pos=np.array([xy_pos]), color=color) - self.point_probes[probe_name] = point_visual + self.point_probes[probe_name] = (xy_pos, point_visual) else: - self.point_probes[probe_name].set_point(xy_pos) + point_visual = self.point_probes[probe_name][1] + point_visual.set_point(xy_pos) + self.point_probes[probe_name] = (xy_pos, point_visual) + + def point_probe_location(self, probe_name): + return self.point_probes[probe_name][0] if probe_name in self.point_probes else None def on_new_polygon(self, probe_name, points, **kwargs): kwargs.setdefault("color", (1.0, 0.0, 1.0, 0.5)) diff --git a/py/setup.py b/py/setup.py index 6aeef2797d5aae2ac4acc59c5f2f8dd3de5be3e0..dd094a7a2f1ad969a0bc3296b8c942b07f0ea5e2 100644 --- a/py/setup.py +++ b/py/setup.py @@ -20,7 +20,7 @@ from setuptools import setup, find_packages setup( name='cspov', - version='0.7.1', + version='0.7.2', description="Satellite Information Familiarization Tool for mercator geotiff files", author='Ray Garcia, SSEC', author_email='ray.garcia@ssec.wisc.edu', diff --git a/py/sift.iss b/py/sift.iss new file mode 100755 index 0000000000000000000000000000000000000000..b8a1438af3f31d77c8b60f67da8b1a18083421dc --- /dev/null +++ b/py/sift.iss @@ -0,0 +1,47 @@ +; -- Example1.iss -- +; Demonstrates copying 3 files and creating an icon. + +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING .ISS SCRIPT FILES! + +[Setup] +AppName=SIFT +AppVersion=0.7.2 +DefaultDirName={pf}\SIFT +DefaultGroupName=SIFT +Compression=lzma2 +SolidCompression=yes +OutputDir=sift_inno_setup_output + +[Files] +Source: "dist\SIFT\*"; DestDir: "{app}\bin"; Flags: replacesameversion recursesubdirs +Source: "..\README.md"; DestName: "README.txt"; DestDir: "{app}"; Flags: isreadme; AfterInstall: ConvertLineEndings + +[Dirs] +Name: "{userdocs}\sift_workspace"; Flags: setntfscompression; Tasks: workspace + +[Tasks] +Name: workspace; Description: "Create default workspace directory: {userdocs}\sift_workspace"; + +[Icons] +Name: "{group}\SIFT"; Filename: "{app}\bin\SIFT.exe" +Name: "{group}\Bug Tracker"; Filename: "https://gitlab.ssec.wisc.edu/rayg/CSPOV/issues" +Name: "{group}\Wiki"; Filename: "https://gitlab.ssec.wisc.edu/rayg/CSPOV/wikis/home" +Name: "{group}\Open Workspace"; Filename: "{userdocs}\sift_workspace" +Name: "{group}\Uninstall SIFT"; Filename: "{uninstallexe}" + +[Code] +const + LF = #10; + CR = #13; + CRLF = CR + LF; + +procedure ConvertLineEndings(); + var + FilePath : String; + FileContents : String; + begin + FilePath := ExpandConstant(CurrentFileName) + LoadStringFromFile(FilePath, FileContents); + StringChangeEx(FileContents, LF, CRLF, False); + SaveStringToFile(FilePath, FileContents, False); + end; \ No newline at end of file diff --git a/py/sift.spec b/py/sift.spec new file mode 100755 index 0000000000000000000000000000000000000000..5cece6fdd2bfc083d7b30dca17342cc1cae0761b --- /dev/null +++ b/py/sift.spec @@ -0,0 +1,46 @@ +# -*- mode: python -*- + +block_cipher = None + +from llvmlite.binding.ffi import _lib_dir, _lib_name +import vispy.glsl +import vispy.io +data_files = [ + (os.path.join(_lib_dir, _lib_name), '.'), + (os.path.join(_lib_dir, "MSVCP120.dll"), '.'), + (os.path.join(_lib_dir, "MSVCR120.dll"), '.'), + (os.path.dirname(vispy.glsl.__file__), os.path.join("vispy", "glsl")), + (os.path.join(os.path.dirname(vispy.io.__file__), "_data"), os.path.join("vispy", "io", "_data")), +] +for shape_dir in ["ne_50m_admin_0_countries", "ne_110m_admin_0_countries"]: + data_files.append((os.path.join("cspov", "data", shape_dir), os.path.join("cspov", "data", shape_dir))) + +a = Analysis(['cspov\\__main__.py'], + pathex=['Z:\\repos\\repos\\git\\CSPOV\\py'], + binaries=None, + datas=data_files, + hiddenimports=["vispy.app.backends._pyqt4", "PyQt4.QtNetwork", "scipy.linalg", "scipy.linalg.cython_blas", "scipy.linalg.cython_lapack", "scipy.integrate"], + hookspath=None, + runtime_hooks=None, + excludes=["tkinter"], + win_no_prefer_redirects=None, + win_private_assemblies=None, + cipher=block_cipher) +pyz = PYZ(a.pure, a.zipped_data, + cipher=block_cipher) +# FIXME: Remove the console when all diagnostics are properly shown in the GUI +exe = EXE(pyz, + a.scripts, + exclude_binaries=True, + name='SIFT', + debug=False, + strip=None, + upx=True, + console=True ) +coll = COLLECT(exe, + a.binaries, + a.zipfiles, + a.datas, + strip=None, + upx=True, + name='SIFT')