Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/gui/sparrow/elements/kite_insar.py: 26%
185 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-04 09:52 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-04 09:52 +0000
1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import copy
7import logging
8try:
9 from kite import Scene
10except ImportError:
11 Scene = None
13import numpy as num
15from pyrocko import geometry, cake
16from pyrocko.guts import Bool, String, List
17from pyrocko.gui.qt_compat import qw
18from pyrocko.gui.vtk_util import TrimeshPipe, faces_to_cells
20from .. import common
22from .base import Element, ElementState, CPTHandler, CPTState
24logger = logging.getLogger('kite_scene')
25guts_prefix = 'sparrow'
27km = 1e3
28d2r = num.pi/180.
31class SceneTileAdapter(object):
33 def __init__(self, scene):
34 self._scene = scene
36 def x(self):
37 # TODO how to handle E given in m
38 frame = self._scene.frame
39 x = num.zeros(frame.cols + 1)
40 x[0] = frame.E[0] - 0.5 * frame.dE
41 x[1:] = frame.E + 0.5 * frame.dE
42 x += frame.llLon
43 return x
45 def y(self):
46 # TODO how to handle N given in m
47 frame = self._scene.frame
48 y = num.zeros(frame.rows + 1)
49 y[0] = frame.N[0] - 0.5 * frame.dN
50 y[1:] = frame.N + 0.5 * frame.dN
51 y += frame.llLat
52 return y
54 @property
55 def data(self):
56 disp = self._scene.displacement
57 disp[num.isnan(disp)] = None
58 return disp
61class KiteMeshPipe(TrimeshPipe):
62 def __init__(self, tile, cells_cache=None, **kwargs):
63 lat_edge = tile.y()
64 lon_edge = tile.x()
65 data_center = tile.data
67 nlat = lat_edge.size
68 nlon = lon_edge.size
70 assert nlat > 1 and nlon > 1
71 assert data_center.shape == (nlat-1, nlon-1)
73 ele = num.zeros((nlat, nlon))
74 ele[:-1, :-1] = data_center * 100000.
75 vertices, faces = geometry.topo_to_mesh(
76 lat_edge, lon_edge, ele, cake.earthradius)
78 self._raw_vertices = vertices
80 if cells_cache is not None:
81 if id(faces) not in cells_cache:
82 cells_cache[id(faces)] = faces_to_cells(faces)
84 cells = cells_cache[id(faces)]
85 else:
86 cells = faces_to_cells(faces)
88 data_center = data_center.flatten()
90 TrimeshPipe.__init__(
91 self, vertices,
92 cells=cells, values=data_center, **kwargs)
95class KiteSceneElement(ElementState):
96 visible = Bool.T(default=True)
97 filename = String.T()
98 scene = None
101class KiteState(ElementState):
102 visible = Bool.T(default=True)
103 scenes = List.T(KiteSceneElement.T(), default=[])
104 cpt = CPTState.T(default=CPTState.D(cpt_name='seismic_r'))
106 def create(self):
107 element = KiteElement()
108 return element
110 def add_scene(self, scene):
111 self.scenes.append(scene)
113 def remove_scene(self, scene):
114 if scene in self.scenes:
115 self.scenes.remove(scene)
118class KiteElement(Element):
120 def __init__(self):
121 Element.__init__(self)
122 self._controls = None
123 self._meshes = {}
124 self._cells = {}
125 self.cpt_handler = CPTHandler()
127 def bind_state(self, state):
128 Element.bind_state(self, state)
129 self.talkie_connect(state, ['visible', 'scenes'], self.update)
131 self.cpt_handler.bind_state(state.cpt, self.update)
133 def unbind_state(self):
134 self.cpt_handler.unbind_state()
135 Element.unbind_state(self)
137 def get_name(self):
138 return 'Kite InSAR Scenes'
140 def set_parent(self, parent):
141 if Scene is None:
142 qw.QMessageBox.warning(
143 parent, 'Import Error',
144 'Software package Kite is needed to display InSAR scenes!')
145 return
147 self._parent = parent
148 self._parent.add_panel(
149 self.get_title_label(),
150 self._get_controls(),
151 visible=True,
152 title_controls=[
153 self.get_title_control_remove(),
154 self.get_title_control_visible()])
156 self.update()
158 def unset_parent(self):
159 self.unbind_state()
160 if self._parent:
161 for mesh in self._meshes:
162 self._parent.remove_actor(mesh.actor)
164 self._meshes.clear()
165 self._cells.clear()
167 if self._controls:
168 self._parent.remove_panel(self._controls)
169 self._controls = None
171 self._parent.update_view()
172 self._parent = None
174 def _load_scene_from_fn(self, fn):
175 try:
176 scene = Scene.load(fn)
177 except ImportError:
178 qw.QMessageBox.warning(
179 self._parent, 'Import Error',
180 'Could not load Kite scene from %s' % fn)
181 return
183 if scene.frame.spacing != 'degree':
184 logger.warning(
185 'Sparrow requires Scene spacing in degrees. '
186 'Skipped %s', fn)
188 return
190 return scene
192 def open_load_scene_dialog(self, *args):
193 caption = 'Select one or more Kite scenes to open'
195 fns, _ = qw.QFileDialog.getOpenFileNames(
196 self._parent, caption,
197 filter='YAML file (*.yml *.yaml)',
198 options=common.qfiledialog_options)
200 for fname in fns:
201 scene = self._load_scene_from_fn(fname)
203 if scene is None:
204 continue
206 logger.debug('Adding Kite scene %s', fname)
208 scene_element = KiteSceneElement(filename=fname)
209 scene_element.scene = scene
210 self._state.add_scene(scene_element)
212 self.update()
214 def clear_scenes(self, *args):
215 logger.debug('Clearing all loaded Kite scenes')
217 for mesh in self._meshes.values():
218 self._parent.remove_actor(mesh.actor)
220 self._meshes.clear()
221 self._state.scenes = []
223 self.update()
225 def update(self, *args):
226 state = self._state
228 for mesh in self._meshes.values():
229 self._parent.remove_actor(mesh.actor)
231 if self._state.visible:
232 for scene_element in state.scenes:
233 logger.debug('Drawing Kite scene')
235 if scene_element.scene is None:
236 scene_element.scene = self._load_scene_from_fn(
237 scene_element.filename)
239 scene = scene_element.scene
241 scene_tile = SceneTileAdapter(scene)
243 k = (scene_tile, state.cpt.cpt_name)
245 if k not in self._meshes:
246 cpt = copy.deepcopy(
247 self.cpt_handler._cpts[state.cpt.cpt_name])
249 mesh = KiteMeshPipe(
250 scene_tile,
251 cells_cache=None,
252 cpt=cpt,
253 backface_culling=False)
255 values = scene_tile.data.flatten()
256 self.cpt_handler._values = values
257 self.cpt_handler.update_cpt()
259 mesh.set_shading('phong')
260 mesh.set_lookuptable(self.cpt_handler._lookuptable)
262 self._meshes[k] = mesh
263 else:
264 mesh = self._meshes[k]
265 self.cpt_handler.update_cpt()
267 if scene_element.visible:
268 self._parent.add_actor(mesh.actor)
270 self._parent.update_view()
272 def _get_controls(self):
273 if not self._controls:
274 frame = qw.QFrame()
275 layout = qw.QGridLayout()
276 frame.setLayout(layout)
278 pb_load = qw.QPushButton('Add Scene')
279 pb_load.clicked.connect(self.open_load_scene_dialog)
280 layout.addWidget(pb_load, 0, 1)
282 pb_clear = qw.QPushButton('Clear Scenes')
283 pb_clear.clicked.connect(self.clear_scenes)
284 layout.addWidget(pb_clear, 0, 2)
286 self.cpt_handler.cpt_controls(
287 self._parent, self._state.cpt, layout)
289 layout.addWidget(qw.QFrame(), 4, 0, 1, 3)
291 self._controls = frame
293 self._update_controls()
295 return self._controls
297 def _update_controls(self):
298 self.cpt_handler._update_cpt_combobox()
299 self.cpt_handler._update_cptscale_lineedit()
302__all__ = [
303 'KiteState',
304 'KiteElement'
305]