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.talkie_connect(state, ['visible', 'color'], self.update)
133 def set_parent(self, parent):
134 Element.set_parent(self, parent)
136 self._parent.add_panel(
137 self.get_title_label(),
138 self._get_controls(),
139 visible=False,
140 title_controls=[
141 self.get_title_control_visible()])
143 self.talkie_connect(
144 self._parent.state, ['distance', 'lat', 'lon'], self.update)
146 self.update()
148 def unset_parent(self):
149 self.unbind_state()
150 if self._parent:
151 if self._crosshair:
152 self._parent.remove_actor(self._crosshair.actor)
153 self._crosshair = None
155 if self._controls:
156 self._parent.remove_panel(self._controls)
157 self._controls = None
159 self._parent.update_view()
160 self._parent = None
162 def update(self, *args):
163 state = self._state
164 pstate = self._parent.state
166 if state.visible:
167 if not self._crosshair:
168 self._crosshair = Crosshair()
169 for actor in self._crosshair.get_actors():
170 self._parent.add_actor(actor)
172 size = pstate.distance * 100.*1000.
173 self._crosshair.set_geometry(
174 pstate.lat, pstate.lon, pstate.depth, size)
175 self._crosshair.set_color(state.color)
177 else:
178 if self._crosshair:
179 for actor in self._crosshair.get_actors():
180 self._parent.remove_actor(actor)
182 self._crosshair = None
184 self._parent.update_view()
186 def _get_controls(self):
187 if not self._controls:
188 from ..state import state_bind_combobox_color
190 frame = qw.QFrame()
191 layout = qw.QGridLayout()
192 frame.setLayout(layout)
194 # color
196 layout.addWidget(qw.QLabel('Color'), 0, 0)
198 cb = common.strings_to_combobox(
199 ['black', 'white', 'scarletred2'])
201 layout.addWidget(cb, 0, 1)
202 state_bind_combobox_color(self, self._state, 'color', cb)
204 layout.addWidget(qw.QFrame(), 2, 0, 1, 2)
206 self._controls = frame
208 return self._controls
211__all__ = [
212 'CrosshairElement',
213 'CrosshairState']