Source code for pyrocko.gui.sparrow.elements.kite_insar

# https://pyrocko.org - GPLv3
#
# The Pyrocko Developers, 21st Century
# ---|P------/S----------~Lg----------

import copy
import logging
try:
    from kite import Scene
except ImportError:
    Scene = None

import numpy as num

from pyrocko import geometry, cake
from pyrocko.guts import Bool, String, List
from pyrocko.gui.qt_compat import qw
from pyrocko.gui.vtk_util import TrimeshPipe, faces_to_cells

from .. import common

from .base import Element, ElementState, CPTHandler, CPTState

logger = logging.getLogger('kite_scene')
guts_prefix = 'sparrow'

km = 1e3
d2r = num.pi/180.


class SceneTileAdapter(object):

    def __init__(self, scene):
        self._scene = scene

    def x(self):
        # TODO how to handle E given in m
        frame = self._scene.frame
        x = num.zeros(frame.cols + 1)
        x[0] = frame.E[0] - 0.5 * frame.dE
        x[1:] = frame.E + 0.5 * frame.dE
        x += frame.llLon
        return x

    def y(self):
        # TODO how to handle N given in m
        frame = self._scene.frame
        y = num.zeros(frame.rows + 1)
        y[0] = frame.N[0] - 0.5 * frame.dN
        y[1:] = frame.N + 0.5 * frame.dN
        y += frame.llLat
        return y

    @property
    def data(self):
        disp = self._scene.displacement
        disp[num.isnan(disp)] = None
        return disp


class KiteMeshPipe(TrimeshPipe):
    def __init__(self, tile, cells_cache=None, **kwargs):
        lat_edge = tile.y()
        lon_edge = tile.x()
        data_center = tile.data

        nlat = lat_edge.size
        nlon = lon_edge.size

        assert nlat > 1 and nlon > 1
        assert data_center.shape == (nlat-1, nlon-1)

        ele = num.zeros((nlat, nlon))
        ele[:-1, :-1] = data_center * 100000.
        vertices, faces = geometry.topo_to_mesh(
            lat_edge, lon_edge, ele, cake.earthradius)

        self._raw_vertices = vertices

        if cells_cache is not None:
            if id(faces) not in cells_cache:
                cells_cache[id(faces)] = faces_to_cells(faces)

            cells = cells_cache[id(faces)]
        else:
            cells = faces_to_cells(faces)

        data_center = data_center.flatten()

        TrimeshPipe.__init__(
            self, vertices,
            cells=cells, values=data_center, **kwargs)


[docs]class KiteSceneElement(ElementState): visible = Bool.T(default=True) filename = String.T() scene = None
[docs]class KiteState(ElementState): visible = Bool.T(default=True) scenes = List.T(KiteSceneElement.T(), default=[]) cpt = CPTState.T(default=CPTState.D(cpt_name='seismic_r')) def create(self): element = KiteElement() return element def add_scene(self, scene): self.scenes.append(scene) def remove_scene(self, scene): if scene in self.scenes: self.scenes.remove(scene)
class KiteElement(Element): def __init__(self): Element.__init__(self) self._controls = None self._meshes = {} self._cells = {} self.cpt_handler = CPTHandler() def bind_state(self, state): Element.bind_state(self, state) self.talkie_connect(state, ['visible', 'scenes'], self.update) self.cpt_handler.bind_state(state.cpt, self.update) def unbind_state(self): self.cpt_handler.unbind_state() Element.unbind_state(self) def get_name(self): return 'Kite InSAR Scenes' def set_parent(self, parent): if Scene is None: qw.QMessageBox.warning( parent, 'Import Error', 'Software package Kite is needed to display InSAR scenes!') return self._parent = parent self._parent.add_panel( self.get_title_label(), self._get_controls(), visible=True, title_controls=[ self.get_title_control_remove(), self.get_title_control_visible()]) self.update() def unset_parent(self): self.unbind_state() if self._parent: for mesh in self._meshes: self._parent.remove_actor(mesh.actor) self._meshes.clear() self._cells.clear() if self._controls: self._parent.remove_panel(self._controls) self._controls = None self._parent.update_view() self._parent = None def _load_scene_from_fn(self, fn): try: scene = Scene.load(fn) except ImportError: qw.QMessageBox.warning( self._parent, 'Import Error', 'Could not load Kite scene from %s' % fn) return if scene.frame.spacing != 'degree': logger.warning( 'Sparrow requires Scene spacing in degrees. ' 'Skipped %s', fn) return return scene def open_load_scene_dialog(self, *args): caption = 'Select one or more Kite scenes to open' fns, _ = qw.QFileDialog.getOpenFileNames( self._parent, caption, filter='YAML file (*.yml *.yaml)', options=common.qfiledialog_options) for fname in fns: scene = self._load_scene_from_fn(fname) if scene is None: continue logger.debug('Adding Kite scene %s', fname) scene_element = KiteSceneElement(filename=fname) scene_element.scene = scene self._state.add_scene(scene_element) self.update() def clear_scenes(self, *args): logger.debug('Clearing all loaded Kite scenes') for mesh in self._meshes.values(): self._parent.remove_actor(mesh.actor) self._meshes.clear() self._state.scenes = [] self.update() def update(self, *args): state = self._state for mesh in self._meshes.values(): self._parent.remove_actor(mesh.actor) if self._state.visible: for scene_element in state.scenes: logger.debug('Drawing Kite scene') if scene_element.scene is None: scene_element.scene = self._load_scene_from_fn( scene_element.filename) scene = scene_element.scene scene_tile = SceneTileAdapter(scene) k = (scene_tile, state.cpt.cpt_name) if k not in self._meshes: cpt = copy.deepcopy( self.cpt_handler._cpts[state.cpt.cpt_name]) mesh = KiteMeshPipe( scene_tile, cells_cache=None, cpt=cpt, backface_culling=False) values = scene_tile.data.flatten() self.cpt_handler._values = values self.cpt_handler.update_cpt() mesh.set_shading('phong') mesh.set_lookuptable(self.cpt_handler._lookuptable) self._meshes[k] = mesh else: mesh = self._meshes[k] self.cpt_handler.update_cpt() if scene_element.visible: self._parent.add_actor(mesh.actor) self._parent.update_view() def _get_controls(self): if not self._controls: frame = qw.QFrame() layout = qw.QGridLayout() frame.setLayout(layout) pb_load = qw.QPushButton('Add Scene') pb_load.clicked.connect(self.open_load_scene_dialog) layout.addWidget(pb_load, 0, 1) pb_clear = qw.QPushButton('Clear Scenes') pb_clear.clicked.connect(self.clear_scenes) layout.addWidget(pb_clear, 0, 2) self.cpt_handler.cpt_controls( self._parent, self._state.cpt, layout) layout.addWidget(qw.QFrame(), 4, 0, 1, 3) self._controls = frame self._update_controls() return self._controls def _update_controls(self): self.cpt_handler._update_cpt_combobox() self.cpt_handler._update_cptscale_lineedit() __all__ = [ 'KiteState', 'KiteElement' ]