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 

9import vtk 

10 

11from pyrocko.guts import Bool, StringChoice, Float 

12from pyrocko.gui.qt_compat import qw, qc 

13from pyrocko.color import Color 

14 

15 

16from pyrocko.gui import vtk_util 

17from .. import common 

18from .base import Element, ElementState 

19 

20guts_prefix = 'sparrow' 

21 

22 

23class CoastlineResolutionChoice(StringChoice): 

24 choices = [ 

25 'crude', 

26 'low', 

27 'intermediate', 

28 'high', 

29 'full'] 

30 

31 

32class CoastlinesPipe(object): 

33 def __init__(self, resolution='low'): 

34 

35 self.mapper = vtk.vtkDataSetMapper() 

36 self.plane = vtk.vtkPlane() 

37 self.plane.SetOrigin(0.0, 0.0, 0.0) 

38 coll = vtk.vtkPlaneCollection() 

39 coll.AddItem(self.plane) 

40 self.mapper.SetClippingPlanes(coll) 

41 

42 self._polyline_grid = {} 

43 self._opacity = 1.0 

44 self._line_width = 1.0 

45 self._color = Color('white') 

46 self.set_resolution(resolution) 

47 

48 actor = vtk.vtkActor() 

49 actor.SetMapper(self.mapper) 

50 

51 prop = actor.GetProperty() 

52 prop.SetDiffuseColor(1, 1, 1) 

53 

54 self.prop = prop 

55 self.actor = actor 

56 

57 def set_resolution(self, resolution): 

58 assert resolution in CoastlineResolutionChoice.choices 

59 

60 if resolution not in self._polyline_grid: 

61 pb = common.get_app().get_progressbars() 

62 if pb: 

63 mess = 'Loading %s resolution coastlines' % resolution 

64 pb.set_status(mess, 0, can_abort=False) 

65 

66 from pyrocko.dataset.gshhg import GSHHG 

67 g = getattr(GSHHG, resolution)() 

68 

69 lines = [] 

70 npoly = len(g.polygons) 

71 for ipoly, poly in enumerate(g.polygons): 

72 if pb: 

73 pb.set_status( 

74 mess, float(ipoly) / npoly * 100., can_abort=False) 

75 

76 lines.append(poly.points) 

77 

78 self._polyline_grid[resolution] = vtk_util.make_multi_polyline( 

79 lines_latlon=lines, depth=-200.) 

80 

81 if pb: 

82 pb.set_status(mess, 100, can_abort=False) 

83 

84 vtk_util.vtk_set_input(self.mapper, self._polyline_grid[resolution]) 

85 

86 def set_opacity(self, opacity): 

87 opacity = float(opacity) 

88 if self._opacity != opacity: 

89 self.prop.SetOpacity(opacity) 

90 self._opacity = opacity 

91 

92 def set_color(self, color): 

93 if self._color != color: 

94 self.prop.SetDiffuseColor(color.rgb) 

95 self._color = color 

96 

97 def set_line_width(self, width): 

98 width = float(width) 

99 if self._line_width != width: 

100 self.prop.SetLineWidth(width) 

101 self._line_width = width 

102 

103 def set_clipping_plane(self, origin, normal): 

104 self.plane.SetOrigin(*origin) 

105 self.plane.SetNormal(*normal) 

106 

107 

108class CoastlinesState(ElementState): 

109 visible = Bool.T(default=True) 

110 resolution = CoastlineResolutionChoice.T(default='low') 

111 opacity = Float.T(default=0.4) 

112 color = Color.T(default=Color.D('white')) 

113 line_width = Float.T(default=1.0) 

114 

115 def create(self): 

116 element = CoastlinesElement() 

117 return element 

118 

119 

120class CoastlinesElement(Element): 

121 

122 def __init__(self): 

123 Element.__init__(self) 

124 self._parent = None 

125 self._controls = None 

126 self._coastlines = None 

127 

128 def get_name(self): 

129 return 'Coastlines' 

130 

131 def bind_state(self, state): 

132 Element.bind_state(self, state) 

133 for var in ['visible', 'resolution', 'opacity', 'color', 'line_width']: 

134 self.register_state_listener3(self.update, state, var) 

135 

136 def unbind_state(self): 

137 self._listeners = [] 

138 

139 def set_parent(self, parent): 

140 self._parent = parent 

141 self._parent.add_panel( 

142 self.get_name(), 

143 self._get_controls(), 

144 visible=True, 

145 title_controls=[ 

146 self.get_title_control_remove(), 

147 self.get_title_control_visible()]) 

148 

149 for var in ['lat', 'lon', 'depth', 'distance', 'azimuth', 'dip']: 

150 self.register_state_listener3( 

151 self.update_clipping, self._parent.state, var) 

152 

153 self.update() 

154 self.update_clipping() 

155 

156 def unset_parent(self): 

157 self.unbind_state() 

158 if self._parent: 

159 if self._coastlines: 

160 self._parent.remove_actor(self._coastlines.actor) 

161 self._coastlines = None 

162 

163 if self._controls: 

164 self._parent.remove_panel(self._controls) 

165 self._controls = None 

166 

167 self._parent.update_view() 

168 self._parent = None 

169 

170 def update(self, *args): 

171 state = self._state 

172 if not state.visible and self._coastlines: 

173 self._parent.remove_actor(self._coastlines.actor) 

174 

175 if state.visible: 

176 if not self._coastlines: 

177 self._coastlines = CoastlinesPipe(resolution=state.resolution) 

178 

179 self._parent.add_actor(self._coastlines.actor) 

180 self._coastlines.set_resolution(state.resolution) 

181 self._coastlines.set_opacity(state.opacity) 

182 self._coastlines.set_color(state.color) 

183 self._coastlines.set_line_width(state.line_width) 

184 

185 self._parent.update_view() 

186 

187 def update_clipping(self, *args): 

188 if self._state.visible and self._coastlines: 

189 cam = self._parent.camera_params[0] 

190 origin = cam / num.linalg.norm(cam)**2 

191 self._coastlines.set_clipping_plane(origin, cam) 

192 

193 def _get_controls(self): 

194 if not self._controls: 

195 from ..state import state_bind_combobox, \ 

196 state_bind_slider, state_bind_combobox_color 

197 

198 frame = qw.QFrame() 

199 layout = qw.QGridLayout() 

200 frame.setLayout(layout) 

201 

202 layout.addWidget(qw.QLabel('Resolution'), 0, 0) 

203 

204 cb = common.string_choices_to_combobox(CoastlineResolutionChoice) 

205 layout.addWidget(cb, 0, 1) 

206 state_bind_combobox(self, self._state, 'resolution', cb) 

207 

208 # opacity 

209 

210 layout.addWidget(qw.QLabel('Opacity'), 1, 0) 

211 

212 slider = qw.QSlider(qc.Qt.Horizontal) 

213 slider.setSizePolicy( 

214 qw.QSizePolicy( 

215 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

216 slider.setMinimum(0) 

217 slider.setMaximum(1000) 

218 layout.addWidget(slider, 1, 1) 

219 

220 state_bind_slider( 

221 self, self._state, 'opacity', slider, factor=0.001) 

222 

223 # color 

224 

225 layout.addWidget(qw.QLabel('Color'), 2, 0) 

226 

227 cb = common.strings_to_combobox( 

228 ['black', 'white']) 

229 

230 layout.addWidget(cb, 2, 1) 

231 state_bind_combobox_color( 

232 self, self._state, 'color', cb) 

233 

234 layout.addWidget(qw.QLabel('Line width'), 3, 0) 

235 

236 slider = qw.QSlider(qc.Qt.Horizontal) 

237 slider.setSizePolicy( 

238 qw.QSizePolicy( 

239 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

240 slider.setMinimum(0) 

241 slider.setMaximum(100) 

242 layout.addWidget(slider, 3, 1) 

243 state_bind_slider( 

244 self, self._state, 'line_width', slider, factor=0.1) 

245 

246 layout.addWidget(qw.QFrame(), 5, 0, 1, 2) 

247 

248 self._controls = frame 

249 

250 return self._controls 

251 

252 

253__all__ = [ 

254 'CoastlinesElement', 

255 'CoastlinesState']