1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6from __future__ import absolute_import, print_function, division
8import numpy as num
9import vtk
11from pyrocko.guts import Bool, StringChoice, Float
12from pyrocko.gui.qt_compat import qw, qc
13from pyrocko.color import Color
16from pyrocko.gui import vtk_util
17from .. import common
18from .base import Element, ElementState
20guts_prefix = 'sparrow'
23class CoastlineResolutionChoice(StringChoice):
24 choices = [
25 'crude',
26 'low',
27 'intermediate',
28 'high',
29 'full']
32class CoastlinesPipe(object):
33 def __init__(self, resolution='low'):
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)
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)
48 actor = vtk.vtkActor()
49 actor.SetMapper(self.mapper)
51 prop = actor.GetProperty()
52 prop.SetDiffuseColor(1, 1, 1)
54 self.prop = prop
55 self.actor = actor
57 def set_resolution(self, resolution):
58 assert resolution in CoastlineResolutionChoice.choices
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)
66 from pyrocko.dataset.gshhg import GSHHG
67 g = getattr(GSHHG, resolution)()
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)
76 lines.append(poly.points)
78 self._polyline_grid[resolution] = vtk_util.make_multi_polyline(
79 lines_latlon=lines, depth=-200.)
81 if pb:
82 pb.set_status(mess, 100, can_abort=False)
84 vtk_util.vtk_set_input(self.mapper, self._polyline_grid[resolution])
86 def set_opacity(self, opacity):
87 opacity = float(opacity)
88 if self._opacity != opacity:
89 self.prop.SetOpacity(opacity)
90 self._opacity = opacity
92 def set_color(self, color):
93 if self._color != color:
94 self.prop.SetDiffuseColor(color.rgb)
95 self._color = color
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
103 def set_clipping_plane(self, origin, normal):
104 self.plane.SetOrigin(*origin)
105 self.plane.SetNormal(*normal)
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)
115 def create(self):
116 element = CoastlinesElement()
117 return element
120class CoastlinesElement(Element):
122 def __init__(self):
123 Element.__init__(self)
124 self._parent = None
125 self._controls = None
126 self._coastlines = None
128 def get_name(self):
129 return 'Coastlines'
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)
136 def unbind_state(self):
137 self._listeners = []
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()])
149 for var in ['lat', 'lon', 'depth', 'distance', 'azimuth', 'dip']:
150 self.register_state_listener3(
151 self.update_clipping, self._parent.state, var)
153 self.update()
154 self.update_clipping()
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
163 if self._controls:
164 self._parent.remove_panel(self._controls)
165 self._controls = None
167 self._parent.update_view()
168 self._parent = None
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)
175 if state.visible:
176 if not self._coastlines:
177 self._coastlines = CoastlinesPipe(resolution=state.resolution)
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)
185 self._parent.update_view()
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)
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
198 frame = qw.QFrame()
199 layout = qw.QGridLayout()
200 frame.setLayout(layout)
202 layout.addWidget(qw.QLabel('Resolution'), 0, 0)
204 cb = common.string_choices_to_combobox(CoastlineResolutionChoice)
205 layout.addWidget(cb, 0, 1)
206 state_bind_combobox(self, self._state, 'resolution', cb)
208 # opacity
210 layout.addWidget(qw.QLabel('Opacity'), 1, 0)
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)
220 state_bind_slider(
221 self, self._state, 'opacity', slider, factor=0.001)
223 # color
225 layout.addWidget(qw.QLabel('Color'), 2, 0)
227 cb = common.strings_to_combobox(
228 ['black', 'white'])
230 layout.addWidget(cb, 2, 1)
231 state_bind_combobox_color(
232 self, self._state, 'color', cb)
234 layout.addWidget(qw.QLabel('Line width'), 3, 0)
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)
246 layout.addWidget(qw.QFrame(), 5, 0, 1, 2)
248 self._controls = frame
250 return self._controls
253__all__ = [
254 'CoastlinesElement',
255 'CoastlinesState']