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
10import vtk
12from pyrocko import util, plot
13from pyrocko.guts import Bool, Float
14from pyrocko.gui.qt_compat import qw
15from pyrocko.color import Color
18from pyrocko.gui import vtk_util
19from .base import Element, ElementState
20from .. import common
21from pyrocko.geometry import r2d, d2r
23km = 1000.
25guts_prefix = 'sparrow'
28def nice_value_circle(step):
29 step = plot.nice_value(step)
30 if step > 30.:
31 return 30.
33 return step
36def ticks(vmin, vmax, vstep):
37 vmin = num.floor(vmin / vstep) * vstep
38 vmax = num.ceil(vmax / vstep) * vstep
39 n = int(round((vmax - vmin) / vstep))
40 return vmin + num.arange(n+1) * vstep
43class LatLonGrid(object):
44 def __init__(self, r, step_major, step_minor, lat, lon, delta, depth):
46 lat_min, lat_max, lon_min, lon_max, lon_closed = common.cover_region(
47 lat, lon, delta, step_major, avoid_poles=True)
49 if delta < 30.:
50 step_major_lon = nice_value_circle(step_major/num.cos(lat*d2r))
51 else:
52 step_major_lon = step_major
54 lat_majors = ticks(lat_min, lat_max, step_major)
55 lon_majors = ticks(lon_min, lon_max, step_major_lon)
57 lat_minors = util.arange2(lat_min, lat_max, step_minor)
59 if lon_closed:
60 lon_minors = util.arange2(-180., 180., step_minor)
61 else:
62 lon_minors = util.arange2(lon_min, lon_max, step_minor)
64 lines = []
65 for lat_major in lat_majors:
66 points = num.zeros((lon_minors.size, 2))
67 points[:, 0] = lat_major
68 points[:, 1] = lon_minors
69 lines.append(points)
71 for lon_major in lon_majors:
72 points = num.zeros((lat_minors.size, 2))
73 points[:, 0] = lat_minors
74 points[:, 1] = lon_major
75 lines.append(points)
77 polyline_grid = vtk_util.make_multi_polyline(
78 lines_latlon=lines, depth=depth)
80 mapper = vtk.vtkDataSetMapper()
81 vtk_util.vtk_set_input(mapper, polyline_grid)
83 actor = vtk.vtkActor()
84 actor.SetMapper(mapper)
86 prop = actor.GetProperty()
87 self.prop = prop
89 prop.SetOpacity(0.15)
91 self._color = None
92 self.set_color(Color('white'))
94 self.actor = actor
96 def set_color(self, color):
97 if self._color is None or self._color != color:
98 self.prop.SetDiffuseColor(color.rgb)
99 self._color = color
102class GridState(ElementState):
103 visible = Bool.T(default=True)
104 color = Color.T(default=Color.D('white'))
105 depth = Float.T(default=-1.0*km)
107 def create(self):
108 element = GridElement()
109 return element
112class GridElement(Element):
114 def __init__(self):
115 Element.__init__(self)
116 self._controls = None
117 self._grid = None
118 self._stepsizes = self.get_stepsizes(10.)
120 def get_name(self):
121 return 'Grid'
123 def bind_state(self, state):
124 Element.bind_state(self, state)
125 self.register_state_listener3(self.update, state, 'visible')
126 self.register_state_listener3(self.update, state, 'color')
127 self.register_state_listener3(self.update, state, 'depth')
129 def set_parent(self, parent):
130 Element.set_parent(self, parent)
131 self._parent.add_panel(
132 self.get_name(),
133 self._get_controls(),
134 visible=True,
135 title_controls=[
136 self.get_title_control_remove(),
137 self.get_title_control_visible()])
139 for var in ['distance', 'lat', 'lon']:
140 self.register_state_listener3(self.update, self._parent.state, var)
142 self.update()
144 def unset_parent(self):
145 self.unbind_state()
146 if self._parent:
147 if self._grid:
148 self._parent.remove_actor(self._grid.actor)
149 self._grid = None
151 if self._controls:
152 self._parent.remove_panel(self._controls)
153 self._controls = None
155 self._parent.update_view()
156 self._parent = None
158 def get_stepsizes(self, distance):
159 factor = 10.
160 step_major = nice_value_circle(min(10.0, factor * distance))
161 step_minor = min(1.0, step_major)
162 return step_major, step_minor
164 def update(self, *args):
165 state = self._state
166 pstate = self._parent.state
168 stepsizes = self.get_stepsizes(pstate.distance)
169 if self._grid:
170 self._parent.remove_actor(self._grid.actor)
171 self._grid = None
173 if state.visible and not self._grid:
174 delta = pstate.distance * r2d * 0.5
175 self._grid = LatLonGrid(
176 1.0, stepsizes[0], stepsizes[1], pstate.lat, pstate.lon, delta,
177 state.depth)
178 self._parent.add_actor(self._grid.actor)
180 if self._grid:
181 self._grid.set_color(state.color)
183 self._parent.update_view()
185 def _get_controls(self):
186 if not self._controls:
187 from ..state import state_bind_combobox_color, \
188 state_bind_lineedit
190 frame = qw.QFrame()
191 layout = qw.QGridLayout()
192 frame.setLayout(layout)
194 # color
196 layout.addWidget(qw.QLabel('Color'), 0, 0)
198 cb = common.strings_to_combobox(
199 ['black', 'white'])
201 layout.addWidget(cb, 0, 1)
202 state_bind_combobox_color(self, self._state, 'color', cb)
204 layout.addWidget(qw.QLabel('Depth [km]'), 1, 0)
205 le = qw.QLineEdit()
206 layout.addWidget(le, 1, 1)
207 state_bind_lineedit(
208 self, self._state, 'depth', le,
209 from_string=lambda s: float(s)*1000.,
210 to_string=lambda v: str(v/1000.))
212 layout.addWidget(qw.QFrame(), 2, 0, 1, 2)
214 self._controls = frame
216 return self._controls
219__all__ = [
220 'GridElement',
221 'GridState']