1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6import numpy as num
7import vtk
9from pyrocko.guts import Bool, StringChoice, Float
10from pyrocko.gui.qt_compat import qw, qc
11from pyrocko.color import Color
14from pyrocko.gui import vtk_util
15from .. import common
16from .base import Element, ElementState
17from pyrocko.dataset.gshhg import Coastlines, Rivers, Borders
20guts_prefix = 'sparrow'
22gshhg_dataset_mapping = {
23 'coastlines': Coastlines,
24 'rivers': Rivers,
25 'borders': Borders,
26}
29class GSHHGDatasetChoice(StringChoice):
30 choices = ['coastlines', 'borders', 'rivers']
33class GSHHGResolutionChoice(StringChoice):
34 choices = [
35 'crude',
36 'low',
37 'intermediate',
38 'high',
39 'full']
42class GSHHGPipe(object):
43 def __init__(self, dataset, resolution='low'):
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)
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)
58 actor = vtk.vtkActor()
59 actor.SetMapper(self.mapper)
61 prop = actor.GetProperty()
62 prop.SetDiffuseColor(1, 1, 1)
64 self.prop = prop
65 self.actor = actor
67 def set_resolution(self, dataset, resolution):
68 assert resolution in GSHHGResolutionChoice.choices
69 assert dataset in GSHHGDatasetChoice.choices
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)
77 dataset = gshhg_dataset_mapping[dataset]
79 g = getattr(dataset, resolution)()
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)
88 lines.append(poly.points)
90 self._polyline_grid[resolution] = vtk_util.make_multi_polyline(
91 lines_latlon=lines, depth=-200.)
93 if pb:
94 pb.set_status(mess, 100, can_abort=False)
96 vtk_util.vtk_set_input(self.mapper, self._polyline_grid[resolution])
98 def set_opacity(self, opacity):
99 opacity = float(opacity)
100 if self._opacity != opacity:
101 self.prop.SetOpacity(opacity)
102 self._opacity = opacity
104 def set_color(self, color):
105 if self._color != color:
106 self.prop.SetDiffuseColor(color.rgb)
107 self._color = color
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
115 def set_clipping_plane(self, origin, normal):
116 self.plane.SetOrigin(*origin)
117 self.plane.SetNormal(*normal)
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)
128 def create(self):
129 element = GSHHGElement()
130 return element
133class GSHHGElement(Element):
135 def __init__(self):
136 Element.__init__(self)
137 self._parent = None
138 self._controls = None
139 self._lines = None
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)
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()])
158 self.talkie_connect(
159 self._parent.state,
160 ['lat', 'lon', 'depth', 'distance', 'azimuth', 'dip'],
161 self.update_clipping)
163 self.update()
164 self.update_clipping()
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
173 if self._controls:
174 self._parent.remove_panel(self._controls)
175 self._controls = None
177 self._parent.update_view()
178 self._parent = None
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)
185 if state.visible:
186 if not self._lines:
187 self._lines = GSHHGPipe(
188 dataset=state.dataset, resolution=state.resolution)
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)
196 self._parent.update_view()
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)
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
209 frame = qw.QFrame()
210 layout = qw.QGridLayout()
211 frame.setLayout(layout)
213 layout.addWidget(qw.QLabel('Resolution'), 0, 0)
215 cb = common.string_choices_to_combobox(GSHHGResolutionChoice)
216 layout.addWidget(cb, 0, 1)
217 state_bind_combobox(self, self._state, 'resolution', cb)
219 # opacity
221 layout.addWidget(qw.QLabel('Opacity'), 1, 0)
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)
231 state_bind_slider(
232 self, self._state, 'opacity', slider, factor=0.001)
234 # color
236 layout.addWidget(qw.QLabel('Color'), 2, 0)
238 cb = common.strings_to_combobox(
239 ['black', 'white', 'blue', 'red'])
241 layout.addWidget(cb, 2, 1)
242 state_bind_combobox_color(
243 self, self._state, 'color', cb)
245 layout.addWidget(qw.QLabel('Line width'), 3, 0)
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)
257 layout.addWidget(qw.QFrame(), 5, 0, 1, 2)
259 self._controls = frame
261 return self._controls
264__all__ = [
265 'GSHHGElement',
266 'GSHHGState']