1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6from __future__ import absolute_import, print_function, division 

7 

8import math 

9 

10from pyrocko.guts import Int, StringChoice, Bool, Float 

11from pyrocko.gui.qt_compat import qw, qc 

12 

13from .. import common 

14from pyrocko.gui.vtk_util import TrimeshPipe 

15from .base import Element, ElementState 

16from pyrocko import icosphere 

17from pyrocko.geometry import r2d 

18from pyrocko.color import Color 

19 

20km = 1000. 

21 

22guts_prefix = 'sparrow' 

23 

24 

25class IcosphereBaseChoice(StringChoice): 

26 choices = ['icosahedron', 'tetrahedron', 'tcube'] 

27 

28 

29class IcosphereKindChoice(StringChoice): 

30 choices = ['kind1', 'kind2'] 

31 

32 

33class IcosphereState(ElementState): 

34 base = IcosphereBaseChoice.T(default='icosahedron') 

35 kind = IcosphereKindChoice.T(default='kind1') 

36 level = Int.T(default=0) 

37 visible = Bool.T(default=True) 

38 smooth = Bool.T(default=False) 

39 color = Color.T(default=Color.D('aluminium5')) 

40 

41 ambient = Float.T(default=0.0) 

42 diffuse = Float.T(default=1.0) 

43 specular = Float.T(default=0.0) 

44 

45 opacity = Float.T(default=1.0) 

46 depth = Float.T(default=30.0*km) 

47 

48 def create(self): 

49 element = IcosphereElement() 

50 return element 

51 

52 

53class IcosphereElement(Element): 

54 

55 def __init__(self): 

56 Element.__init__(self) 

57 self._mesh = None 

58 self._controls = None 

59 self._params = None 

60 

61 def get_name(self): 

62 return 'Icosphere' 

63 

64 def bind_state(self, state): 

65 Element.bind_state(self, state) 

66 for var in ['visible', 'level', 'base', 'kind', 'smooth', 'color', 

67 'ambient', 'diffuse', 'specular', 'depth', 'opacity']: 

68 

69 self.register_state_listener3(self.update, state, var) 

70 

71 def set_parent(self, parent): 

72 Element.set_parent(self, parent) 

73 self.register_state_listener3(self.update, self._parent.state, 'dip') 

74 

75 self._parent.add_panel( 

76 self.get_name(), 

77 self._get_controls(), 

78 visible=True, 

79 title_controls=[ 

80 self.get_title_control_remove(), 

81 self.get_title_control_visible()]) 

82 

83 self.update() 

84 

85 def unset_parent(self): 

86 self.unbind_state() 

87 if self._parent: 

88 if self._mesh: 

89 self._parent.remove_actor(self._mesh.actor) 

90 self._mesh = None 

91 

92 if self._controls: 

93 self._parent.remove_panel(self._controls) 

94 self._controls = None 

95 

96 self._parent.update_view() 

97 self._parent = None 

98 

99 def update(self, *args): 

100 state = self._state 

101 

102 params = state.level, state.base, state.kind, state.smooth 

103 

104 if self._mesh and (params != self._params or not state.visible): 

105 self._parent.remove_actor(self._mesh.actor) 

106 self._mesh = None 

107 

108 if state.visible and not self._mesh: 

109 vertices, faces = icosphere.sphere( 

110 state.level, state.base, state.kind, radius=1.0, 

111 triangulate=False) 

112 

113 self._vertices = vertices 

114 self._depth = 0.0 

115 

116 self._mesh = TrimeshPipe(vertices, faces, smooth=state.smooth) 

117 self._params = params 

118 

119 self._parent.add_actor(self._mesh.actor) 

120 

121 if self._parent.state.distance < 2.0: 

122 angle = 180. - math.acos(self._parent.state.distance / 2.0)*r2d 

123 

124 opacity = min( 

125 1.0, 

126 max(0., (angle+5. - self._parent.state.dip) / 10.)) 

127 else: 

128 opacity = 1.0 

129 

130 opacity *= state.opacity 

131 

132 if self._mesh: 

133 if self._depth != state.depth: 

134 radius = (self._parent.planet_radius - state.depth) \ 

135 / self._parent.planet_radius 

136 

137 self._mesh.set_vertices(self._vertices * radius) 

138 self._depth = state.depth 

139 

140 self._mesh.set_opacity(opacity) 

141 self._mesh.set_color(state.color) 

142 self._mesh.set_ambient(state.ambient) 

143 self._mesh.set_diffuse(state.diffuse) 

144 self._mesh.set_specular(state.specular) 

145 

146 self._parent.update_view() 

147 

148 def _get_controls(self): 

149 state = self._state 

150 if not self._controls: 

151 from ..state import state_bind_slider, \ 

152 state_bind_combobox, state_bind_checkbox, \ 

153 state_bind_combobox_color, state_bind_lineedit 

154 

155 frame = qw.QFrame() 

156 layout = qw.QGridLayout() 

157 frame.setLayout(layout) 

158 

159 slider = qw.QSlider(qc.Qt.Horizontal) 

160 slider.setSizePolicy( 

161 qw.QSizePolicy( 

162 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

163 slider.setMinimum(0) 

164 slider.setMaximum(5) 

165 slider.setSingleStep(1) 

166 slider.setPageStep(1) 

167 

168 layout.addWidget(qw.QLabel('Level'), 0, 0) 

169 layout.addWidget(slider, 0, 1) 

170 

171 state_bind_slider(self, state, 'level', slider, dtype=int) 

172 

173 cb = common.string_choices_to_combobox(IcosphereBaseChoice) 

174 layout.addWidget(qw.QLabel('Base'), 1, 0) 

175 layout.addWidget(cb, 1, 1) 

176 state_bind_combobox(self, state, 'base', cb) 

177 

178 cb = common.string_choices_to_combobox(IcosphereKindChoice) 

179 layout.addWidget(qw.QLabel('Kind'), 2, 0) 

180 layout.addWidget(cb, 2, 1) 

181 state_bind_combobox(self, state, 'kind', cb) 

182 

183 layout.addWidget(qw.QLabel('Color'), 3, 0) 

184 

185 cb = common.strings_to_combobox( 

186 ['black', 'aluminium6', 'aluminium5', 'aluminium4', 

187 'aluminium3', 'aluminium2', 'aluminium1', 'white', 

188 'scarletred2', 'orange2', 'skyblue2', 'plum2']) 

189 

190 layout.addWidget(cb, 3, 1) 

191 state_bind_combobox_color( 

192 self, self._state, 'color', cb) 

193 

194 def add_slider(title, param, irow): 

195 layout.addWidget(qw.QLabel(title), irow, 0) 

196 

197 slider = qw.QSlider(qc.Qt.Horizontal) 

198 slider.setSizePolicy( 

199 qw.QSizePolicy( 

200 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

201 slider.setMinimum(0) 

202 slider.setMaximum(1000) 

203 layout.addWidget(slider, irow, 1) 

204 

205 state_bind_slider( 

206 self, state, param, slider, factor=0.001) 

207 

208 add_slider('Opacity', 'opacity', 4) 

209 add_slider('Ambient', 'ambient', 5) 

210 add_slider('Diffuse', 'diffuse', 6) 

211 add_slider('Specular', 'specular', 7) 

212 

213 cb = qw.QCheckBox('Smooth') 

214 layout.addWidget(cb, 8, 1) 

215 state_bind_checkbox(self, state, 'smooth', cb) 

216 

217 layout.addWidget(qw.QLabel('Depth [km]'), 9, 0) 

218 le = qw.QLineEdit() 

219 layout.addWidget(le, 9, 1) 

220 state_bind_lineedit( 

221 self, state, 'depth', le, 

222 from_string=lambda s: float(s)*1000., 

223 to_string=lambda v: str(v/1000.)) 

224 

225 layout.addWidget(qw.QFrame(), 10, 0, 1, 2) 

226 

227 self._controls = frame 

228 

229 return self._controls 

230 

231 

232__all__ = [ 

233 'IcosphereElement', 

234 'IcosphereState', 

235 'IcosphereKindChoice', 

236 'IcosphereBaseChoice']