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 

17from pyrocko.dataset.gshhg import Coastlines, Rivers, Borders 

18 

19 

20guts_prefix = 'sparrow' 

21 

22gshhg_dataset_mapping = { 

23 'coastlines': Coastlines, 

24 'rivers': Rivers, 

25 'borders': Borders, 

26} 

27 

28 

29class GSHHGDatasetChoice(StringChoice): 

30 choices = ['coastlines', 'borders', 'rivers'] 

31 

32 

33class GSHHGResolutionChoice(StringChoice): 

34 choices = [ 

35 'crude', 

36 'low', 

37 'intermediate', 

38 'high', 

39 'full'] 

40 

41 

42class GSHHGPipe(object): 

43 def __init__(self, dataset, resolution='low'): 

44 

45 self.mapper = vtk.vtkDataSetMapper() 

46 self.plane = vtk.vtkPlane() 

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

48 coll = vtk.vtkPlaneCollection() 

49 coll.AddItem(self.plane) 

50 self.mapper.SetClippingPlanes(coll) 

51 

52 self._polyline_grid = {} 

53 self._opacity = 1.0 

54 self._line_width = 1.0 

55 self._color = Color('white') 

56 self.set_resolution(dataset, resolution) 

57 

58 actor = vtk.vtkActor() 

59 actor.SetMapper(self.mapper) 

60 

61 prop = actor.GetProperty() 

62 prop.SetDiffuseColor(1, 1, 1) 

63 

64 self.prop = prop 

65 self.actor = actor 

66 

67 def set_resolution(self, dataset, resolution): 

68 assert resolution in GSHHGResolutionChoice.choices 

69 assert dataset in GSHHGDatasetChoice.choices 

70 

71 if resolution not in self._polyline_grid: 

72 pb = common.get_viewer().progressbars 

73 if pb: 

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

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

76 

77 dataset = gshhg_dataset_mapping[dataset] 

78 

79 g = getattr(dataset, resolution)() 

80 

81 lines = [] 

82 npoly = len(g.polygons) 

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

84 if pb: 

85 pb.set_status( 

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

87 

88 lines.append(poly.points) 

89 

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

91 lines_latlon=lines, depth=-200.) 

92 

93 if pb: 

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

95 

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

97 

98 def set_opacity(self, opacity): 

99 opacity = float(opacity) 

100 if self._opacity != opacity: 

101 self.prop.SetOpacity(opacity) 

102 self._opacity = opacity 

103 

104 def set_color(self, color): 

105 if self._color != color: 

106 self.prop.SetDiffuseColor(color.rgb) 

107 self._color = color 

108 

109 def set_line_width(self, width): 

110 width = float(width) 

111 if self._line_width != width: 

112 self.prop.SetLineWidth(width) 

113 self._line_width = width 

114 

115 def set_clipping_plane(self, origin, normal): 

116 self.plane.SetOrigin(*origin) 

117 self.plane.SetNormal(*normal) 

118 

119 

120class GSHHGState(ElementState): 

121 visible = Bool.T(default=True) 

122 dataset = GSHHGDatasetChoice.T(default='coastlines') 

123 resolution = GSHHGResolutionChoice.T(default='low') 

124 opacity = Float.T(default=0.4) 

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

126 line_width = Float.T(default=1.0) 

127 

128 def create(self): 

129 element = GSHHGElement() 

130 return element 

131 

132 

133class GSHHGElement(Element): 

134 

135 def __init__(self): 

136 Element.__init__(self) 

137 self._parent = None 

138 self._controls = None 

139 self._lines = None 

140 

141 def bind_state(self, state): 

142 Element.bind_state(self, state) 

143 self.talkie_connect( 

144 state, 

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

146 self.update) 

147 

148 def set_parent(self, parent): 

149 self._parent = parent 

150 self._parent.add_panel( 

151 self.get_title_label(), 

152 self._get_controls(), 

153 visible=True, 

154 title_controls=[ 

155 self.get_title_control_remove(), 

156 self.get_title_control_visible()]) 

157 

158 self.talkie_connect( 

159 self._parent.state, 

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

161 self.update_clipping) 

162 

163 self.update() 

164 self.update_clipping() 

165 

166 def unset_parent(self): 

167 self.unbind_state() 

168 if self._parent: 

169 if self._lines: 

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

171 self._lines = None 

172 

173 if self._controls: 

174 self._parent.remove_panel(self._controls) 

175 self._controls = None 

176 

177 self._parent.update_view() 

178 self._parent = None 

179 

180 def update(self, *args): 

181 state = self._state 

182 if not state.visible and self._lines: 

183 self._parent.remove_actor(self._lines.actor) 

184 

185 if state.visible: 

186 if not self._lines: 

187 self._lines = GSHHGPipe( 

188 dataset=state.dataset, resolution=state.resolution) 

189 

190 self._parent.add_actor(self._lines.actor) 

191 self._lines.set_resolution(state.dataset, state.resolution) 

192 self._lines.set_opacity(state.opacity) 

193 self._lines.set_color(state.color) 

194 self._lines.set_line_width(state.line_width) 

195 

196 self._parent.update_view() 

197 

198 def update_clipping(self, *args): 

199 if self._state.visible and self._lines: 

200 cam = self._parent.camera_params[0] 

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

202 self._lines.set_clipping_plane(origin, cam) 

203 

204 def _get_controls(self): 

205 if not self._controls: 

206 from ..state import state_bind_combobox, \ 

207 state_bind_slider, state_bind_combobox_color 

208 

209 frame = qw.QFrame() 

210 layout = qw.QGridLayout() 

211 frame.setLayout(layout) 

212 

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

214 

215 cb = common.string_choices_to_combobox(GSHHGResolutionChoice) 

216 layout.addWidget(cb, 0, 1) 

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

218 

219 # opacity 

220 

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

222 

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

224 slider.setSizePolicy( 

225 qw.QSizePolicy( 

226 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

227 slider.setMinimum(0) 

228 slider.setMaximum(1000) 

229 layout.addWidget(slider, 1, 1) 

230 

231 state_bind_slider( 

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

233 

234 # color 

235 

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

237 

238 cb = common.strings_to_combobox( 

239 ['black', 'white', 'blue', 'red']) 

240 

241 layout.addWidget(cb, 2, 1) 

242 state_bind_combobox_color( 

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

244 

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

246 

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

248 slider.setSizePolicy( 

249 qw.QSizePolicy( 

250 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

251 slider.setMinimum(0) 

252 slider.setMaximum(100) 

253 layout.addWidget(slider, 3, 1) 

254 state_bind_slider( 

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

256 

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

258 

259 self._controls = frame 

260 

261 return self._controls 

262 

263 

264__all__ = [ 

265 'GSHHGElement', 

266 'GSHHGState']