1import vtk
2import numpy as num
4from pyrocko.gui.qt_compat import qw
5from pyrocko import orthodrome as od
6from pyrocko.gui import vtk_util
7from pyrocko.guts import Bool
8from pyrocko.color import Color
9from .. import common
11from .base import Element, ElementState
14def cross3d_flat(a=1., b=0.5):
15 lines_ned = []
16 for i in range(2):
17 for s in (-1., 1.):
18 line = num.zeros((2, 3))
19 line[0, i] = s*a
20 line[1, i] = s*b
21 lines_ned.append(line)
23 return lines_ned
26def cross3d(a=1., b=0.5):
27 lines_ned = []
28 for i in range(3):
29 for s in (-1., 1.):
30 line = num.zeros((2, 3))
31 line[0, i] = s*a
32 line[1, i] = s*b
33 lines_ned.append(line)
35 return lines_ned
38class Crosshair(object):
39 def __init__(self):
41 self.mapper_surface = vtk.vtkDataSetMapper()
42 self.mapper_position = vtk.vtkDataSetMapper()
44 self.actor_surface = vtk.vtkActor()
45 self.actor_surface.SetMapper(self.mapper_surface)
47 self.actor_position = vtk.vtkActor()
48 self.actor_position.SetMapper(self.mapper_position)
50 self._color = None
51 self.set_color(Color('white'))
53 def get_actors(self):
54 return [self.actor_surface, self.actor_position]
56 def make_multi_polyline(self, lat, lon, depth, size):
57 lines_ned = cross3d_flat()
58 lines_lld = []
59 for line_ned in lines_ned:
60 line_ned_sized = size * line_ned
61 line_lld = num.zeros(line_ned.shape)
62 line_lld[:, :2] = num.vstack(
63 od.ne_to_latlon(
64 lat, lon, line_ned_sized[:, 0], line_ned_sized[:, 1])).T
66 line_lld[:, 2] = line_ned_sized[:, 2]
67 lines_lld.append(line_lld)
69 mpl_surface = vtk_util.make_multi_polyline(
70 lines_latlondepth=lines_lld)
72 lines_ned = cross3d()
73 lines_lld = []
74 for line_ned in lines_ned:
75 line_ned_sized = size * line_ned
76 line_lld = num.zeros(line_ned.shape)
77 line_lld[:, :2] = num.vstack(
78 od.ne_to_latlon(
79 lat, lon, line_ned_sized[:, 0], line_ned_sized[:, 1])).T
81 line_lld[:, 2] = depth + line_ned_sized[:, 2]
82 lines_lld.append(line_lld)
84 mpl_position = vtk_util.make_multi_polyline(
85 lines_latlondepth=lines_lld)
87 return [mpl_surface, mpl_position]
89 def set_geometry(self, lat, lon, depth, size):
90 mpl_surface, mpl_position = self.make_multi_polyline(
91 lat, lon, depth, size)
92 vtk_util.vtk_set_input(self.mapper_surface, mpl_surface)
93 vtk_util.vtk_set_input(self.mapper_position, mpl_position)
94 self.actor_surface.GetProperty().SetOpacity(
95 min(1.0, abs(depth) / size) * 0.5)
97 def set_color(self, color):
98 if self._color is None or self._color != color:
99 for actor in self.get_actors():
100 prop = actor.GetProperty()
101 prop.SetDiffuseColor(color.rgb)
103 self._color = color
106class CrosshairState(ElementState):
107 visible = Bool.T(default=False)
108 color = Color.T(default=Color.D('white'))
110 def __init__(self, *args, **kwargs):
111 ElementState.__init__(self, *args, **kwargs)
112 self.is_connected = False
114 def create(self):
115 element = CrosshairElement()
116 return element
119class CrosshairElement(Element):
121 def __init__(self):
122 Element.__init__(self)
123 self._controls = None
124 self._crosshair = None
126 def get_name(self):
127 return 'Crosshair'
129 def bind_state(self, state):
130 Element.bind_state(self, state)
131 self.register_state_listener3(self.update, state, 'visible')
132 self.register_state_listener3(self.update, state, 'color')
134 def set_parent(self, parent):
135 Element.set_parent(self, parent)
137 self._parent.add_panel(
138 self.get_name(),
139 self._get_controls(),
140 visible=False,
141 title_controls=[
142 self.get_title_control_visible()])
144 for var in ['distance', 'lat', 'lon']:
145 self.register_state_listener3(self.update, self._parent.state, var)
147 self.update()
149 def unset_parent(self):
150 self.unbind_state()
151 if self._parent:
152 if self._crosshair:
153 self._parent.remove_actor(self._crosshair.actor)
154 self._crosshair = None
156 if self._controls:
157 self._parent.remove_panel(self._controls)
158 self._controls = None
160 self._parent.update_view()
161 self._parent = None
163 def update(self, *args):
164 state = self._state
165 pstate = self._parent.state
167 if state.visible:
168 if not self._crosshair:
169 self._crosshair = Crosshair()
170 for actor in self._crosshair.get_actors():
171 self._parent.add_actor(actor)
173 size = pstate.distance * 100.*1000.
174 self._crosshair.set_geometry(
175 pstate.lat, pstate.lon, pstate.depth, size)
176 self._crosshair.set_color(state.color)
178 else:
179 if self._crosshair:
180 for actor in self._crosshair.get_actors():
181 self._parent.remove_actor(actor)
183 self._crosshair = None
185 self._parent.update_view()
187 def _get_controls(self):
188 if not self._controls:
189 from ..state import state_bind_combobox_color
191 frame = qw.QFrame()
192 layout = qw.QGridLayout()
193 frame.setLayout(layout)
195 # color
197 layout.addWidget(qw.QLabel('Color'), 0, 0)
199 cb = common.strings_to_combobox(
200 ['black', 'white', 'scarletred2'])
202 layout.addWidget(cb, 0, 1)
203 state_bind_combobox_color(self, self._state, 'color', cb)
205 layout.addWidget(qw.QFrame(), 2, 0, 1, 2)
207 self._controls = frame
209 return self._controls
212__all__ = [
213 'CrosshairElement',
214 'CrosshairState']