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.register_state_listener3(self.update, state, 'visible') 

132 self.register_state_listener3(self.update, state, 'color') 

133 

134 def set_parent(self, parent): 

135 Element.set_parent(self, parent) 

136 

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

143 

144 for var in ['distance', 'lat', 'lon']: 

145 self.register_state_listener3(self.update, self._parent.state, var) 

146 

147 self.update() 

148 

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 

155 

156 if self._controls: 

157 self._parent.remove_panel(self._controls) 

158 self._controls = None 

159 

160 self._parent.update_view() 

161 self._parent = None 

162 

163 def update(self, *args): 

164 state = self._state 

165 pstate = self._parent.state 

166 

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) 

172 

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) 

177 

178 else: 

179 if self._crosshair: 

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

181 self._parent.remove_actor(actor) 

182 

183 self._crosshair = None 

184 

185 self._parent.update_view() 

186 

187 def _get_controls(self): 

188 if not self._controls: 

189 from ..state import state_bind_combobox_color 

190 

191 frame = qw.QFrame() 

192 layout = qw.QGridLayout() 

193 frame.setLayout(layout) 

194 

195 # color 

196 

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

198 

199 cb = common.strings_to_combobox( 

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

201 

202 layout.addWidget(cb, 0, 1) 

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

204 

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

206 

207 self._controls = frame 

208 

209 return self._controls 

210 

211 

212__all__ = [ 

213 'CrosshairElement', 

214 'CrosshairState']