1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6from __future__ import absolute_import, print_function, division 

7 

8import numpy as num 

9 

10import vtk 

11 

12from pyrocko import util, plot 

13from pyrocko.guts import Bool, Float 

14from pyrocko.gui.qt_compat import qw 

15from pyrocko.color import Color 

16 

17 

18from pyrocko.gui import vtk_util 

19from .base import Element, ElementState 

20from .. import common 

21from pyrocko.geometry import r2d, d2r 

22 

23km = 1000. 

24 

25guts_prefix = 'sparrow' 

26 

27 

28def nice_value_circle(step): 

29 step = plot.nice_value(step) 

30 if step > 30.: 

31 return 30. 

32 

33 return step 

34 

35 

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 

41 

42 

43class LatLonGrid(object): 

44 def __init__(self, r, step_major, step_minor, lat, lon, delta, depth): 

45 

46 lat_min, lat_max, lon_min, lon_max, lon_closed = common.cover_region( 

47 lat, lon, delta, step_major, avoid_poles=True) 

48 

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 

53 

54 lat_majors = ticks(lat_min, lat_max, step_major) 

55 lon_majors = ticks(lon_min, lon_max, step_major_lon) 

56 

57 lat_minors = util.arange2(lat_min, lat_max, step_minor) 

58 

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) 

63 

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) 

70 

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) 

76 

77 polyline_grid = vtk_util.make_multi_polyline( 

78 lines_latlon=lines, depth=depth) 

79 

80 mapper = vtk.vtkDataSetMapper() 

81 vtk_util.vtk_set_input(mapper, polyline_grid) 

82 

83 actor = vtk.vtkActor() 

84 actor.SetMapper(mapper) 

85 

86 prop = actor.GetProperty() 

87 self.prop = prop 

88 

89 prop.SetOpacity(0.15) 

90 

91 self._color = None 

92 self.set_color(Color('white')) 

93 

94 self.actor = actor 

95 

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 

100 

101 

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) 

106 

107 def create(self): 

108 element = GridElement() 

109 return element 

110 

111 

112class GridElement(Element): 

113 

114 def __init__(self): 

115 Element.__init__(self) 

116 self._controls = None 

117 self._grid = None 

118 self._stepsizes = self.get_stepsizes(10.) 

119 

120 def get_name(self): 

121 return 'Grid' 

122 

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') 

128 

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()]) 

138 

139 for var in ['distance', 'lat', 'lon']: 

140 self.register_state_listener3(self.update, self._parent.state, var) 

141 

142 self.update() 

143 

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 

150 

151 if self._controls: 

152 self._parent.remove_panel(self._controls) 

153 self._controls = None 

154 

155 self._parent.update_view() 

156 self._parent = None 

157 

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 

163 

164 def update(self, *args): 

165 state = self._state 

166 pstate = self._parent.state 

167 

168 stepsizes = self.get_stepsizes(pstate.distance) 

169 if self._grid: 

170 self._parent.remove_actor(self._grid.actor) 

171 self._grid = None 

172 

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) 

179 

180 if self._grid: 

181 self._grid.set_color(state.color) 

182 

183 self._parent.update_view() 

184 

185 def _get_controls(self): 

186 if not self._controls: 

187 from ..state import state_bind_combobox_color, \ 

188 state_bind_lineedit 

189 

190 frame = qw.QFrame() 

191 layout = qw.QGridLayout() 

192 frame.setLayout(layout) 

193 

194 # color 

195 

196 layout.addWidget(qw.QLabel('Color'), 0, 0) 

197 

198 cb = common.strings_to_combobox( 

199 ['black', 'white']) 

200 

201 layout.addWidget(cb, 0, 1) 

202 state_bind_combobox_color(self, self._state, 'color', cb) 

203 

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.)) 

211 

212 layout.addWidget(qw.QFrame(), 2, 0, 1, 2) 

213 

214 self._controls = frame 

215 

216 return self._controls 

217 

218 

219__all__ = [ 

220 'GridElement', 

221 'GridState']