1import vtk 

2import numpy as num 

3 

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 

10 

11from .base import Element, ElementState 

12 

13 

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) 

22 

23 return lines_ned 

24 

25 

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) 

34 

35 return lines_ned 

36 

37 

38class Crosshair(object): 

39 def __init__(self): 

40 

41 self.mapper_surface = vtk.vtkDataSetMapper() 

42 self.mapper_position = vtk.vtkDataSetMapper() 

43 

44 self.actor_surface = vtk.vtkActor() 

45 self.actor_surface.SetMapper(self.mapper_surface) 

46 

47 self.actor_position = vtk.vtkActor() 

48 self.actor_position.SetMapper(self.mapper_position) 

49 

50 self._color = None 

51 self.set_color(Color('white')) 

52 

53 def get_actors(self): 

54 return [self.actor_surface, self.actor_position] 

55 

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 

65 

66 line_lld[:, 2] = line_ned_sized[:, 2] 

67 lines_lld.append(line_lld) 

68 

69 mpl_surface = vtk_util.make_multi_polyline( 

70 lines_latlondepth=lines_lld) 

71 

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 

80 

81 line_lld[:, 2] = depth + line_ned_sized[:, 2] 

82 lines_lld.append(line_lld) 

83 

84 mpl_position = vtk_util.make_multi_polyline( 

85 lines_latlondepth=lines_lld) 

86 

87 return [mpl_surface, mpl_position] 

88 

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) 

96 

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) 

102 

103 self._color = color 

104 

105 

106class CrosshairState(ElementState): 

107 visible = Bool.T(default=False) 

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

109 

110 def __init__(self, *args, **kwargs): 

111 ElementState.__init__(self, *args, **kwargs) 

112 self.is_connected = False 

113 

114 def create(self): 

115 element = CrosshairElement() 

116 return element 

117 

118 

119class CrosshairElement(Element): 

120 

121 def __init__(self): 

122 Element.__init__(self) 

123 self._controls = None 

124 self._crosshair = None 

125 

126 def get_name(self): 

127 return 'Crosshair' 

128 

129 def bind_state(self, state): 

130 Element.bind_state(self, state) 

131 self.talkie_connect(state, ['visible', 'color'], self.update) 

132 

133 def set_parent(self, parent): 

134 Element.set_parent(self, parent) 

135 

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()]) 

142 

143 self.talkie_connect( 

144 self._parent.state, ['distance', 'lat', 'lon'], self.update) 

145 

146 self.update() 

147 

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 

154 

155 if self._controls: 

156 self._parent.remove_panel(self._controls) 

157 self._controls = None 

158 

159 self._parent.update_view() 

160 self._parent = None 

161 

162 def update(self, *args): 

163 state = self._state 

164 pstate = self._parent.state 

165 

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) 

171 

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) 

176 

177 else: 

178 if self._crosshair: 

179 for actor in self._crosshair.get_actors(): 

180 self._parent.remove_actor(actor) 

181 

182 self._crosshair = None 

183 

184 self._parent.update_view() 

185 

186 def _get_controls(self): 

187 if not self._controls: 

188 from ..state import state_bind_combobox_color 

189 

190 frame = qw.QFrame() 

191 layout = qw.QGridLayout() 

192 frame.setLayout(layout) 

193 

194 # color 

195 

196 layout.addWidget(qw.QLabel('Color'), 0, 0) 

197 

198 cb = common.strings_to_combobox( 

199 ['black', 'white', 'scarletred2']) 

200 

201 layout.addWidget(cb, 0, 1) 

202 state_bind_combobox_color(self, self._state, 'color', cb) 

203 

204 layout.addWidget(qw.QFrame(), 2, 0, 1, 2) 

205 

206 self._controls = frame 

207 

208 return self._controls 

209 

210 

211__all__ = [ 

212 'CrosshairElement', 

213 'CrosshairState']