pygmi 2.2.7__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygmi-2.2.7/LICENSE.txt +623 -0
- pygmi-2.2.7/MANIFEST.in +7 -0
- pygmi-2.2.7/PKG-INFO +47 -0
- pygmi-2.2.7/README.md +55 -0
- pygmi-2.2.7/README.rst +20 -0
- pygmi-2.2.7/log.txt +242 -0
- pygmi-2.2.7/pygmi/__init__.py +22 -0
- pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
- pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
- pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
- pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
- pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
- pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
- pygmi-2.2.7/pygmi/clust/menu.py +139 -0
- pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
- pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
- pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
- pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
- pygmi-2.2.7/pygmi/images/Help.png +0 -0
- pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
- pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
- pygmi-2.2.7/pygmi/images/delete.png +0 -0
- pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
- pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
- pygmi-2.2.7/pygmi/images/logo256.png +0 -0
- pygmi-2.2.7/pygmi/images/pointer.png +0 -0
- pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
- pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
- pygmi-2.2.7/pygmi/main.py +1037 -0
- pygmi-2.2.7/pygmi/menu_default.py +327 -0
- pygmi-2.2.7/pygmi/misc.py +147 -0
- pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
- pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
- pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
- pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
- pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
- pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
- pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
- pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
- pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
- pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
- pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
- pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
- pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
- pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
- pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
- pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
- pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
- pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
- pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
- pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
- pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
- pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
- pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
- pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
- pygmi-2.2.7/pygmi/raster/menu.py +307 -0
- pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
- pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
- pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
- pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
- pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
- pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
- pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
- pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
- pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
- pygmi-2.2.7/pygmi/seis/menu.py +136 -0
- pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
- pygmi-2.2.7/pygmi/test/__init__.py +6 -0
- pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
- pygmi-2.2.7/pygmi/test/tests.py +39 -0
- pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
- pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
- pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
- pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
- pygmi-2.2.7/pygmi/vector/menu.py +127 -0
- pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
- pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
- pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
- pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
- pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
- pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
- pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
- pygmi-2.2.7/quickstart.py +35 -0
- pygmi-2.2.7/setup.cfg +8 -0
- pygmi-2.2.7/setup.py +80 -0
|
@@ -0,0 +1,751 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# Name: beachball.py (part of PyGMI)
|
|
3
|
+
#
|
|
4
|
+
# Author: Patrick Cole
|
|
5
|
+
# E-Mail: pcole@geoscience.org.za
|
|
6
|
+
#
|
|
7
|
+
# Copyright: (c) 2013 Council for Geoscience
|
|
8
|
+
# Licence: GPL-3.0
|
|
9
|
+
#
|
|
10
|
+
# This file is part of PyGMI
|
|
11
|
+
#
|
|
12
|
+
# PyGMI is free software: you can redistribute it and/or modify
|
|
13
|
+
# it under the terms of the GNU General Public License as published by
|
|
14
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
15
|
+
# (at your option) any later version.
|
|
16
|
+
#
|
|
17
|
+
# PyGMI is distributed in the hope that it will be useful,
|
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20
|
+
# GNU General Public License for more details.
|
|
21
|
+
#
|
|
22
|
+
# You should have received a copy of the GNU General Public License
|
|
23
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
# -----------------------------------------------------------------------------
|
|
25
|
+
# Licence for original ModestImage code (modified version below)
|
|
26
|
+
# ModestImage
|
|
27
|
+
# Copyright (c) 2013 Chris Beaumont
|
|
28
|
+
#
|
|
29
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
30
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
31
|
+
# to deal in the Software without restriction, including without limitation
|
|
32
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
33
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
34
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
35
|
+
#
|
|
36
|
+
# The above copyright notice and this permission notice shall be included in
|
|
37
|
+
# all copies or substantial portions of the Software.
|
|
38
|
+
#
|
|
39
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
40
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
41
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
42
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
43
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
44
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
45
|
+
# DEALINGS IN THE SOFTWARE.
|
|
46
|
+
# -----------------------------------------------------------------------------
|
|
47
|
+
""" Plot fault plane solutions.
|
|
48
|
+
The code below is translated from bb.m written by Andy Michael and Oliver Boyd
|
|
49
|
+
at http://www.ceri.memphis.edu/people/olboyd/Software/Software.html"""
|
|
50
|
+
|
|
51
|
+
import numpy as np
|
|
52
|
+
import numexpr as ne
|
|
53
|
+
from PyQt4 import QtGui
|
|
54
|
+
import matplotlib.cm as cm
|
|
55
|
+
import matplotlib.pyplot as plt
|
|
56
|
+
from matplotlib.backends.backend_qt4agg import FigureCanvas
|
|
57
|
+
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as \
|
|
58
|
+
NavigationToolbar
|
|
59
|
+
import os
|
|
60
|
+
from matplotlib import patches
|
|
61
|
+
import osgeo.ogr as ogr
|
|
62
|
+
import osgeo.osr as osr
|
|
63
|
+
import scipy.spatial.distance as sdist
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class MyMplCanvas(FigureCanvas):
|
|
67
|
+
"""Canvas for the actual plot"""
|
|
68
|
+
def __init__(self, parent):
|
|
69
|
+
fig = plt.figure()
|
|
70
|
+
super(MyMplCanvas, self).__init__(fig)
|
|
71
|
+
|
|
72
|
+
# figure stuff
|
|
73
|
+
self.htype = 'Linear'
|
|
74
|
+
self.cbar = cm.jet
|
|
75
|
+
self.data = []
|
|
76
|
+
self.gmode = None
|
|
77
|
+
self.argb = [None, None, None]
|
|
78
|
+
self.hhist = [None, None, None]
|
|
79
|
+
self.hband = [None, None, None]
|
|
80
|
+
self.htxt = [None, None, None]
|
|
81
|
+
self.patches = []
|
|
82
|
+
self.lines = []
|
|
83
|
+
self.image = None
|
|
84
|
+
self.cnt = None
|
|
85
|
+
self.cntf = None
|
|
86
|
+
self.background = None
|
|
87
|
+
self.pwidth = 0.001
|
|
88
|
+
|
|
89
|
+
self.axes = fig.add_subplot(111)
|
|
90
|
+
self.axes.xaxis.set_visible(False)
|
|
91
|
+
self.axes.yaxis.set_visible(False)
|
|
92
|
+
|
|
93
|
+
self.setParent(parent)
|
|
94
|
+
|
|
95
|
+
FigureCanvas.setSizePolicy(self,
|
|
96
|
+
QtGui.QSizePolicy.Expanding,
|
|
97
|
+
QtGui.QSizePolicy.Expanding)
|
|
98
|
+
FigureCanvas.updateGeometry(self)
|
|
99
|
+
|
|
100
|
+
def init_graph(self):
|
|
101
|
+
""" Initialize the graph """
|
|
102
|
+
|
|
103
|
+
self.axes.clear()
|
|
104
|
+
self.axes.set_aspect("equal")
|
|
105
|
+
|
|
106
|
+
maxdiam = self.pwidth*self.data[:, -1].max()
|
|
107
|
+
xmin = self.data[:, 0].min()-maxdiam
|
|
108
|
+
xmax = self.data[:, 0].max()+maxdiam
|
|
109
|
+
ymin = self.data[:, 1].min()-maxdiam
|
|
110
|
+
ymax = self.data[:, 1].max()+maxdiam
|
|
111
|
+
|
|
112
|
+
self.axes.set_xlim((xmin, xmax))
|
|
113
|
+
self.axes.set_ylim((ymin, ymax))
|
|
114
|
+
|
|
115
|
+
self.figure.canvas.draw()
|
|
116
|
+
QtGui.QApplication.processEvents()
|
|
117
|
+
|
|
118
|
+
for idat in self.data:
|
|
119
|
+
pxy = idat[:2]
|
|
120
|
+
np1 = idat[2:-1]
|
|
121
|
+
pwidth = self.pwidth*idat[-1]
|
|
122
|
+
xxx, yyy, xxx2, yyy2 = beachball(np1, pxy[0], pxy[1], pwidth)
|
|
123
|
+
|
|
124
|
+
pvert1 = np.transpose([yyy, xxx])
|
|
125
|
+
pvert0 = np.transpose([xxx2, yyy2])
|
|
126
|
+
|
|
127
|
+
self.axes.add_patch(patches.Polygon(pvert1))
|
|
128
|
+
self.axes.add_patch(patches.Polygon(pvert0, facecolor='none'))
|
|
129
|
+
|
|
130
|
+
self.figure.canvas.draw()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class BeachBall(QtGui.QDialog):
|
|
134
|
+
""" Create shapefiles with beachballs """
|
|
135
|
+
def __init__(self, parent=None):
|
|
136
|
+
super(BeachBall, self).__init__(parent)
|
|
137
|
+
|
|
138
|
+
self.ifile = ""
|
|
139
|
+
self.name = "Beachball: "
|
|
140
|
+
self.ext = ""
|
|
141
|
+
self.pbar = None
|
|
142
|
+
self.parent = parent
|
|
143
|
+
self.indata = {}
|
|
144
|
+
self.outdata = {}
|
|
145
|
+
self.algorithm = 'FPFIT'
|
|
146
|
+
self.nofps = False
|
|
147
|
+
|
|
148
|
+
self.mmc = MyMplCanvas(self)
|
|
149
|
+
self.btn_saveshp = QtGui.QPushButton()
|
|
150
|
+
self.cbox_alg = QtGui.QComboBox()
|
|
151
|
+
self.dsb_dist = QtGui.QDoubleSpinBox()
|
|
152
|
+
|
|
153
|
+
self.setupui()
|
|
154
|
+
|
|
155
|
+
def data_init(self):
|
|
156
|
+
""" data init - entry point into routine """
|
|
157
|
+
if 'Seis' not in self.indata:
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
data = self.indata['Seis']
|
|
161
|
+
|
|
162
|
+
alist = []
|
|
163
|
+
for i in data:
|
|
164
|
+
alist += list(i['F'].keys())
|
|
165
|
+
alist = sorted(set(alist))
|
|
166
|
+
|
|
167
|
+
if len(alist) == 0:
|
|
168
|
+
self.parent.showprocesslog('Error: no Fault Plane Solutions')
|
|
169
|
+
self.nofps = True
|
|
170
|
+
return False
|
|
171
|
+
else:
|
|
172
|
+
self.nofps = False
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
self.cbox_alg.currentIndexChanged.disconnect()
|
|
176
|
+
except TypeError:
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
self.cbox_alg.clear()
|
|
180
|
+
self.cbox_alg.addItems(alist)
|
|
181
|
+
self.algorithm = alist[0]
|
|
182
|
+
|
|
183
|
+
self.cbox_alg.currentIndexChanged.connect(self.change_alg)
|
|
184
|
+
|
|
185
|
+
pwidth = 1.
|
|
186
|
+
|
|
187
|
+
for j in alist:
|
|
188
|
+
tmpxy = []
|
|
189
|
+
tmpmag = []
|
|
190
|
+
for i in data:
|
|
191
|
+
if i['F'].get(j) is not None:
|
|
192
|
+
tmp = [i['1'].longitude,
|
|
193
|
+
i['1'].latitude,
|
|
194
|
+
i['1'].magnitude_1]
|
|
195
|
+
tmpxy.append([tmp[0], tmp[1]])
|
|
196
|
+
tmpmag.append(tmp[2])
|
|
197
|
+
|
|
198
|
+
if len(tmpmag) > 1:
|
|
199
|
+
pwidth = min(sdist.pdist(tmpxy).min()/(2*max(tmpmag)), pwidth)
|
|
200
|
+
|
|
201
|
+
self.dsb_dist.setValue(pwidth)
|
|
202
|
+
|
|
203
|
+
self.change_alg()
|
|
204
|
+
|
|
205
|
+
def setupui(self):
|
|
206
|
+
""" Setup UI """
|
|
207
|
+
hbl_all = QtGui.QHBoxLayout(self)
|
|
208
|
+
mpl_toolbar = NavigationToolbar(self.mmc, self)
|
|
209
|
+
vbl_raster = QtGui.QVBoxLayout()
|
|
210
|
+
label2 = QtGui.QLabel()
|
|
211
|
+
label3 = QtGui.QLabel()
|
|
212
|
+
|
|
213
|
+
self.dsb_dist.setDecimals(4)
|
|
214
|
+
self.dsb_dist.setMinimum(0.0001)
|
|
215
|
+
self.dsb_dist.setSingleStep(0.0001)
|
|
216
|
+
self.dsb_dist.setProperty("value", 0.001)
|
|
217
|
+
|
|
218
|
+
spacer = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
|
|
219
|
+
QtGui.QSizePolicy.Expanding)
|
|
220
|
+
|
|
221
|
+
self.setWindowTitle("Fault Plane Solution (FPS)")
|
|
222
|
+
label2.setText('FPS Algorithm:')
|
|
223
|
+
label3.setText('Width Scale Factor:')
|
|
224
|
+
self.btn_saveshp.setText('Save Shapefile')
|
|
225
|
+
|
|
226
|
+
vbl_raster.addWidget(label2)
|
|
227
|
+
vbl_raster.addWidget(self.cbox_alg)
|
|
228
|
+
vbl_raster.addWidget(label3)
|
|
229
|
+
vbl_raster.addWidget(self.dsb_dist)
|
|
230
|
+
vbl_raster.addItem(spacer)
|
|
231
|
+
vbl_raster.addWidget(self.btn_saveshp)
|
|
232
|
+
vbl_right = QtGui.QVBoxLayout()
|
|
233
|
+
vbl_right.addWidget(self.mmc)
|
|
234
|
+
vbl_right.addWidget(mpl_toolbar)
|
|
235
|
+
hbl_all.addLayout(vbl_raster)
|
|
236
|
+
hbl_all.addLayout(vbl_right)
|
|
237
|
+
|
|
238
|
+
self.btn_saveshp.clicked.connect(self.save_shp)
|
|
239
|
+
self.dsb_dist.valueChanged.connect(self.change_alg)
|
|
240
|
+
|
|
241
|
+
def save_shp(self):
|
|
242
|
+
"""Save Beachballs """
|
|
243
|
+
# data = self.indata['Seis']
|
|
244
|
+
|
|
245
|
+
ext = "Shape file (*.shp)"
|
|
246
|
+
|
|
247
|
+
filename = QtGui.QFileDialog.getSaveFileName(
|
|
248
|
+
self.parent, 'Save Shape File', '.', ext)
|
|
249
|
+
|
|
250
|
+
if filename == '':
|
|
251
|
+
return False
|
|
252
|
+
os.chdir(filename.rpartition('/')[0])
|
|
253
|
+
|
|
254
|
+
self.ifile = str(filename)
|
|
255
|
+
self.ext = filename[-3:]
|
|
256
|
+
|
|
257
|
+
indata = self.mmc.data
|
|
258
|
+
|
|
259
|
+
ifile_bnd = self.ifile[:-4]+'_bnd.shp'
|
|
260
|
+
if os.path.isfile(self.ifile):
|
|
261
|
+
tmp = self.ifile[:-4]
|
|
262
|
+
os.remove(tmp+'.shp')
|
|
263
|
+
os.remove(tmp+'.shx')
|
|
264
|
+
os.remove(tmp+'.prj')
|
|
265
|
+
os.remove(tmp+'.dbf')
|
|
266
|
+
if os.path.isfile(ifile_bnd):
|
|
267
|
+
tmp = ifile_bnd[:-4]
|
|
268
|
+
os.remove(tmp+'.shp')
|
|
269
|
+
os.remove(tmp+'.shx')
|
|
270
|
+
os.remove(tmp+'.prj')
|
|
271
|
+
os.remove(tmp+'.dbf')
|
|
272
|
+
|
|
273
|
+
driver = ogr.GetDriverByName("ESRI Shapefile")
|
|
274
|
+
data_source = driver.CreateDataSource(self.ifile)
|
|
275
|
+
data_source2 = driver.CreateDataSource(ifile_bnd)
|
|
276
|
+
|
|
277
|
+
# create the spatial reference, WGS84
|
|
278
|
+
srs = osr.SpatialReference()
|
|
279
|
+
srs.ImportFromEPSG(4326)
|
|
280
|
+
|
|
281
|
+
# create the layer
|
|
282
|
+
layer = data_source.CreateLayer("Fault Plane Solution", srs,
|
|
283
|
+
ogr.wkbPolygon)
|
|
284
|
+
layer.CreateField(ogr.FieldDefn("Strike", ogr.OFTReal))
|
|
285
|
+
layer.CreateField(ogr.FieldDefn("Dip", ogr.OFTReal))
|
|
286
|
+
layer.CreateField(ogr.FieldDefn("Rake", ogr.OFTReal))
|
|
287
|
+
layer.CreateField(ogr.FieldDefn("Magnitude", ogr.OFTReal))
|
|
288
|
+
|
|
289
|
+
layer2 = data_source2.CreateLayer("Fault Plane Solution Boundaries",
|
|
290
|
+
srs, ogr.wkbPolygon)
|
|
291
|
+
|
|
292
|
+
# Calculate BeachBall
|
|
293
|
+
for idat in indata:
|
|
294
|
+
pxy = idat[:2]
|
|
295
|
+
np1 = idat[2:-1]
|
|
296
|
+
pwidth = self.mmc.pwidth*idat[-1]
|
|
297
|
+
xxx, yyy, xxx2, yyy2 = beachball(np1, pxy[0], pxy[1], pwidth)
|
|
298
|
+
|
|
299
|
+
pvert1 = np.transpose([yyy, xxx])
|
|
300
|
+
pvert0 = np.transpose([xxx2, yyy2])
|
|
301
|
+
|
|
302
|
+
# Create Geometry
|
|
303
|
+
outring = ogr.Geometry(ogr.wkbLinearRing)
|
|
304
|
+
for i in pvert1:
|
|
305
|
+
outring.AddPoint(i[0], i[1])
|
|
306
|
+
|
|
307
|
+
innerring = ogr.Geometry(ogr.wkbLinearRing)
|
|
308
|
+
for i in pvert0:
|
|
309
|
+
innerring.AddPoint(i[0], i[1])
|
|
310
|
+
|
|
311
|
+
poly = ogr.Geometry(ogr.wkbPolygon)
|
|
312
|
+
poly.AddGeometry(outring)
|
|
313
|
+
|
|
314
|
+
poly1 = ogr.Geometry(ogr.wkbPolygon)
|
|
315
|
+
poly1.AddGeometry(innerring)
|
|
316
|
+
|
|
317
|
+
feature = ogr.Feature(layer.GetLayerDefn())
|
|
318
|
+
|
|
319
|
+
feature.SetField("Strike", np1[0])
|
|
320
|
+
feature.SetField("Dip", np1[1])
|
|
321
|
+
feature.SetField("Rake", np1[2])
|
|
322
|
+
feature.SetField("Magnitude", idat[-1])
|
|
323
|
+
|
|
324
|
+
feature.SetGeometry(poly)
|
|
325
|
+
# Create the feature in the layer (shapefile)
|
|
326
|
+
layer.CreateFeature(feature)
|
|
327
|
+
# Destroy the feature to free resources
|
|
328
|
+
feature.Destroy()
|
|
329
|
+
|
|
330
|
+
feature = ogr.Feature(layer2.GetLayerDefn())
|
|
331
|
+
feature.SetGeometry(poly1)
|
|
332
|
+
# Create the feature in the layer (shapefile)
|
|
333
|
+
layer2.CreateFeature(feature)
|
|
334
|
+
# Destroy the feature to free resources
|
|
335
|
+
feature.Destroy()
|
|
336
|
+
|
|
337
|
+
data_source.Destroy()
|
|
338
|
+
data_source2.Destroy()
|
|
339
|
+
|
|
340
|
+
def change_alg(self):
|
|
341
|
+
""" Change algorithm """
|
|
342
|
+
txt = str(self.cbox_alg.currentText())
|
|
343
|
+
self.algorithm = txt
|
|
344
|
+
data = self.indata['Seis']
|
|
345
|
+
|
|
346
|
+
indata = []
|
|
347
|
+
for i in data:
|
|
348
|
+
if i['F'].get(self.algorithm) is not None:
|
|
349
|
+
tmp = [i['1'].longitude, i['1'].latitude,
|
|
350
|
+
i['F'][self.algorithm].strike,
|
|
351
|
+
i['F'][self.algorithm].dip,
|
|
352
|
+
i['F'][self.algorithm].rake,
|
|
353
|
+
i['1'].magnitude_1]
|
|
354
|
+
indata.append(tmp)
|
|
355
|
+
|
|
356
|
+
self.mmc.data = np.array(indata)
|
|
357
|
+
self.mmc.pwidth = self.dsb_dist.value()
|
|
358
|
+
self.mmc.init_graph()
|
|
359
|
+
|
|
360
|
+
def settings(self):
|
|
361
|
+
""" run """
|
|
362
|
+
if self.nofps:
|
|
363
|
+
self.parent.showprocesslog('Error: no Fault Plane Solutions')
|
|
364
|
+
return False
|
|
365
|
+
|
|
366
|
+
self.show()
|
|
367
|
+
QtGui.QApplication.processEvents()
|
|
368
|
+
|
|
369
|
+
self.mmc.init_graph()
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def beachball(fm, centerx, centery, diam):
|
|
373
|
+
"""
|
|
374
|
+
function bb(fm, centerx, centery, diam, ta, color)
|
|
375
|
+
Draws beachball diagram of earthquake double-couple focal mechanism(s).
|
|
376
|
+
S1, D1, and R1, the strike, dip and rake of one of the focal planes, can
|
|
377
|
+
be vectors of multiple focal mechanisms.
|
|
378
|
+
|
|
379
|
+
Parameters
|
|
380
|
+
----------
|
|
381
|
+
fm : numpy array
|
|
382
|
+
focal mechanism that is either number of mechnisms (NM) by 3
|
|
383
|
+
(strike, dip, and rake) or NM x 6 (mxx, myy, mzz, mxy, mxz, myz -
|
|
384
|
+
the six independent components of the moment tensor). The strike is
|
|
385
|
+
of the first plane, clockwise relative to north. The dip is of the
|
|
386
|
+
first plane, defined clockwise and perpedicular to strike, relative
|
|
387
|
+
to horizontal such that 0 is horizontal and 90 is vertical. The rake is
|
|
388
|
+
of the first focal plane solution. 90 moves the hanging wall up-dip
|
|
389
|
+
(thrust), 0 moves it in the strike direction (left-lateral), -90 moves
|
|
390
|
+
it down-dip (normal), and 180 moves it opposite to strike
|
|
391
|
+
(right-lateral).
|
|
392
|
+
centerx : float
|
|
393
|
+
place beachball(s) at position centerx
|
|
394
|
+
centery : float
|
|
395
|
+
place beachball(s) at position centery
|
|
396
|
+
diam : float
|
|
397
|
+
draw beachball with this diameter.
|
|
398
|
+
|
|
399
|
+
Returns
|
|
400
|
+
-------
|
|
401
|
+
X : numpy array
|
|
402
|
+
array of x coordinates for vertices
|
|
403
|
+
Y : numpy array
|
|
404
|
+
array of y coordinates for vertices
|
|
405
|
+
xx : numpy array
|
|
406
|
+
array of x coordinates for vertices
|
|
407
|
+
yy : numpy array
|
|
408
|
+
array of y coordinates for vertices
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
fm = np.array(fm)
|
|
412
|
+
diam = np.array([diam])
|
|
413
|
+
centerx = np.array([centerx])
|
|
414
|
+
centery = np.array([centery])
|
|
415
|
+
|
|
416
|
+
if fm.ndim == 1:
|
|
417
|
+
ne1 = 1
|
|
418
|
+
n = fm.size
|
|
419
|
+
fm = np.array([fm])
|
|
420
|
+
else:
|
|
421
|
+
ne1, n = fm.shape
|
|
422
|
+
if n == 6:
|
|
423
|
+
s1 = np.zeros(ne)
|
|
424
|
+
d1 = np.zeros(ne)
|
|
425
|
+
r1 = np.zeros(ne)
|
|
426
|
+
for j in range(ne):
|
|
427
|
+
s1[j], d1[j], r1[j] = mij2sdr(fm[j, 0], fm[j, 1], fm[j, 2],
|
|
428
|
+
fm[j, 3], fm[j, 4], fm[j, 5])
|
|
429
|
+
else:
|
|
430
|
+
s1 = fm[:, 0]
|
|
431
|
+
d1 = fm[:, 1]
|
|
432
|
+
r1 = fm[:, 2]
|
|
433
|
+
|
|
434
|
+
# r2d = 180/np.pi
|
|
435
|
+
d2r = np.pi/180
|
|
436
|
+
ampy = np.cos(np.mean(centery)*d2r)
|
|
437
|
+
|
|
438
|
+
if ne1 > 1:
|
|
439
|
+
[_, i] = np.sort(diam, 1, 'descend')
|
|
440
|
+
diam = diam[i]
|
|
441
|
+
s1 = s1[i]
|
|
442
|
+
d1 = d1[i]
|
|
443
|
+
r1 = r1[i]
|
|
444
|
+
centerx = centerx[i]
|
|
445
|
+
centery = centery[i]
|
|
446
|
+
|
|
447
|
+
mech = np.zeros([ne1, 1])
|
|
448
|
+
j = np.nonzero(r1 > 180)
|
|
449
|
+
r1[j] = r1[j] - 180
|
|
450
|
+
mech[j] = 1
|
|
451
|
+
j = np.nonzero(r1 < 0)
|
|
452
|
+
r1[j] = r1[j] + 180
|
|
453
|
+
mech[j] = 1
|
|
454
|
+
|
|
455
|
+
# Get azimuth and dip of second plane
|
|
456
|
+
s2, d2, r2 = auxplane(s1, d1, r1)
|
|
457
|
+
|
|
458
|
+
for ev in range(ne1):
|
|
459
|
+
S1 = s1[ev]
|
|
460
|
+
D1 = d1[ev]
|
|
461
|
+
S2 = s2[ev]
|
|
462
|
+
D2 = d2[ev]
|
|
463
|
+
P = r1[ev]
|
|
464
|
+
CX = centerx[ev]
|
|
465
|
+
CY = centery[ev]
|
|
466
|
+
D = diam[ev]
|
|
467
|
+
M = mech[ev]
|
|
468
|
+
|
|
469
|
+
if M > 0:
|
|
470
|
+
P = 2
|
|
471
|
+
else:
|
|
472
|
+
P = 1
|
|
473
|
+
|
|
474
|
+
if D1 >= 90:
|
|
475
|
+
D1 = 89.9999
|
|
476
|
+
if D2 >= 90:
|
|
477
|
+
D2 = 89.9999
|
|
478
|
+
|
|
479
|
+
phi = np.arange(0, np.pi, .01)
|
|
480
|
+
d = 90 - D1
|
|
481
|
+
m = 90
|
|
482
|
+
l1 = np.sqrt(d**2/(np.sin(phi)**2 + np.cos(phi)**2 * d**2/m**2))
|
|
483
|
+
|
|
484
|
+
d = 90 - D2
|
|
485
|
+
m = 90
|
|
486
|
+
l2 = np.sqrt(d**2/(np.sin(phi)**2 + np.cos(phi)**2 * d**2/m**2))
|
|
487
|
+
|
|
488
|
+
if D == 0:
|
|
489
|
+
print('Enter a diameter for the beachballs!')
|
|
490
|
+
return
|
|
491
|
+
|
|
492
|
+
inc = 1
|
|
493
|
+
X1, Y1 = pol2cart(phi+S1*d2r, l1)
|
|
494
|
+
if P == 1:
|
|
495
|
+
lo = S1 - 180
|
|
496
|
+
hi = S2
|
|
497
|
+
if lo > hi:
|
|
498
|
+
inc = -inc
|
|
499
|
+
th1 = np.arange(S1-180, S2, inc)
|
|
500
|
+
Xs1, Ys1 = pol2cart(th1*d2r, 90*np.ones_like(th1))
|
|
501
|
+
X2, Y2 = pol2cart(phi+S2*d2r, l2)
|
|
502
|
+
th2 = np.arange(S2+180, S1, -inc)
|
|
503
|
+
else:
|
|
504
|
+
hi = S1 - 180
|
|
505
|
+
lo = S2 - 180
|
|
506
|
+
if lo > hi:
|
|
507
|
+
inc = -inc
|
|
508
|
+
th1 = np.arange(hi, lo, -inc)
|
|
509
|
+
Xs1, Ys1 = pol2cart(th1*d2r, 90*np.ones_like(th1))
|
|
510
|
+
X2, Y2 = pol2cart(phi+S2*d2r, l2)
|
|
511
|
+
X2 = X2[::-1]
|
|
512
|
+
Y2 = Y2[::-1]
|
|
513
|
+
th2 = np.arange(S2, S1, inc)
|
|
514
|
+
|
|
515
|
+
Xs2, Ys2 = pol2cart(th2*d2r, 90*np.ones_like(th2))
|
|
516
|
+
|
|
517
|
+
X = np.concatenate((X1, Xs1, X2, Xs2), 1)
|
|
518
|
+
Y = np.concatenate((Y1, Ys1, Y2, Ys2), 1)
|
|
519
|
+
|
|
520
|
+
if D > 0:
|
|
521
|
+
X = ampy*X * D/90 + CY
|
|
522
|
+
Y = Y * D/90 + CX
|
|
523
|
+
phid = np.arange(0, 2*np.pi, 0.01)
|
|
524
|
+
x, y = pol2cart(phid, 90)
|
|
525
|
+
xx = x*D/90 + CX
|
|
526
|
+
yy = ampy*y*D/90 + CY
|
|
527
|
+
|
|
528
|
+
return X, Y, xx, yy
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def pol2cart(phi, rho):
|
|
532
|
+
""" Polar to cartesian coordinates """
|
|
533
|
+
xxx = rho*np.cos(phi)
|
|
534
|
+
yyy = rho*np.sin(phi)
|
|
535
|
+
return xxx, yyy
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def auxplane(s1, d1, r1):
|
|
539
|
+
"""
|
|
540
|
+
function [strike, dip, rake] = auxplane(s1,d1,r1)
|
|
541
|
+
Get Strike and dip of second plane, adapted from Andy Michael bothplanes.c
|
|
542
|
+
"""
|
|
543
|
+
r2d = 180/np.pi
|
|
544
|
+
|
|
545
|
+
z = (s1+90)/r2d
|
|
546
|
+
z2 = d1/r2d
|
|
547
|
+
z3 = r1/r2d
|
|
548
|
+
# /* slick vector in plane 1 */
|
|
549
|
+
sl1 = -np.cos(z3)*np.cos(z)-np.sin(z3)*np.sin(z)*np.cos(z2)
|
|
550
|
+
sl2 = np.cos(z3)*np.sin(z)-np.sin(z3)*np.cos(z)*np.cos(z2)
|
|
551
|
+
sl3 = np.sin(z3)*np.sin(z2)
|
|
552
|
+
strike, dip = strikedip(sl2, sl1, sl3)
|
|
553
|
+
|
|
554
|
+
n1 = np.sin(z)*np.sin(z2) # /* normal vector to plane 1 */
|
|
555
|
+
n2 = np.cos(z)*np.sin(z2)
|
|
556
|
+
# n3 = np.cos(z2)
|
|
557
|
+
h1 = -sl2 # /* strike vector of plane 2 */
|
|
558
|
+
h2 = sl1
|
|
559
|
+
# /* note h3=0 always so we leave it out */
|
|
560
|
+
|
|
561
|
+
z = h1*n1 + h2*n2
|
|
562
|
+
z = z/np.sqrt(h1*h1 + h2*h2)
|
|
563
|
+
z = np.arccos(z)
|
|
564
|
+
|
|
565
|
+
rake = np.zeros_like(strike)
|
|
566
|
+
j = np.nonzero(sl3 > 0)
|
|
567
|
+
rake[j] = z[j]*r2d
|
|
568
|
+
j = np.nonzero(sl3 <= 0)
|
|
569
|
+
rake[j] = -z[j]*r2d
|
|
570
|
+
|
|
571
|
+
return strike, dip, rake
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def strikedip(n, e, u):
|
|
575
|
+
"""
|
|
576
|
+
function [strike, dip] = strikedip(n, e, u)
|
|
577
|
+
Finds strike and dip of plane given normal vector having components n,
|
|
578
|
+
e, and u
|
|
579
|
+
Adapted from Andy Michaels stridip.c
|
|
580
|
+
"""
|
|
581
|
+
r2d = 180/np.pi
|
|
582
|
+
|
|
583
|
+
j = np.nonzero(u < 0)
|
|
584
|
+
n[j] = -n[j]
|
|
585
|
+
e[j] = -e[j]
|
|
586
|
+
u[j] = -u[j]
|
|
587
|
+
|
|
588
|
+
strike = np.arctan2(e, n)*r2d
|
|
589
|
+
strike = strike - 90
|
|
590
|
+
while strike >= 360:
|
|
591
|
+
strike = strike - 360
|
|
592
|
+
while strike < 0:
|
|
593
|
+
strike = strike + 360
|
|
594
|
+
|
|
595
|
+
x = np.sqrt(n**2 + e**2)
|
|
596
|
+
dip = np.arctan2(x, u)*r2d
|
|
597
|
+
return strike, dip
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def mij2sdr(mxx, myy, mzz, mxy, mxz, myz):
|
|
601
|
+
"""
|
|
602
|
+
function [str,dip,rake] = mij2sdr(mxx,myy,mzz,mxy,mxz,myz)
|
|
603
|
+
Adapted from code, mij2d.f, created by Chen Ji
|
|
604
|
+
|
|
605
|
+
Parameters
|
|
606
|
+
----------
|
|
607
|
+
mxx - float
|
|
608
|
+
independent component of the moment tensor
|
|
609
|
+
myy - float
|
|
610
|
+
independent component of the moment tensor
|
|
611
|
+
mzz - float
|
|
612
|
+
independent component of the moment tensor
|
|
613
|
+
mxy - float
|
|
614
|
+
independent component of the moment tensor
|
|
615
|
+
mxz - float
|
|
616
|
+
independent component of the moment tensor
|
|
617
|
+
myz - float
|
|
618
|
+
independent component of the moment tensor
|
|
619
|
+
|
|
620
|
+
Returns
|
|
621
|
+
-------
|
|
622
|
+
strike : float
|
|
623
|
+
strike of first focal plane (degrees)
|
|
624
|
+
dip : float
|
|
625
|
+
dip of first focal plane (degrees)
|
|
626
|
+
rake : float
|
|
627
|
+
rake of first focal plane (degrees)
|
|
628
|
+
"""
|
|
629
|
+
|
|
630
|
+
a = np.array([[mxx, mxy, mxz],
|
|
631
|
+
[mxy, myy, myz],
|
|
632
|
+
[mxz, myz, mzz]])
|
|
633
|
+
d, V = np.linalg.eig(a)
|
|
634
|
+
|
|
635
|
+
D = np.array([d[1], d[0], d[2]])
|
|
636
|
+
|
|
637
|
+
V = np.array([[-V[1, 1], V[1, 0], V[1, 2]],
|
|
638
|
+
[-V[2, 1], V[2, 0], V[2, 2]],
|
|
639
|
+
[V[0, 1], -V[0, 0], -V[0, 2]]])
|
|
640
|
+
|
|
641
|
+
IMAX = np.nonzero(D == D.max())
|
|
642
|
+
IMIN = np.nonzero(D == D.min())
|
|
643
|
+
AE = (V[:, IMAX]+V[:, IMIN])/np.sqrt(2.0)
|
|
644
|
+
AN = (V[:, IMAX]-V[:, IMIN])/np.sqrt(2.0)
|
|
645
|
+
AER = np.sqrt(AE[0]**2+AE[1]**2+AE[2]**2)
|
|
646
|
+
ANR = np.sqrt(AN[0]**2+AN[1]**2+AN[2]**2)
|
|
647
|
+
AE = AE/AER
|
|
648
|
+
AN = AN/ANR
|
|
649
|
+
if AN[2] <= 0.:
|
|
650
|
+
AN1 = AN
|
|
651
|
+
AE1 = AE
|
|
652
|
+
else:
|
|
653
|
+
AN1 = -AN
|
|
654
|
+
AE1 = -AE
|
|
655
|
+
ft, fd, fl = TDL(AN1, AE1)
|
|
656
|
+
strike = 360 - ft
|
|
657
|
+
dip = fd
|
|
658
|
+
rake = 180 - fl
|
|
659
|
+
return strike, dip, rake
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
def TDL(AN, BN):
|
|
663
|
+
"""
|
|
664
|
+
TDL
|
|
665
|
+
|
|
666
|
+
Parameters
|
|
667
|
+
----------
|
|
668
|
+
AN : numpy array
|
|
669
|
+
array comprising XN, YN, ZN
|
|
670
|
+
BN : numpy array
|
|
671
|
+
array comprising XE, YE, ZE
|
|
672
|
+
|
|
673
|
+
Returns
|
|
674
|
+
-------
|
|
675
|
+
FT : float
|
|
676
|
+
relates to strike (360 - ft)
|
|
677
|
+
FD : float
|
|
678
|
+
dip
|
|
679
|
+
FL : float
|
|
680
|
+
relates to rake (180 - fl)
|
|
681
|
+
"""
|
|
682
|
+
XN, YN, ZN = AN.flatten()
|
|
683
|
+
XE, YE, ZE = BN.flatten()
|
|
684
|
+
AAA = 1.0E-06
|
|
685
|
+
CON = 57.2957795
|
|
686
|
+
if abs(ZN) < AAA:
|
|
687
|
+
FD = 90.
|
|
688
|
+
AXN = abs(XN)
|
|
689
|
+
if AXN > 1.0:
|
|
690
|
+
AXN = 1.0
|
|
691
|
+
FT = np.arcsin(AXN)*CON
|
|
692
|
+
ST = -XN
|
|
693
|
+
CT = YN
|
|
694
|
+
if ST >= 0. and CT < 0:
|
|
695
|
+
FT = 180.-FT
|
|
696
|
+
if ST < 0. and CT <= 0:
|
|
697
|
+
FT = 180.+FT
|
|
698
|
+
if ST < 0. and CT > 0:
|
|
699
|
+
FT = 360.-FT
|
|
700
|
+
FL = np.arcsin(abs(ZE))*CON
|
|
701
|
+
SL = -ZE
|
|
702
|
+
if abs(XN) < AAA:
|
|
703
|
+
CL = XE/YN
|
|
704
|
+
else:
|
|
705
|
+
CL = -YE/XN
|
|
706
|
+
if SL >= 0. and CL < 0:
|
|
707
|
+
FL = 180.-FL
|
|
708
|
+
if SL < 0. and CL <= 0:
|
|
709
|
+
FL = FL-180.
|
|
710
|
+
if SL < 0. and CL > 0:
|
|
711
|
+
FL = -FL
|
|
712
|
+
else:
|
|
713
|
+
if -ZN > 1.0:
|
|
714
|
+
ZN = -1.0
|
|
715
|
+
FDH = np.arccos(-ZN)
|
|
716
|
+
FD = FDH*CON
|
|
717
|
+
SD = np.sin(FDH)
|
|
718
|
+
if SD == 0:
|
|
719
|
+
return
|
|
720
|
+
ST = -XN/SD
|
|
721
|
+
CT = YN/SD
|
|
722
|
+
SX = abs(ST)
|
|
723
|
+
if SX > 1.0:
|
|
724
|
+
SX = 1.0
|
|
725
|
+
FT = np.arcsin(SX)*CON
|
|
726
|
+
if ST >= 0. and CT < 0:
|
|
727
|
+
FT = 180.-FT
|
|
728
|
+
if ST < 0. and CT <= 0:
|
|
729
|
+
FT = 180.+FT
|
|
730
|
+
if ST < 0. and CT > 0:
|
|
731
|
+
FT = 360.-FT
|
|
732
|
+
SL = -ZE/SD
|
|
733
|
+
SX = np.abs(SL)
|
|
734
|
+
if SX > 1.0:
|
|
735
|
+
SX = 1.0
|
|
736
|
+
FL = np.arcsin(SX)*CON
|
|
737
|
+
if ST == 0:
|
|
738
|
+
CL = XE/CT
|
|
739
|
+
else:
|
|
740
|
+
xxx = YN*ZN*ZE/SD/SD+YE
|
|
741
|
+
CL = -SD*xxx/XN
|
|
742
|
+
if CT == 0:
|
|
743
|
+
CL = YE/ST
|
|
744
|
+
if SL >= 0. and CL < 0:
|
|
745
|
+
FL = 180.-FL
|
|
746
|
+
if SL < 0. and CL <= 0:
|
|
747
|
+
FL = FL-180.
|
|
748
|
+
if SL < 0. and CL > 0:
|
|
749
|
+
FL = -FL
|
|
750
|
+
|
|
751
|
+
return FT, FD, FL
|