1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6from __future__ import absolute_import, print_function, division
8import numpy as num
10from pyrocko.guts import Int, Float, Bool
11from pyrocko.gui.qt_compat import qw, qc
13from pyrocko.gui.vtk_util import TrimeshPipe
14from .base import Element, ElementState
15from pyrocko import icosphere, moment_tensor as pmt, orthodrome as od, cake
16from pyrocko.geometry import d2r
18guts_prefix = 'sparrow'
21class SpheroidState(ElementState):
22 level = Int.T(default=4)
23 visible = Bool.T(default=True)
24 opacity = Float.T(default=1.0)
25 lat = Float.T(default=0.0)
26 lon = Float.T(default=0.0)
27 depth = Float.T(default=0.0)
28 a = Float.T(default=10000.)
29 b = Float.T(default=10000.)
30 c = Float.T(default=10000.)
31 azimuth = Float.T(default=0.0)
32 dip = Float.T(default=0.0)
34 def create(self):
35 element = SpheroidElement()
36 return element
39class SpheroidElement(Element):
41 def __init__(self):
42 Element.__init__(self)
43 self._mesh = None
44 self._controls = None
45 self._params = None
46 self._opacity = None
48 def get_name(self):
49 return 'Spheroid'
51 def bind_state(self, state):
52 Element.bind_state(self, state)
54 for var in [
55 'visible', 'level', 'opacity',
56 'lat', 'lon', 'depth', 'a', 'b', 'c', 'azimuth', 'dip']:
58 self.register_state_listener3(self.update, state, var)
60 def unbind_state(self):
61 self._listeners = []
63 def set_parent(self, parent):
64 Element.set_parent(self, parent)
66 self._parent.add_panel(
67 self.get_name(),
68 self._get_controls(),
69 visible=True,
70 title_controls=[
71 self.get_title_control_remove(),
72 self.get_title_control_visible()])
74 self.update()
76 def unset_parent(self):
77 self.unbind_state()
78 if self._parent:
79 if self._mesh:
80 self._parent.remove_actor(self._mesh.actor)
81 self._mesh = None
83 if self._controls:
84 self._parent.remove_panel(self._controls)
85 self._controls = None
87 self._parent.update_view()
88 self._parent = None
89 self._opacity = None
90 self._params = None
92 def update(self, *args):
93 state = self._state
95 params = (state.level,)
97 if self._mesh and (params != self._params or not state.visible):
98 self._parent.remove_actor(self._mesh.actor)
99 self._mesh = None
101 if state.visible and not self._mesh:
102 vertices, faces = icosphere.sphere(
103 state.level, 'icosahedron', 'kind1',
104 radius=1.0,
105 triangulate=False)
107 self._vertices0 = vertices
108 self._mesh = TrimeshPipe(vertices, faces, smooth=True)
109 self._params = params
111 self._parent.add_actor(self._mesh.actor)
113 s = num.array(
114 [state.c, state.b, state.a]) / cake.earthradius
116 if self._mesh:
117 vertices = self._vertices0 * s[num.newaxis, :]
118 bc = num.matrix(
119 [[1, 0, 0], [0, 0, 1], [0, 1, 0]], dtype=num.float64)
120 rot = num.dot(
121 bc,
122 num.dot(
123 pmt.euler_to_matrix(-d2r*state.azimuth, -d2r*state.dip, 0),
124 bc.T))
125 vertices = num.dot(rot, vertices.T).T
126 vertices[:, 0] += 1.0 - state.depth / cake.earthradius
127 rot = od.rot_to_00(state.lat, state.lon).T
128 vertices = num.dot(rot, vertices.T).T
130 self._mesh.set_vertices(vertices)
131 self._mesh.prop.SetColor(0.8, 0.2, 0.1)
133 if self._mesh and self._opacity != state.opacity:
134 self._mesh.set_opacity(state.opacity)
135 self._opacity = state.opacity
136 else:
137 self._opacity = None
139 self._parent.update_view()
141 def move_here(self):
142 pstate = self._parent.state
143 state = self._state
144 state.lat = pstate.lat
145 state.lon = pstate.lon
147 def _get_controls(self):
148 state = self._state
149 if not self._controls:
150 from ..state import state_bind_slider
152 frame = qw.QFrame()
153 layout = qw.QGridLayout()
154 frame.setLayout(layout)
156 iy = 0
157 for (param, vmin, vmax) in [
158 ('lat', -90., 90.),
159 ('lon', -180., 180.),
160 ('depth', -10000., 100000.),
161 ('a', 100., 100000.),
162 ('b', 100., 100000.),
163 ('c', 100., 100000.),
164 ('azimuth', -180., 180.),
165 ('dip', -90., 90.),
166 ('opacity', 0., 1.)]:
168 layout.addWidget(qw.QLabel(param.capitalize()), iy, 0)
170 slider = qw.QSlider(qc.Qt.Horizontal)
171 slider.setSizePolicy(qw.QSizePolicy(
172 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed))
174 slider.setMinimum(int(round(vmin * 100.)))
175 slider.setMaximum(int(round(vmax * 100.)))
176 layout.addWidget(slider, iy, 1)
178 state_bind_slider(self, state, param, slider, factor=0.01)
179 iy += 1
181 pb = qw.QPushButton('Move Here')
182 layout.addWidget(pb, iy, 0)
183 pb.clicked.connect(self.move_here)
185 iy += 1
187 layout.addWidget(qw.QFrame(), iy, 0, 1, 2)
189 self._controls = frame
191 return self._controls
194__all__ = [
195 'SpheroidElement',
196 'SpheroidState']