1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6import numpy as num 

7import vtk 

8 

9from pyrocko.guts import Bool, StringChoice, Float 

10from pyrocko.gui.qt_compat import qw, qc 

11from pyrocko.color import Color 

12 

13 

14from pyrocko.gui import vtk_util 

15from .. import common 

16from .base import Element, ElementState 

17 

18guts_prefix = 'sparrow' 

19 

20 

21class CoastlineResolutionChoice(StringChoice): 

22 choices = [ 

23 'crude', 

24 'low', 

25 'intermediate', 

26 'high', 

27 'full'] 

28 

29 

30class CoastlinesPipe(object): 

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

32 

33 self.mapper = vtk.vtkDataSetMapper() 

34 self.plane = vtk.vtkPlane() 

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

36 coll = vtk.vtkPlaneCollection() 

37 coll.AddItem(self.plane) 

38 self.mapper.SetClippingPlanes(coll) 

39 

40 self._polyline_grid = {} 

41 self._opacity = 1.0 

42 self._line_width = 1.0 

43 self._color = Color('white') 

44 self.set_resolution(resolution) 

45 

46 actor = vtk.vtkActor() 

47 actor.SetMapper(self.mapper) 

48 

49 prop = actor.GetProperty() 

50 prop.SetDiffuseColor(1, 1, 1) 

51 

52 self.prop = prop 

53 self.actor = actor 

54 

55 def set_resolution(self, resolution): 

56 assert resolution in CoastlineResolutionChoice.choices 

57 

58 if resolution not in self._polyline_grid: 

59 pb = common.get_viewer().progressbars 

60 if pb: 

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

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

63 

64 from pyrocko.dataset.gshhg import GSHHG 

65 g = getattr(GSHHG, resolution)() 

66 

67 lines = [] 

68 npoly = len(g.polygons) 

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

70 if pb: 

71 pb.set_status( 

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

73 

74 lines.append(poly.points) 

75 

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

77 lines_latlon=lines, depth=-200.) 

78 

79 if pb: 

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

81 

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

83 

84 def set_opacity(self, opacity): 

85 opacity = float(opacity) 

86 if self._opacity != opacity: 

87 self.prop.SetOpacity(opacity) 

88 self._opacity = opacity 

89 

90 def set_color(self, color): 

91 if self._color != color: 

92 self.prop.SetDiffuseColor(color.rgb) 

93 self._color = color 

94 

95 def set_line_width(self, width): 

96 width = float(width) 

97 if self._line_width != width: 

98 self.prop.SetLineWidth(width) 

99 self._line_width = width 

100 

101 def set_clipping_plane(self, origin, normal): 

102 self.plane.SetOrigin(*origin) 

103 self.plane.SetNormal(*normal) 

104 

105 

106class CoastlinesState(ElementState): 

107 visible = Bool.T(default=True) 

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

109 opacity = Float.T(default=0.4) 

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

111 line_width = Float.T(default=1.0) 

112 

113 def create(self): 

114 element = CoastlinesElement() 

115 return element 

116 

117 

118class CoastlinesElement(Element): 

119 

120 def __init__(self): 

121 Element.__init__(self) 

122 self._parent = None 

123 self._controls = None 

124 self._coastlines = None 

125 

126 def get_name(self): 

127 return 'Coastlines' 

128 

129 def bind_state(self, state): 

130 Element.bind_state(self, state) 

131 self.talkie_connect( 

132 state, 

133 ['visible', 'resolution', 'opacity', 'color', 'line_width'], 

134 self.update) 

135 

136 def set_parent(self, parent): 

137 self._parent = parent 

138 self._parent.add_panel( 

139 self.get_title_label(), 

140 self._get_controls(), 

141 visible=True, 

142 title_controls=[ 

143 self.get_title_control_remove(), 

144 self.get_title_control_visible()]) 

145 

146 self.talkie_connect( 

147 self._parent.state, 

148 ['lat', 'lon', 'depth', 'distance', 'azimuth', 'dip'], 

149 self.update_clipping) 

150 

151 self.update() 

152 self.update_clipping() 

153 

154 def unset_parent(self): 

155 self.unbind_state() 

156 if self._parent: 

157 if self._coastlines: 

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

159 self._coastlines = None 

160 

161 if self._controls: 

162 self._parent.remove_panel(self._controls) 

163 self._controls = None 

164 

165 self._parent.update_view() 

166 self._parent = None 

167 

168 def update(self, *args): 

169 state = self._state 

170 if not state.visible and self._coastlines: 

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

172 

173 if state.visible: 

174 if not self._coastlines: 

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

176 

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

178 self._coastlines.set_resolution(state.resolution) 

179 self._coastlines.set_opacity(state.opacity) 

180 self._coastlines.set_color(state.color) 

181 self._coastlines.set_line_width(state.line_width) 

182 

183 self._parent.update_view() 

184 

185 def update_clipping(self, *args): 

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

187 cam = self._parent.camera_params[0] 

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

189 self._coastlines.set_clipping_plane(origin, cam) 

190 

191 def _get_controls(self): 

192 if not self._controls: 

193 from ..state import state_bind_combobox, \ 

194 state_bind_slider, state_bind_combobox_color 

195 

196 frame = qw.QFrame() 

197 layout = qw.QGridLayout() 

198 frame.setLayout(layout) 

199 

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

201 

202 cb = common.string_choices_to_combobox(CoastlineResolutionChoice) 

203 layout.addWidget(cb, 0, 1) 

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

205 

206 # opacity 

207 

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

209 

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

211 slider.setSizePolicy( 

212 qw.QSizePolicy( 

213 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

214 slider.setMinimum(0) 

215 slider.setMaximum(1000) 

216 layout.addWidget(slider, 1, 1) 

217 

218 state_bind_slider( 

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

220 

221 # color 

222 

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

224 

225 cb = common.strings_to_combobox( 

226 ['black', 'white']) 

227 

228 layout.addWidget(cb, 2, 1) 

229 state_bind_combobox_color( 

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

231 

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

233 

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

235 slider.setSizePolicy( 

236 qw.QSizePolicy( 

237 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

238 slider.setMinimum(0) 

239 slider.setMaximum(100) 

240 layout.addWidget(slider, 3, 1) 

241 state_bind_slider( 

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

243 

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

245 

246 self._controls = frame 

247 

248 return self._controls 

249 

250 

251__all__ = [ 

252 'CoastlinesElement', 

253 'CoastlinesState']