Coverage for /usr/local/lib/python3.11/dist-packages/pyrocko/gui/sparrow/elements/spheroid.py: 94%
110 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-06 15:01 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-10-06 15:01 +0000
1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import numpy as num
8from pyrocko.guts import Int, Float, Bool
9from pyrocko.gui.qt_compat import qw, qc
11from pyrocko.gui.vtk_util import TrimeshPipe
12from .base import Element, ElementState
13from pyrocko import icosphere, moment_tensor as pmt, orthodrome as od, cake
14from pyrocko.geometry import d2r
16guts_prefix = 'sparrow'
19class SpheroidState(ElementState):
20 level = Int.T(default=4)
21 visible = Bool.T(default=True)
22 opacity = Float.T(default=1.0)
23 lat = Float.T(default=0.0)
24 lon = Float.T(default=0.0)
25 depth = Float.T(default=0.0)
26 a = Float.T(default=10000.)
27 b = Float.T(default=10000.)
28 c = Float.T(default=10000.)
29 azimuth = Float.T(default=0.0)
30 dip = Float.T(default=0.0)
32 def create(self):
33 element = SpheroidElement()
34 return element
37class SpheroidElement(Element):
39 def __init__(self):
40 Element.__init__(self)
41 self._mesh = None
42 self._controls = None
43 self._params = None
44 self._opacity = None
46 def get_name(self):
47 return 'Spheroid'
49 def bind_state(self, state):
50 Element.bind_state(self, state)
51 self.talkie_connect(
52 state,
53 ['visible', 'level', 'opacity', 'lat', 'lon', 'depth', 'a', 'b',
54 'c', 'azimuth', 'dip'],
55 self.update)
57 def set_parent(self, parent):
58 Element.set_parent(self, parent)
60 self._parent.add_panel(
61 self.get_title_label(),
62 self._get_controls(),
63 visible=True,
64 title_controls=[
65 self.get_title_control_remove(),
66 self.get_title_control_visible()])
68 self.update()
70 def unset_parent(self):
71 self.unbind_state()
72 if self._parent:
73 if self._mesh:
74 self._parent.remove_actor(self._mesh.actor)
75 self._mesh = None
77 if self._controls:
78 self._parent.remove_panel(self._controls)
79 self._controls = None
81 self._parent.update_view()
82 self._parent = None
83 self._opacity = None
84 self._params = None
86 def update(self, *args):
87 state = self._state
89 params = (state.level,)
91 if self._mesh and (params != self._params or not state.visible):
92 self._parent.remove_actor(self._mesh.actor)
93 self._mesh = None
95 if state.visible and not self._mesh:
96 vertices, faces = icosphere.sphere(
97 state.level, 'icosahedron', 'kind1',
98 radius=1.0,
99 triangulate=False)
101 self._vertices0 = vertices
102 self._mesh = TrimeshPipe(vertices, faces, smooth=True)
103 self._params = params
105 self._parent.add_actor(self._mesh.actor)
107 s = num.array(
108 [state.c, state.b, state.a]) / cake.earthradius
110 if self._mesh:
111 vertices = self._vertices0 * s[num.newaxis, :]
112 bc = num.array(
113 [[1, 0, 0], [0, 0, 1], [0, 1, 0]], dtype=num.float64)
114 rot = num.dot(
115 bc,
116 num.dot(
117 pmt.euler_to_matrix(-d2r*state.azimuth, -d2r*state.dip, 0),
118 bc.T))
119 vertices = num.dot(rot, vertices.T).T
120 vertices[:, 0] += 1.0 - state.depth / cake.earthradius
121 rot = od.rot_to_00(state.lat, state.lon).T
122 vertices = num.dot(rot, vertices.T).T
124 self._mesh.set_vertices(vertices)
125 self._mesh.prop.SetColor(0.8, 0.2, 0.1)
127 if self._mesh and self._opacity != state.opacity:
128 self._mesh.set_opacity(state.opacity)
129 self._opacity = state.opacity
130 else:
131 self._opacity = None
133 self._parent.update_view()
135 def move_here(self):
136 pstate = self._parent.state
137 state = self._state
138 state.lat = pstate.lat
139 state.lon = pstate.lon
141 def _get_controls(self):
142 state = self._state
143 if not self._controls:
144 from ..state import state_bind_slider
146 frame = qw.QFrame()
147 layout = qw.QGridLayout()
148 frame.setLayout(layout)
150 iy = 0
151 for (param, vmin, vmax) in [
152 ('lat', -90., 90.),
153 ('lon', -180., 180.),
154 ('depth', -10000., 100000.),
155 ('a', 100., 100000.),
156 ('b', 100., 100000.),
157 ('c', 100., 100000.),
158 ('azimuth', -180., 180.),
159 ('dip', -90., 90.),
160 ('opacity', 0., 1.)]:
162 layout.addWidget(qw.QLabel(param.capitalize()), iy, 0)
164 slider = qw.QSlider(qc.Qt.Horizontal)
165 slider.setSizePolicy(qw.QSizePolicy(
166 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed))
168 slider.setMinimum(int(round(vmin * 100.)))
169 slider.setMaximum(int(round(vmax * 100.)))
170 layout.addWidget(slider, iy, 1)
172 state_bind_slider(self, state, param, slider, factor=0.01)
173 iy += 1
175 pb = qw.QPushButton('Move Here')
176 layout.addWidget(pb, iy, 0)
177 pb.clicked.connect(self.move_here)
179 iy += 1
181 layout.addWidget(qw.QFrame(), iy, 0, 1, 2)
183 self._controls = frame
185 return self._controls
188__all__ = [
189 'SpheroidElement',
190 'SpheroidState']