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.
Files changed (106) hide show
  1. pygmi-2.2.7/LICENSE.txt +623 -0
  2. pygmi-2.2.7/MANIFEST.in +7 -0
  3. pygmi-2.2.7/PKG-INFO +47 -0
  4. pygmi-2.2.7/README.md +55 -0
  5. pygmi-2.2.7/README.rst +20 -0
  6. pygmi-2.2.7/log.txt +242 -0
  7. pygmi-2.2.7/pygmi/__init__.py +22 -0
  8. pygmi-2.2.7/pygmi/clust/__init__.py +4 -0
  9. pygmi-2.2.7/pygmi/clust/crisp_clust.py +708 -0
  10. pygmi-2.2.7/pygmi/clust/datatypes.py +65 -0
  11. pygmi-2.2.7/pygmi/clust/fuzzy_clust.py +906 -0
  12. pygmi-2.2.7/pygmi/clust/graphs.py +421 -0
  13. pygmi-2.2.7/pygmi/clust/graphtool.py +667 -0
  14. pygmi-2.2.7/pygmi/clust/menu.py +139 -0
  15. pygmi-2.2.7/pygmi/clust/var_ratio.py +92 -0
  16. pygmi-2.2.7/pygmi/clust/xie_beni.py +93 -0
  17. pygmi-2.2.7/pygmi/helpdocs/linepointer.png +0 -0
  18. pygmi-2.2.7/pygmi/helpdocs/pygmi.main.html +31 -0
  19. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.ddisp.html +15 -0
  20. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.exportkmz.html +13 -0
  21. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.iodefs.importpicture.html +16 -0
  22. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.layer.html +17 -0
  23. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.mext.html +44 -0
  24. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.misc.rangedcopy.html +16 -0
  25. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.param.html +37 -0
  26. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.prof.html +32 -0
  27. pygmi-2.2.7/pygmi/helpdocs/pygmi.pfmod.pview.html +26 -0
  28. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.gradients.html +14 -0
  29. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.tilt.html +14 -0
  30. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.cooper.visibility.html +14 -0
  31. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datagrid.html +13 -0
  32. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datamerge.html +11 -0
  33. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.datareproj.html +11 -0
  34. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.dataprep.rtp.html +14 -0
  35. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.ginterp.html +31 -0
  36. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.igrf.html +20 -0
  37. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.normalisation.html +14 -0
  38. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.smooth.html +22 -0
  39. pygmi-2.2.7/pygmi/helpdocs/pygmi.raster.tiltdepth.html +20 -0
  40. pygmi-2.2.7/pygmi/images/Help.png +0 -0
  41. pygmi-2.2.7/pygmi/images/bringtofront.png +0 -0
  42. pygmi-2.2.7/pygmi/images/cgs2.emf +0 -0
  43. pygmi-2.2.7/pygmi/images/delete.png +0 -0
  44. pygmi-2.2.7/pygmi/images/linepointer.png +0 -0
  45. pygmi-2.2.7/pygmi/images/logo256.ico +0 -0
  46. pygmi-2.2.7/pygmi/images/logo256.png +0 -0
  47. pygmi-2.2.7/pygmi/images/pointer.png +0 -0
  48. pygmi-2.2.7/pygmi/images/pygmi.png +0 -0
  49. pygmi-2.2.7/pygmi/images/sendtoback.png +0 -0
  50. pygmi-2.2.7/pygmi/main.py +1037 -0
  51. pygmi-2.2.7/pygmi/menu_default.py +327 -0
  52. pygmi-2.2.7/pygmi/misc.py +147 -0
  53. pygmi-2.2.7/pygmi/pfmod/__init__.py +6 -0
  54. pygmi-2.2.7/pygmi/pfmod/cubes.py +1488 -0
  55. pygmi-2.2.7/pygmi/pfmod/datatypes.py +292 -0
  56. pygmi-2.2.7/pygmi/pfmod/grvmag3d.py +1265 -0
  57. pygmi-2.2.7/pygmi/pfmod/iodefs.py +1001 -0
  58. pygmi-2.2.7/pygmi/pfmod/menu.py +107 -0
  59. pygmi-2.2.7/pygmi/pfmod/misc.py +301 -0
  60. pygmi-2.2.7/pygmi/pfmod/pfmod.py +248 -0
  61. pygmi-2.2.7/pygmi/pfmod/tab_ddisp.py +425 -0
  62. pygmi-2.2.7/pygmi/pfmod/tab_layer.py +490 -0
  63. pygmi-2.2.7/pygmi/pfmod/tab_mext.py +544 -0
  64. pygmi-2.2.7/pygmi/pfmod/tab_param.py +548 -0
  65. pygmi-2.2.7/pygmi/pfmod/tab_prof.py +946 -0
  66. pygmi-2.2.7/pygmi/pfmod/tab_pview.py +740 -0
  67. pygmi-2.2.7/pygmi/raster/IGRF11.COF +1635 -0
  68. pygmi-2.2.7/pygmi/raster/__init__.py +14 -0
  69. pygmi-2.2.7/pygmi/raster/cooper.py +718 -0
  70. pygmi-2.2.7/pygmi/raster/dataprep.py +1640 -0
  71. pygmi-2.2.7/pygmi/raster/datatypes.py +123 -0
  72. pygmi-2.2.7/pygmi/raster/equation_editor.py +256 -0
  73. pygmi-2.2.7/pygmi/raster/ginterp.py +1901 -0
  74. pygmi-2.2.7/pygmi/raster/graphs.py +531 -0
  75. pygmi-2.2.7/pygmi/raster/igrf.py +860 -0
  76. pygmi-2.2.7/pygmi/raster/iodefs.py +813 -0
  77. pygmi-2.2.7/pygmi/raster/menu.py +307 -0
  78. pygmi-2.2.7/pygmi/raster/normalisation.py +187 -0
  79. pygmi-2.2.7/pygmi/raster/show_table.py +245 -0
  80. pygmi-2.2.7/pygmi/raster/smooth.py +406 -0
  81. pygmi-2.2.7/pygmi/raster/tiltdepth.py +590 -0
  82. pygmi-2.2.7/pygmi/seis/__init__.py +0 -0
  83. pygmi-2.2.7/pygmi/seis/beachball.py +751 -0
  84. pygmi-2.2.7/pygmi/seis/datatypes.py +605 -0
  85. pygmi-2.2.7/pygmi/seis/del_rec.py +410 -0
  86. pygmi-2.2.7/pygmi/seis/iodefs.py +1261 -0
  87. pygmi-2.2.7/pygmi/seis/menu.py +136 -0
  88. pygmi-2.2.7/pygmi/seis/scan_imp.py +795 -0
  89. pygmi-2.2.7/pygmi/test/__init__.py +6 -0
  90. pygmi-2.2.7/pygmi/test/pfmod.py +212 -0
  91. pygmi-2.2.7/pygmi/test/tests.py +39 -0
  92. pygmi-2.2.7/pygmi/vector/__init__.py +7 -0
  93. pygmi-2.2.7/pygmi/vector/datatypes.py +74 -0
  94. pygmi-2.2.7/pygmi/vector/graphs.py +443 -0
  95. pygmi-2.2.7/pygmi/vector/iodefs.py +345 -0
  96. pygmi-2.2.7/pygmi/vector/menu.py +127 -0
  97. pygmi-2.2.7/pygmi.egg-info/PKG-INFO +47 -0
  98. pygmi-2.2.7/pygmi.egg-info/SOURCES.txt +105 -0
  99. pygmi-2.2.7/pygmi.egg-info/dependency_links.txt +1 -0
  100. pygmi-2.2.7/pygmi.egg-info/entry_points.txt +3 -0
  101. pygmi-2.2.7/pygmi.egg-info/not-zip-safe +1 -0
  102. pygmi-2.2.7/pygmi.egg-info/requires.txt +7 -0
  103. pygmi-2.2.7/pygmi.egg-info/top_level.txt +1 -0
  104. pygmi-2.2.7/quickstart.py +35 -0
  105. pygmi-2.2.7/setup.cfg +8 -0
  106. pygmi-2.2.7/setup.py +80 -0
@@ -0,0 +1,1488 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Name: cubes.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
+ """ This is code for the 3d model creation. """
26
+
27
+ from __future__ import print_function
28
+
29
+ import os
30
+ import sys
31
+ import numpy as np
32
+ from PyQt4 import QtCore, QtGui, QtOpenGL
33
+ # import OpenGL
34
+ # OpenGL.ERROR_CHECKING = False # Note This!!!!
35
+ from OpenGL import GL
36
+ from OpenGL import GLU
37
+ from OpenGL.arrays import vbo
38
+ import pygmi.pfmod.misc as misc
39
+ from scipy.ndimage.interpolation import zoom
40
+ import scipy.ndimage.filters as sf
41
+ from numba import jit
42
+ from PIL import Image
43
+
44
+
45
+ class Mod3dDisplay(QtGui.QDialog):
46
+ """ Widget class to call the main interface """
47
+ def __init__(self, parent=None):
48
+ QtGui.QDialog.__init__(self, parent)
49
+ self.parent = parent
50
+ self.lmod1 = None
51
+ self.indata = {}
52
+ self.outdata = self.indata
53
+
54
+ if hasattr(parent, 'showtext'):
55
+ self.showtext = parent.showtext
56
+ else:
57
+ self.showtext = print
58
+
59
+ if hasattr(parent, 'showprocesslog'):
60
+ self.showprocesslog = parent.showprocesslog
61
+ else:
62
+ self.showprocesslog = print
63
+
64
+ self.corners = []
65
+ self.faces = {}
66
+ self.norms = []
67
+ self.gdata = np.zeros([4, 3, 2])
68
+ self.gdata[0, 0, 0] = -1
69
+ self.sliths = np.array([]) # selected lithologies
70
+ self.origin = [0., 0., 0.]
71
+ self.spacing = [10., 10., 10.]
72
+ self.zmult = 1.
73
+ self.lut = np.ones((255, 4))*255
74
+ self.lut[0] = [255, 0, 0, 255]
75
+ self.lut[1] = [0, 255, 0, 255]
76
+ self.gfaces = []
77
+ self.gpoints = []
78
+ self.gnorms = []
79
+ self.glutlith = []
80
+ self.demsurf = None
81
+ self.qdiv = 0
82
+ self.mesh = {}
83
+ self.opac = 0.0
84
+ self.cust_z = None
85
+
86
+ # Back to normal stuff
87
+ self.lw_3dmod_defs = QtGui.QListWidget()
88
+ self.label = QtGui.QLabel()
89
+ self.label2 = QtGui.QLabel()
90
+ self.pb_save = QtGui.QPushButton()
91
+ self.pb_refresh = QtGui.QPushButton()
92
+ self.checkbox_smooth = QtGui.QCheckBox()
93
+ self.pbar = QtGui.QProgressBar()
94
+ self.glwidget = GLWidget()
95
+ self.vslider_3dmodel = QtGui.QSlider()
96
+
97
+ self.setupui()
98
+
99
+ def setupui(self):
100
+ """ Setup UI """
101
+ horizontallayout = QtGui.QHBoxLayout(self)
102
+ vbox_cmodel = QtGui.QVBoxLayout()
103
+ verticallayout = QtGui.QVBoxLayout()
104
+
105
+ self.vslider_3dmodel.setMinimum(1)
106
+ self.vslider_3dmodel.setMaximum(1000)
107
+ self.vslider_3dmodel.setOrientation(QtCore.Qt.Vertical)
108
+ vbox_cmodel.setSizeConstraint(QtGui.QLayout.SetNoConstraint)
109
+ sizepolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
110
+ QtGui.QSizePolicy.Fixed)
111
+
112
+ sizepolicy_pb = QtGui.QSizePolicy(QtGui.QSizePolicy.Maximum,
113
+ QtGui.QSizePolicy.Maximum)
114
+
115
+ self.lw_3dmod_defs.setSizePolicy(sizepolicy)
116
+ self.lw_3dmod_defs.setSelectionMode(
117
+ QtGui.QAbstractItemView.MultiSelection)
118
+ self.lw_3dmod_defs.setFixedWidth(220)
119
+ self.checkbox_smooth.setSizePolicy(sizepolicy)
120
+ self.pb_save.setSizePolicy(sizepolicy_pb)
121
+ self.pb_refresh.setSizePolicy(sizepolicy_pb)
122
+ self.pbar.setOrientation(QtCore.Qt.Vertical)
123
+
124
+ self.checkbox_smooth.setText("Smooth Model")
125
+ self.pb_save.setText("Save to Image File (JPG or PNG)")
126
+ self.pb_refresh.setText('Refresh Model')
127
+
128
+ verticallayout.addWidget(self.lw_3dmod_defs)
129
+ verticallayout.addWidget(self.checkbox_smooth)
130
+ verticallayout.addWidget(self.pb_save)
131
+ verticallayout.addWidget(self.pb_refresh)
132
+ vbox_cmodel.addWidget(self.glwidget)
133
+ horizontallayout.addWidget(self.vslider_3dmodel)
134
+ horizontallayout.addLayout(vbox_cmodel)
135
+ horizontallayout.addLayout(verticallayout)
136
+ horizontallayout.addWidget(self.pbar)
137
+
138
+ self.lw_3dmod_defs.clicked.connect(self.change_defs)
139
+ self.vslider_3dmodel.sliderReleased.connect(self.mod3d_vs)
140
+ self.pb_save.clicked.connect(self.save)
141
+ self.pb_refresh.clicked.connect(self.run)
142
+ self.checkbox_smooth.stateChanged.connect(self.update_plot)
143
+
144
+ def save(self):
145
+ """ This saves a jpg """
146
+ filename = QtGui.QFileDialog.getSaveFileName(
147
+ self.parent, 'Save File', '.', 'JPG (*.jpg);;PNG (*.png)')
148
+ if filename == '':
149
+ return
150
+ os.chdir(filename.rpartition('/')[0])
151
+
152
+ ftype = 'JPEG'
153
+
154
+ if 'PNG' in filename:
155
+ ftype = 'PNG'
156
+
157
+ width = self.glwidget.width()
158
+ height = self.glwidget.height()
159
+ tmp = self.glwidget.readPixels()
160
+ image = Image.fromstring('RGB', (width, height), tmp)
161
+ image = image.transpose(Image.FLIP_TOP_BOTTOM)
162
+ image.save(filename, ftype)
163
+
164
+ def update_for_kmz(self):
165
+ """ Updates for the kmz file """
166
+
167
+ self.gpoints = self.corners
168
+ self.gnorms = self.norms
169
+ self.gfaces = {}
170
+ # pdb.set_trace()
171
+
172
+ # (Pdb) self.corners[0].max(0)
173
+ # array([ 505000., 320000., 60000.])
174
+ # (Pdb) self.corners[0].min(0)
175
+ # array([ 0., 0., 31000.])
176
+
177
+
178
+ # (Pdb) self.corners[0].max(0)
179
+ # array([ 509386.36363636, 324386.36363636, -0. ])
180
+ # (Pdb) self.corners[0].min(0)
181
+ # array([ 0. , 0. , -60877.27272727])
182
+
183
+ if list(self.faces.values())[0].shape[1] == 4:
184
+ for i in list(self.faces.keys()):
185
+ self.gfaces[i] = np.append(self.faces[i][:, :-1],
186
+ self.faces[i][:, [0, 2, 3]])
187
+ self.gfaces[i].shape = (self.gfaces[i].shape[0]/3, 3)
188
+ else:
189
+ self.gfaces = self.faces.copy()
190
+
191
+ self.glutlith = range(1, len(list(self.gfaces.keys()))+1)
192
+
193
+ def change_defs(self):
194
+ """ List box routine """
195
+ if len(self.lmod1.lith_list.keys()) == 0:
196
+ return
197
+ self.set_selected_liths()
198
+ self.update_color()
199
+
200
+ def data_init(self):
201
+ """ Data initialisation routine """
202
+ self.outdata = self.indata
203
+
204
+ def set_selected_liths(self):
205
+ """ Sets the selected lithologies """
206
+ i = self.lw_3dmod_defs.selectedItems()
207
+
208
+ itxt = [j.text() for j in i]
209
+ lith = [self.lmod1.lith_list[j] for j in itxt]
210
+ lith3d = [j.lith_index for j in lith]
211
+
212
+ self.sliths = np.intersect1d(self.gdata, lith3d)
213
+
214
+ def mod3d_vs(self):
215
+ """ Vertical slider used to scale 3d view """
216
+ perc = (float(self.vslider_3dmodel.value()) /
217
+ float(self.vslider_3dmodel.maximum()))
218
+
219
+ zdist = self.lmod1.numz*self.lmod1.d_z
220
+ if self.lmod1.numx > self.lmod1.numy:
221
+ xydist = self.lmod1.numx*self.lmod1.dxy
222
+ else:
223
+ xydist = self.lmod1.numy*self.lmod1.dxy
224
+ xy_z_ratio = xydist/zdist
225
+
226
+ self.zmult = 1.0 + perc*xy_z_ratio
227
+ self.update_model2()
228
+
229
+ def update_color(self):
230
+ """ Update color only """
231
+ liths = np.unique(self.gdata)
232
+ liths = liths[liths < 900]
233
+
234
+ if liths.max() == -1:
235
+ return
236
+ if liths[0] == -1:
237
+ liths = liths[1:]
238
+ if liths[0] == 0:
239
+ liths = liths[1:]
240
+
241
+ lut = self.lut[:, [0, 1, 2]]/255.
242
+
243
+ clr = np.array([])
244
+ lcheck = np.unique(self.lmod1.lith_index)
245
+
246
+ for lno in liths:
247
+ if lno not in lcheck:
248
+ continue
249
+ if self.corners[lno] == []:
250
+ continue
251
+ if lno in self.sliths:
252
+ clrtmp = lut[lno].tolist()+[1.]
253
+ else:
254
+ clrtmp = lut[lno].tolist()+[self.opac]
255
+
256
+ clr = np.append(clr,
257
+ np.zeros([self.corners[lno].shape[0], 4])+clrtmp)
258
+
259
+ clr.shape = (clr.shape[0]/4, 4)
260
+
261
+ self.glwidget.cubeClrArray = clr
262
+
263
+ self.glwidget.init_object()
264
+ self.glwidget.updateGL()
265
+
266
+ def run(self):
267
+ """ Process data """
268
+ if 'Model3D' not in self.indata:
269
+ self.showprocesslog('No 3D model. You may need to execute' +
270
+ ' that module first')
271
+ return False
272
+
273
+ self.lmod1 = self.indata['Model3D'][0]
274
+
275
+ # self.vslider_3dmodel.setValue(1)
276
+
277
+ liths = np.unique(self.lmod1.lith_index[::1, ::1, ::-1])
278
+ liths = np.array(liths).astype(int) # needed for use in faces array
279
+ if liths[0] == -1:
280
+ liths = liths[1:]
281
+ if liths[0] == 0:
282
+ liths = liths[1:]
283
+ if liths.size == 0:
284
+ self.showprocesslog('No 3D model. You need to draw in at' +
285
+ ' least part of a lithology first.')
286
+ return False
287
+
288
+ self.show()
289
+ misc.update_lith_lw(self.lmod1, self.lw_3dmod_defs)
290
+ for i in range(self.lw_3dmod_defs.count()-1, -1, -1):
291
+ if self.lw_3dmod_defs.item(i).text() == 'Background':
292
+ self.lw_3dmod_defs.takeItem(i)
293
+
294
+ for i in range(self.lw_3dmod_defs.count()):
295
+ self.lw_3dmod_defs.item(i).setSelected(True)
296
+ self.update_plot()
297
+ return True
298
+
299
+ def update_plot(self):
300
+ """ Update 3D Model """
301
+ QtGui.QApplication.processEvents()
302
+ # Update 3D model
303
+ self.spacing = [self.lmod1.dxy, self.lmod1.dxy, self.lmod1.d_z]
304
+ self.origin = [self.lmod1.xrange[0], self.lmod1.yrange[0],
305
+ self.lmod1.zrange[0]]
306
+ self.gdata = self.lmod1.lith_index[::1, ::1, ::-1]
307
+
308
+ # update colors
309
+ i = self.lw_3dmod_defs.findItems("*", QtCore.Qt.MatchWildcard)
310
+ itxt = [j.text() for j in i]
311
+ itmp = []
312
+ for i in itxt:
313
+ itmp.append(self.lmod1.lith_list[i].lith_index)
314
+
315
+ itmp = np.sort(itmp)
316
+ tmp = np.ones((255, 4))*255
317
+
318
+ for i in itmp:
319
+ tmp[i, :3] = self.lmod1.mlut[i]
320
+
321
+ self.lut = tmp
322
+
323
+ if len(self.lmod1.lith_list.keys()) > 0:
324
+ self.set_selected_liths()
325
+ self.update_model()
326
+ self.update_model2()
327
+
328
+ self.glwidget.xRot = 0*16
329
+ self.glwidget.zRot = 0*16
330
+
331
+ self.glwidget.init_object()
332
+ self.glwidget.updateGL()
333
+
334
+ def update_model(self, issmooth=None):
335
+ """ Update the 3d model. Faces, nodes and face normals are calculated
336
+ here, from the voxel model. """
337
+ QtGui.QApplication.processEvents()
338
+
339
+ if issmooth is None:
340
+ issmooth = self.checkbox_smooth.isChecked()
341
+
342
+ self.faces = {}
343
+ self.norms = {}
344
+ self.corners = {}
345
+
346
+ liths = np.unique(self.gdata)
347
+ liths = np.array(liths).astype(int) # needed for use in faces array
348
+ lcheck = np.unique(self.lmod1.lith_index)
349
+
350
+ if liths.max() == -1:
351
+ return
352
+ if liths[0] == -1:
353
+ liths = liths[1:]
354
+
355
+ self.pbar.setMaximum(liths.size)
356
+ self.pbar.setValue(0)
357
+
358
+ if not issmooth:
359
+ igd, jgd, kgd = self.gdata.shape
360
+ cloc = np.indices(((kgd+1), (jgd+1), (igd+1))).T.reshape(
361
+ (igd+1)*(jgd+1)*(kgd+1), 3).T[::-1].T
362
+ cloc = cloc * self.spacing + self.origin
363
+ cindx = np.arange(cloc.size/3, dtype=int)
364
+ cindx.shape = (igd+1, jgd+1, kgd+1)
365
+
366
+ tmpdat = np.zeros([igd+2, jgd+2, kgd+2])-1
367
+ tmpdat[1:-1, 1:-1, 1:-1] = self.gdata
368
+
369
+ else:
370
+ # Setup stuff for triangle calcs
371
+ nshape = np.array(self.lmod1.lith_index.shape)+[2, 2, 2]
372
+ x = np.arange(nshape[1]) * self.spacing[1]
373
+ y = np.arange(nshape[0]) * self.spacing[0]
374
+ z = np.arange(nshape[2]) * self.spacing[2]
375
+ # if self.cust_z is None:
376
+ # z = np.arange(nshape[2]) * self.spacing[2]
377
+ # else:
378
+ # z = ([self.cust_z[0] - self.cust_z[1]] + self.cust_z.tolist()
379
+ # + [2*self.cust_z[-1] - self.cust_z[-2]])
380
+ xx, yy, zz = np.meshgrid(x, y, z)
381
+
382
+ # Set up gaussian smoothing filter
383
+ ix, iy, iz = np.mgrid[-1:2, -1:2, -1:2]
384
+ sigma = 2
385
+ cci = np.exp(-(ix**2+iy**2+iz**2)/(3*sigma**2))
386
+
387
+ tmppval = 0
388
+ for lno in liths:
389
+ tmppval += 1
390
+ self.pbar.setValue(tmppval)
391
+ if lno not in lcheck:
392
+ continue
393
+ if not issmooth:
394
+ gdat2 = tmpdat.copy()
395
+ gdat2[gdat2 != lno] = -0.5
396
+ gdat2[gdat2 == lno] = 0.5
397
+
398
+ newfaces = []
399
+
400
+ ndiff = np.diff(gdat2, 1, 2).astype(int)
401
+ nd1 = ndiff[1:, 1:]
402
+ nd2 = ndiff[:-1, 1:]
403
+ nd3 = ndiff[:-1, :-1]
404
+ nd4 = ndiff[1:, :-1]
405
+
406
+ c_1 = cindx[nd1 == 1]
407
+ c_2 = cindx[nd2 == 1]
408
+ c_3 = cindx[nd3 == 1]
409
+ c_4 = cindx[nd4 == 1]
410
+ ccc = np.transpose([c_1, c_4, c_3, c_2])
411
+ newfaces = np.append(newfaces, ccc)
412
+
413
+ c_1 = cindx[nd1 == -1]
414
+ c_2 = cindx[nd2 == -1]
415
+ c_3 = cindx[nd3 == -1]
416
+ c_4 = cindx[nd4 == -1]
417
+ ccc = np.transpose([c_1, c_2, c_3, c_4])
418
+ newfaces = np.append(newfaces, ccc)
419
+
420
+ ndiff = np.diff(gdat2, 1, 1).astype(int)
421
+ nd1 = ndiff[1:, :, 1:]
422
+ nd2 = ndiff[:-1, :, 1:]
423
+ nd3 = ndiff[:-1, :, :-1]
424
+ nd4 = ndiff[1:, :, :-1]
425
+
426
+ c_1 = cindx[nd1 == 1]
427
+ c_2 = cindx[nd2 == 1]
428
+ c_3 = cindx[nd3 == 1]
429
+ c_4 = cindx[nd4 == 1]
430
+ ccc = np.transpose([c_1, c_2, c_3, c_4])
431
+ newfaces = np.append(newfaces, ccc)
432
+
433
+ c_1 = cindx[nd1 == -1]
434
+ c_2 = cindx[nd2 == -1]
435
+ c_3 = cindx[nd3 == -1]
436
+ c_4 = cindx[nd4 == -1]
437
+ ccc = np.transpose([c_1, c_4, c_3, c_2])
438
+ newfaces = np.append(newfaces, ccc)
439
+
440
+ ndiff = np.diff(gdat2, 1, 0).astype(int)
441
+ nd1 = ndiff[:, 1:, 1:]
442
+ nd2 = ndiff[:, 1:, :-1]
443
+ nd3 = ndiff[:, :-1, :-1]
444
+ nd4 = ndiff[:, :-1, 1:]
445
+
446
+ c_1 = cindx[nd1 == 1]
447
+ c_2 = cindx[nd2 == 1]
448
+ c_3 = cindx[nd3 == 1]
449
+ c_4 = cindx[nd4 == 1]
450
+ ccc = np.transpose([c_1, c_2, c_3, c_4])
451
+ newfaces = np.append(newfaces, ccc)
452
+
453
+ c_1 = cindx[nd1 == -1]
454
+ c_2 = cindx[nd2 == -1]
455
+ c_3 = cindx[nd3 == -1]
456
+ c_4 = cindx[nd4 == -1]
457
+ ccc = np.transpose([c_1, c_4, c_3, c_2])
458
+ newfaces = np.append(newfaces, ccc)
459
+
460
+ uuu, i = np.unique(newfaces, return_inverse=True)
461
+ uuu = uuu.astype(int)
462
+ n_f = np.arange(uuu.size)
463
+ newfaces = n_f[i]
464
+ newcorners = cloc[uuu]
465
+ newfaces.shape = (newfaces.size/4, 4)
466
+
467
+ self.faces[lno] = newfaces
468
+ self.corners[lno] = newcorners
469
+
470
+ else:
471
+ c = np.zeros(nshape)
472
+
473
+ cc = self.lmod1.lith_index.copy()
474
+ cc[cc != lno] = 0
475
+ cc[cc == lno] = 1
476
+
477
+ cc = sf.convolve(cc, cci)/cci.size
478
+
479
+ # shrink cc to match only visible lithology? Origin offset would need to be
480
+ # checked.
481
+
482
+ c[1:-1, 1:-1, 1:-1] = cc
483
+
484
+ faces, vtx = MarchingCubes(xx, yy, zz, c, .1)
485
+
486
+ if vtx == []:
487
+ self.faces[lno] = []
488
+ self.corners[lno] = []
489
+ self.norms[lno] = []
490
+ continue
491
+
492
+ self.faces[lno] = faces
493
+
494
+ vtx[:, 2] *= -1
495
+ vtx[:, 2] += zz.max()
496
+
497
+ self.corners[lno] = vtx[:, [1, 0, 2]] + self.origin
498
+
499
+ self.norms[lno] = calc_norms(self.faces[lno], self.corners[lno])
500
+
501
+ # ftmp = np.transpose(self.faces[lno])
502
+ # I = np.lexsort(ftmp)
503
+ # self.faces[lno] = self.faces[lno][I]
504
+
505
+ def update_model2(self):
506
+ """ Update the 3d model. Faces, nodes and face normals are calculated
507
+ here, from the voxel model. """
508
+ liths = np.unique(self.gdata)
509
+ liths = np.array(liths).astype(int) # needed for use in faces array
510
+ liths = liths[liths < 900]
511
+
512
+ if liths.max() == -1:
513
+ return
514
+ if liths[0] == -1:
515
+ liths = liths[1:]
516
+ if liths[0] == 0:
517
+ liths = liths[1:]
518
+
519
+ lut = self.lut[:, [0, 1, 2]]/255.
520
+
521
+ vtx = np.array([])
522
+ clr = np.array([])
523
+ nrm = np.array([])
524
+ idx = np.array([])
525
+ idxmax = 0
526
+ lcheck = np.unique(self.lmod1.lith_index)
527
+
528
+ self.pbar.setMaximum(liths.size)
529
+ self.pbar.setValue(0)
530
+ tmppval = 0
531
+
532
+ for lno in liths:
533
+ tmppval += 1
534
+ self.pbar.setValue(tmppval)
535
+
536
+ if lno not in lcheck:
537
+ continue
538
+ if self.corners[lno] == []:
539
+ continue
540
+ if lno in self.sliths:
541
+ clrtmp = lut[lno].tolist()+[1.]
542
+ else:
543
+ clrtmp = lut[lno].tolist()+[self.opac]
544
+
545
+ vtx = np.append(vtx, self.corners[lno])
546
+ clr = np.append(clr,
547
+ np.zeros([self.corners[lno].shape[0], 4])+clrtmp)
548
+
549
+ nrm2 = calc_norms(self.faces[lno], self.corners[lno] *
550
+ [1, 1, self.zmult])
551
+
552
+ nrm = np.append(nrm, nrm2)
553
+ idx = np.append(idx, self.faces[lno].flatten()+idxmax)
554
+ idxmax = idx.max()+1
555
+
556
+ vtx.shape = (vtx.shape[0]/3, 3)
557
+ clr.shape = (clr.shape[0]/4, 4)
558
+
559
+ vtx[:, -1] = (vtx[:, -1]-self.origin[-1])*self.zmult + self.origin[-1]
560
+
561
+ cptp = vtx.ptp(0).max()/100.
562
+ cmin = vtx.min(0)
563
+ cptpd2 = vtx.ptp(0)/2.
564
+ vtx = (vtx-cmin-cptpd2)/cptp
565
+
566
+ self.glwidget.hastriangles = self.checkbox_smooth.isChecked()
567
+ self.glwidget.cubeVtxArray = vtx
568
+ self.glwidget.cubeClrArray = clr
569
+ self.glwidget.cubeNrmArray = nrm
570
+ self.glwidget.cubeIdxArray = idx.astype(np.uint32)
571
+
572
+ self.glwidget.init_object()
573
+ self.glwidget.updateGL()
574
+
575
+
576
+ class GLWidget(QtOpenGL.QGLWidget):
577
+ """ OpenGL Widget """
578
+ def __init__(self, parent=None):
579
+ super(GLWidget, self).__init__(parent)
580
+
581
+ self.data = None
582
+ self.idx = None
583
+ self.data_buffer = None
584
+ self.indx_buffer = None
585
+ self.xRot = 0
586
+ self.yRot = 0
587
+ self.zRot = 0
588
+ self.zoomfactor = 1.0
589
+ self.aspect = 1.
590
+ self.glist = None
591
+ self.hastriangles = False
592
+
593
+ self.cubeVtxArray = np.array([[0.0, 0.0, 0.0],
594
+ [1.0, 0.0, 0.0],
595
+ [1.0, 1.0, 0.0],
596
+ [0.0, 1.0, 0.0],
597
+ [0.0, 0.0, 1.0],
598
+ [1.0, 0.0, 1.0],
599
+ [1.0, 1.0, 1.0],
600
+ [0.0, 1.0, 1.0]])
601
+
602
+ self.cubeIdxArray = np.array([0, 1, 2, 3,
603
+ 3, 2, 6, 7,
604
+ 1, 0, 4, 5,
605
+ 2, 1, 5, 6,
606
+ 0, 3, 7, 4,
607
+ 7, 6, 5, 4])
608
+
609
+ self.cubeClrArray = np.array([[0.0, 0.0, 0.0, 0.0],
610
+ [1.0, 0.0, 0.0, 0.0],
611
+ [1.0, 1.0, 0.0, 0.0],
612
+ [0.0, 1.0, 0.0, 0.0],
613
+ [0.0, 0.0, 1.0, 0.0],
614
+ [1.0, 0.0, 1.0, 0.0],
615
+ [1.0, 1.0, 1.0, 0.0],
616
+ [0.0, 1.0, 1.0, 0.0]])
617
+
618
+ self.cubeNrmArray = np.array([[0.0, 0.0, 0.0],
619
+ [1.0, 0.0, 0.0],
620
+ [0.0, 1.0, 0.0],
621
+ [0.0, 1.0, 0.0],
622
+ [0.0, 0.0, 1.0],
623
+ [0.0, 0.0, 1.0],
624
+ [1.0, 0.0, 0.0],
625
+ [0.0, 1.0, 0.0]])
626
+
627
+ self.lastPos = QtCore.QPoint()
628
+
629
+ def minimumSizeHint(self):
630
+ """ minimum size hint """
631
+ return QtCore.QSize(50, 50)
632
+
633
+ def sizeHint(self):
634
+ """ size hint """
635
+ return QtCore.QSize(400, 400)
636
+
637
+ def setXRotation(self, angle):
638
+ """ set X rotation """
639
+ angle = self.normalizeAngle(angle)
640
+ if angle != self.xRot:
641
+ self.xRot = angle
642
+
643
+ def setYRotation(self, angle):
644
+ """ set Y rotation """
645
+ angle = self.normalizeAngle(angle)
646
+ if angle != self.yRot:
647
+ self.yRot = angle
648
+
649
+ def setZRotation(self, angle):
650
+ """ set Z rotation """
651
+ angle = self.normalizeAngle(angle)
652
+ if angle != self.zRot:
653
+ self.zRot = angle
654
+
655
+ def initializeGL(self):
656
+ """ initialize OpenGL """
657
+ ctmp = QtGui.QColor.fromCmykF(0., 0., 0., 0.0)
658
+ self.qglClearColor(ctmp)
659
+ self.initGeometry()
660
+
661
+ # GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE)
662
+ # GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL)
663
+ # GL.glShadeModel(GL.GL_SMOOTH)
664
+
665
+ #############
666
+ # GL.glEnable(GL.GL_NORMALIZE)
667
+ # Blend allows transparency
668
+
669
+ GL.glEnable(GL.GL_ALPHA_TEST)
670
+ GL.glAlphaFunc(GL.GL_GREATER, 0.1)
671
+ GL.glEnable(GL.GL_DEPTH_TEST)
672
+ GL.glDepthMask(GL.GL_TRUE)
673
+ GL.glDepthFunc(GL.GL_LEQUAL)
674
+
675
+ GL.glEnable(GL.GL_CULL_FACE)
676
+
677
+ GL.glEnable(GL.GL_COLOR_MATERIAL)
678
+ GL.glEnable(GL.GL_LIGHTING)
679
+ GL.glEnable(GL.GL_LIGHT0)
680
+ GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, [1., 1., 1., 0.])
681
+
682
+ ##################
683
+ # GL.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, [1.,1.,1.,1.])
684
+ # GL.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, [1.,1.,1.,1.])
685
+ # GL.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, [0.,0.,0.,1.])
686
+ #
687
+ # GL.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, [0., 1., 0., 1.0])
688
+ # GL.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, [1., 0., 0., 1.0])
689
+ #
690
+ # shininess = 64.
691
+ # GL.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, [1., 1., 1., 1.0])
692
+ # GL.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, shininess);
693
+
694
+ def initGeometry(self):
695
+ """ Initialize Geometry """
696
+ self.init_object()
697
+
698
+ def init_object(self):
699
+ """ Initialise VBO """
700
+ self.cubeNrmArray.shape = self.cubeVtxArray.shape
701
+
702
+ data = np.hstack((self.cubeVtxArray,
703
+ self.cubeClrArray,
704
+ self.cubeNrmArray))
705
+
706
+ data = data.astype(np.float32)
707
+ idx = self.cubeIdxArray.astype(np.uint32)
708
+
709
+ if self.data_buffer is None:
710
+ self.data_buffer = vbo.VBO(data)
711
+ self.indx_buffer = vbo.VBO(idx, target='GL_ELEMENT_ARRAY_BUFFER')
712
+ else:
713
+ self.data_buffer.set_array(data)
714
+ self.indx_buffer.set_array(idx)
715
+
716
+ def paintGL(self):
717
+ """ Paint OpenGL """
718
+ float_size = 4
719
+ voff = 0 * float_size
720
+ coff = 3 * float_size
721
+ noff = 7 * float_size
722
+ record_len = 10 * float_size
723
+
724
+ GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
725
+
726
+ self.data_buffer.bind()
727
+ self.indx_buffer.bind()
728
+
729
+ GL.glEnableClientState(GL.GL_VERTEX_ARRAY)
730
+ GL.glEnableClientState(GL.GL_COLOR_ARRAY)
731
+ GL.glEnableClientState(GL.GL_NORMAL_ARRAY)
732
+ GL.glVertexPointer(3, GL.GL_FLOAT, record_len, self.data_buffer + voff)
733
+ GL.glColorPointer(4, GL.GL_FLOAT, record_len, self.data_buffer + coff)
734
+ GL.glNormalPointer(GL.GL_FLOAT, record_len, self.data_buffer + noff)
735
+
736
+ GL.glLoadIdentity()
737
+ GL.glTranslated(0.0, 0.0, -100.0)
738
+ GL.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
739
+ GL.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
740
+ GL.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
741
+
742
+ if self.hastriangles:
743
+ GL.glDrawElements(GL.GL_TRIANGLES, self.cubeIdxArray.size,
744
+ GL.GL_UNSIGNED_INT, self.indx_buffer)
745
+ else:
746
+ GL.glDrawElements(GL.GL_QUADS, self.cubeIdxArray.size,
747
+ GL.GL_UNSIGNED_INT, self.indx_buffer)
748
+
749
+ self.data_buffer.unbind()
750
+ self.indx_buffer.unbind()
751
+
752
+ GL.glDisableClientState(GL.GL_VERTEX_ARRAY)
753
+ GL.glDisableClientState(GL.GL_COLOR_ARRAY)
754
+ GL.glDisableClientState(GL.GL_NORMAL_ARRAY)
755
+
756
+ def resizeGL(self, width, height):
757
+ """ Resize OpenGL """
758
+ side = min(width, height)
759
+ if side < 0:
760
+ return
761
+
762
+ GL.glViewport((width - side) // 2, (height - side) // 2, side, side)
763
+
764
+ GL.glMatrixMode(GL.GL_PROJECTION)
765
+ GL.glLoadIdentity()
766
+ self.aspect = width / float(height)
767
+ # GL.glFrustum(-1.0, +1.0, -1.0, 1.0, 1.0, 201.)
768
+
769
+ GLU.gluPerspective(70.0*self.zoomfactor, self.aspect, 1.0, 201.0)
770
+
771
+ GL.glMatrixMode(GL.GL_MODELVIEW)
772
+
773
+ def readPixels(self):
774
+ """ Reads pixels from the window """
775
+ data = GL.glReadPixels(0, 0, self.width(), self.height(), GL.GL_RGB,
776
+ GL.GL_UNSIGNED_BYTE)
777
+ return data
778
+
779
+ def mousePressEvent(self, event):
780
+ """ Mouse Press Event """
781
+ self.lastPos = event.pos()
782
+
783
+ def mouseMoveEvent(self, event):
784
+ """ Mouse Move Event """
785
+ dxx = event.x() - self.lastPos.x()
786
+ dyy = event.y() - self.lastPos.y()
787
+
788
+ if event.buttons() & QtCore.Qt.LeftButton:
789
+ self.setXRotation(self.xRot + 8 * dyy)
790
+ self.setYRotation(self.yRot + 8 * dxx)
791
+ elif event.buttons() & QtCore.Qt.RightButton:
792
+ self.setXRotation(self.xRot + 8 * dyy)
793
+ self.setZRotation(self.zRot + 8 * dxx)
794
+
795
+ self.updateGL()
796
+ self.lastPos = event.pos()
797
+
798
+ def wheelEvent(self, event):
799
+ """ Mouse wheel event """
800
+ self.zoomfactor -= event.delta()/1000.
801
+
802
+ GL.glMatrixMode(GL.GL_PROJECTION)
803
+ GL.glLoadIdentity()
804
+ GLU.gluPerspective(70.0*self.zoomfactor, self.aspect, 1.0, 201.0)
805
+
806
+ GL.glMatrixMode(GL.GL_MODELVIEW)
807
+ self.updateGL()
808
+
809
+ def normalizeAngle(self, angle):
810
+ """ Normalize angle """
811
+ while angle < 0:
812
+ angle += 360 * 16
813
+ while angle > 360 * 16:
814
+ angle -= 360 * 16
815
+ return angle
816
+
817
+
818
+ def calc_norms(faces, vtx):
819
+ """ Calculates normals """
820
+
821
+ nrm = np.zeros(vtx.shape, dtype=vtx.dtype)
822
+ tris = vtx[faces]
823
+ n = np.cross(tris[::, 1] - tris[::, 0], tris[::, 2] -
824
+ tris[::, 0])
825
+ normalize_v3(n)
826
+
827
+ nrm[faces[:, 0]] += n
828
+ nrm[faces[:, 1]] += n
829
+ nrm[faces[:, 2]] += n
830
+
831
+ normalize_v3(nrm)
832
+
833
+ return nrm
834
+
835
+
836
+ def normalize_v3(arr):
837
+ ''' Normalize a numpy array of 3 component vectors shape=(n,3) '''
838
+ lens = np.sqrt(arr[:, 0]**2 + arr[:, 1]**2 + arr[:, 2]**2)
839
+ lens[lens == 0] = 1 # Get rid of divide by zero.
840
+
841
+ arr /= lens[:, np.newaxis]
842
+ # arr[:, 0] /= lens
843
+ # arr[:, 1] /= lens
844
+ # arr[:, 2] /= lens
845
+ return arr
846
+
847
+
848
+ def MarchingCubes(x, y, z, c, iso):
849
+ """
850
+ # function [F,V,col] = MarchingCubes(x,y,z,c,iso,colors)
851
+
852
+ # [F,V] = MarchingCubes(X,Y,Z,C,ISO)
853
+ # [F,V,COL] = MarchingCubes(X,Y,Z,C,ISO,COLORS)
854
+ #
855
+ # Use marching cubes algorithm to compute a triangulated mesh of the
856
+ # isosurface within the 3D matrix of scalar values C at isosurface value
857
+ # ISO. The 3D matrices (X,Y,Z) represent a Cartesian, axis-aligned grid
858
+ # specifying the points at which the data C is given. These coordinate
859
+ # arrays must be in the format produced by Matlab's meshgrid function.
860
+ # Output arguments F and V are the face list and vertex list
861
+ # of the resulting triangulated mesh. The orientation of the triangles is
862
+ # chosen such that the normals point from the higher values to the lower
863
+ # values. Optional arguments COLORS ans COLS can be used to produce
864
+ # interpolated mesh face colors. For usage, see Matlab's isosurface.m.
865
+ # To avoid Out of Memory errors when matrix C is large, convert matrices
866
+ # X,Y,Z and C from doubles (Matlab default) to singles (32-bit floats).
867
+ #
868
+ # Adapted for Matlab by Peter Hammer in 2011 based on an
869
+ # Octave function written by Martin Helm <martin@mhelm.de> in 2009
870
+ # http://www.mhelm.de/octave/m/marching_cube.m
871
+ #
872
+ # Revised 30 September, 2011 to add code by Oliver Woodford for removing
873
+ # duplicate vertices.
874
+
875
+ # error('x, y, z, c must be matrices of dim 3')
876
+ # error('x, y, z, c must be the same size')
877
+ # error('grid size must be at least 2x2x2')
878
+ # error('iso needs to be scalar value')
879
+ # error( 'color must be matrix of same size as c')
880
+ """
881
+ lindex = 4
882
+
883
+ [edgeTable, triTable] = GetTables()
884
+
885
+ n = np.array(c.shape) - 1 # number of cubes along each direction of image
886
+
887
+ # for each cube, assign which edges are intersected by the isosurface
888
+ # 3d array of 8-bit vertex codes
889
+ cc = np.zeros(n, dtype=np.uint16)
890
+
891
+ n1 = np.arange(n[0])
892
+ n2 = np.arange(n[1])
893
+ n3 = np.arange(n[2])
894
+
895
+ vertex_idx = np.array([[n1, n2, n3],
896
+ [n1+1, n2, n3],
897
+ [n1+1, n2+1, n3],
898
+ [n1, n2+1, n3],
899
+ [n1, n2, n3+1],
900
+ [n1+1, n2, n3+1],
901
+ [n1+1, n2+1, n3+1],
902
+ [n1, n2+1, n3+1]])
903
+
904
+ # loop thru vertices of all cubes
905
+
906
+ out = np.zeros(n)
907
+ for ii in range(8):
908
+ # which cubes have vtx ii > iso
909
+ tmp2 = fancyindex(out, c, vertex_idx[ii, 0], vertex_idx[ii, 1],
910
+ vertex_idx[ii, 2])
911
+ idx = tmp2 > iso
912
+ cc[idx] = bitset(cc[idx], ii) # for those cubes, turn bit ii on
913
+
914
+ # intersected edges for each cube ([n1 x n2 x n3] mtx)
915
+ cedge = edgeTable[cc]
916
+ # voxels which are intersected (col of indcs into cedge)
917
+ iden = np.nonzero(cedge.flatten(order='F'))[0]
918
+
919
+ if iden.size == 0: # all voxels are above or below iso
920
+ print('No such lithology, or all voxels are above or below iso')
921
+ F = []
922
+ V = []
923
+ return F, V
924
+
925
+ # calculate the list of intersection points
926
+ xyz_off = np.array([[1, 1, 1],
927
+ [2, 1, 1],
928
+ [2, 2, 1],
929
+ [1, 2, 1],
930
+ [1, 1, 2],
931
+ [2, 1, 2],
932
+ [2, 2, 2],
933
+ [1, 2, 2]])-1
934
+ edges = np.array([[1, 2], [2, 3], [3, 4], [4, 1],
935
+ [5, 6], [6, 7], [7, 8], [8, 5],
936
+ [1, 5], [2, 6], [3, 7], [4, 8]])-1
937
+
938
+ offset = sub2ind(c.shape, xyz_off[:, 0], xyz_off[:, 1], xyz_off[:, 2])
939
+ pp = np.zeros([iden.size, lindex, 12])
940
+ ccedge = np.array([cedge.flatten(order='F')[iden], iden]) # uses vec
941
+ ccedge = ccedge.T
942
+ ix_offset = 0
943
+
944
+ x = x.flatten(order='F')
945
+ y = y.flatten(order='F')
946
+ z = z.flatten(order='F')
947
+ cp = c.flatten(order='F')
948
+
949
+ for jj in range(12):
950
+ id__ = bitget(ccedge[:, 0], jj) # used for logical indexing
951
+ id_ = ccedge[id__, 1]
952
+ ix, iy, iz = ind2sub(cc.shape, id_)
953
+ id_c = sub2ind(c.shape, ix, iy, iz)
954
+ id1 = id_c + offset[edges[jj, 0]]
955
+ id2 = id_c + offset[edges[jj, 1]]
956
+
957
+ pp[id__, :3, jj] = InterpolateVertices(iso,
958
+ x[id1], y[id1], z[id1],
959
+ x[id2], y[id2], z[id2],
960
+ cp[id1], cp[id2])
961
+ pp[id__, 3, jj] = np.arange(1, id_.shape[0]+1) + ix_offset
962
+
963
+ ix_offset = ix_offset + id_.shape[0]
964
+
965
+ pp2 = pp.astype(int)
966
+ # calculate the triangulation from the point list
967
+ F1 = np.array([], dtype=np.int32)
968
+ F2 = np.array([], dtype=np.int32)
969
+ F3 = np.array([], dtype=np.int32)
970
+ tri = triTable[cc.flatten(order='F')[iden]]
971
+
972
+ pp2f = pp2.flatten(order='F')
973
+
974
+ for jj in range(0, 15, 3):
975
+ id_ = np.nonzero(tri[:, jj] > 0)[0]
976
+ if id_.size > 0:
977
+ V = np.zeros([id_.size, 5], dtype=int)
978
+ V[:, 0] = id_
979
+ V[:, 1] = (lindex-1)*np.ones(id_.shape[0])
980
+ V[:, 2] = tri[id_, jj] - 1
981
+ V[:, 3] = tri[id_, jj+1] - 1
982
+ V[:, 4] = tri[id_, jj+2] - 1
983
+
984
+ p1 = sub2ind(pp.shape, V[:, 0], V[:, 1], V[:, 2])
985
+ p2 = sub2ind(pp.shape, V[:, 0], V[:, 1], V[:, 3])
986
+ p3 = sub2ind(pp.shape, V[:, 0], V[:, 1], V[:, 4])
987
+
988
+ F1 = np.hstack((F1, pp2f[p1]))
989
+ F2 = np.hstack((F2, pp2f[p2]))
990
+ F3 = np.hstack((F3, pp2f[p3]))
991
+
992
+ F = np.transpose([F1, F2, F3])-1
993
+ V = np.zeros([pp2.max(), 3])
994
+
995
+ for jj in range(12):
996
+ idp = pp[:, lindex-1, jj] > 0
997
+ if any(idp):
998
+ V[pp2[idp, lindex-1, jj]-1, :3] = pp[idp, :3, jj]
999
+
1000
+ # Remove duplicate vertices (by Oliver Woodford)
1001
+ I = np.lexsort(V.T)
1002
+ V = V[I]
1003
+
1004
+ M = np.hstack(([True], np.sum(np.abs(V[1:]-V[:-1]), 1).astype(bool)))
1005
+
1006
+ V = V[M]
1007
+ newI = np.zeros_like(I)
1008
+ newI[I] = np.cumsum(M)-1
1009
+ F = newI[F]
1010
+
1011
+ return F, V
1012
+ # ============================================================
1013
+ # ================== SUBFUNCTIONS ===========================
1014
+ # ============================================================
1015
+
1016
+
1017
+ def InterpolateVertices(isolevel, p1x, p1y, p1z, p2x, p2y, p2z, valp1, valp2):
1018
+ """Interpolate vertices """
1019
+ p = np.zeros([len(p1x), 3])
1020
+
1021
+ eps = np.spacing(1)
1022
+ mu = np.zeros(len(p1x))
1023
+ iden = abs(valp1-valp2) < (10*eps) * (abs(valp1) + abs(valp2))
1024
+ if any(iden):
1025
+ p[iden, 0] = p1x[iden]
1026
+ p[iden, 1] = p1y[iden]
1027
+ p[iden, 2] = p1z[iden]
1028
+
1029
+ nid = np.logical_not(iden)
1030
+
1031
+ if any(nid):
1032
+ mu[nid] = (isolevel - valp1[nid]) / (valp2[nid] - valp1[nid])
1033
+ p[nid, 0] = p1x[nid] + mu[nid] * (p2x[nid] - p1x[nid])
1034
+ p[nid, 1] = p1y[nid] + mu[nid] * (p2y[nid] - p1y[nid])
1035
+ p[nid, 2] = p1z[nid] + mu[nid] * (p2z[nid] - p1z[nid])
1036
+ return p
1037
+
1038
+
1039
+ @jit
1040
+ def fancyindex(out, var1, ii, jj, kk):
1041
+ """ fancy """
1042
+
1043
+ i1 = -1
1044
+ for i in ii:
1045
+ i1 += 1
1046
+ j1 = -1
1047
+ for j in jj:
1048
+ j1 += 1
1049
+ k1 = -1
1050
+ for k in kk:
1051
+ k1 += 1
1052
+ out[i1, j1, k1] = var1[i, j, k]
1053
+ return out
1054
+
1055
+
1056
+ def bitget(byteval, idx):
1057
+ """ bitget """
1058
+ return (byteval & (1 << idx)) != 0
1059
+
1060
+
1061
+ def bitset(byteval, idx):
1062
+ """ bitset """
1063
+ return byteval | (1 << idx)
1064
+
1065
+
1066
+ def sub2ind(msize, row, col, layer):
1067
+ """ Sub2ind """
1068
+ nrows, ncols, _ = msize
1069
+ # tmp = layer*ncols*nrows+row*ncols+col
1070
+ tmp = layer*ncols*nrows+nrows*col+row
1071
+ return tmp.astype(int)
1072
+
1073
+
1074
+ def ind2sub(msize, idx):
1075
+ """ Sub2ind """
1076
+ nrows, ncols, _ = msize
1077
+ layer = idx/(nrows*ncols)
1078
+ layer = layer.astype(int)
1079
+ idx = idx - layer*nrows*ncols
1080
+ col = idx/nrows
1081
+ col = col.astype(int)
1082
+ row = idx - col*nrows
1083
+
1084
+ return row, col, layer
1085
+
1086
+
1087
+ def GetTables():
1088
+ """ Get Tables """
1089
+ edgeTable = np.array([0, 265, 515, 778, 1030, 1295, 1541, 1804,
1090
+ 2060, 2309, 2575, 2822, 3082, 3331, 3593, 3840,
1091
+ 400, 153, 915, 666, 1430, 1183, 1941, 1692,
1092
+ 2460, 2197, 2975, 2710, 3482, 3219, 3993, 3728,
1093
+ 560, 825, 51, 314, 1590, 1855, 1077, 1340,
1094
+ 2620, 2869, 2111, 2358, 3642, 3891, 3129, 3376,
1095
+ 928, 681, 419, 170, 1958, 1711, 1445, 1196,
1096
+ 2988, 2725, 2479, 2214, 4010, 3747, 3497, 3232,
1097
+ 1120, 1385, 1635, 1898, 102, 367, 613, 876,
1098
+ 3180, 3429, 3695, 3942, 2154, 2403, 2665, 2912,
1099
+ 1520, 1273, 2035, 1786, 502, 255, 1013, 764,
1100
+ 3580, 3317, 4095, 3830, 2554, 2291, 3065, 2800,
1101
+ 1616, 1881, 1107, 1370, 598, 863, 85, 348,
1102
+ 3676, 3925, 3167, 3414, 2650, 2899, 2137, 2384,
1103
+ 1984, 1737, 1475, 1226, 966, 719, 453, 204,
1104
+ 4044, 3781, 3535, 3270, 3018, 2755, 2505, 2240,
1105
+ 2240, 2505, 2755, 3018, 3270, 3535, 3781, 4044,
1106
+ 204, 453, 719, 966, 1226, 1475, 1737, 1984,
1107
+ 2384, 2137, 2899, 2650, 3414, 3167, 3925, 3676,
1108
+ 348, 85, 863, 598, 1370, 1107, 1881, 1616,
1109
+ 2800, 3065, 2291, 2554, 3830, 4095, 3317, 3580,
1110
+ 764, 1013, 255, 502, 1786, 2035, 1273, 1520,
1111
+ 2912, 2665, 2403, 2154, 3942, 3695, 3429, 3180,
1112
+ 876, 613, 367, 102, 1898, 1635, 1385, 1120,
1113
+ 3232, 3497, 3747, 4010, 2214, 2479, 2725, 2988,
1114
+ 1196, 1445, 1711, 1958, 170, 419, 681, 928,
1115
+ 3376, 3129, 3891, 3642, 2358, 2111, 2869, 2620,
1116
+ 1340, 1077, 1855, 1590, 314, 51, 825, 560,
1117
+ 3728, 3993, 3219, 3482, 2710, 2975, 2197, 2460,
1118
+ 1692, 1941, 1183, 1430, 666, 915, 153, 400,
1119
+ 3840, 3593, 3331, 3082, 2822, 2575, 2309, 2060,
1120
+ 1804, 1541, 1295, 1030, 778, 515, 265, 0])
1121
+
1122
+ triTable = np.array([
1123
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1124
+ [0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1125
+ [0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1126
+ [1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1127
+ [1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1128
+ [0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1129
+ [9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1130
+ [2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1],
1131
+ [3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1132
+ [0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1133
+ [1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1134
+ [1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1],
1135
+ [3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1136
+ [0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1],
1137
+ [3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1],
1138
+ [9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1139
+ [4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1140
+ [4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1141
+ [0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1142
+ [4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1],
1143
+ [1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1144
+ [3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1],
1145
+ [9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1],
1146
+ [2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1],
1147
+ [8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1148
+ [11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1],
1149
+ [9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1],
1150
+ [4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1],
1151
+ [3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1],
1152
+ [1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1],
1153
+ [4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1],
1154
+ [4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1],
1155
+ [9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1156
+ [9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1157
+ [0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1158
+ [8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1],
1159
+ [1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1160
+ [3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1],
1161
+ [5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1],
1162
+ [2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1],
1163
+ [9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1164
+ [0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1],
1165
+ [0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1],
1166
+ [2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1],
1167
+ [10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1],
1168
+ [4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1],
1169
+ [5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1],
1170
+ [5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1],
1171
+ [9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1172
+ [9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1],
1173
+ [0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1],
1174
+ [1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1175
+ [9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1],
1176
+ [10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1],
1177
+ [8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1],
1178
+ [2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1],
1179
+ [7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1],
1180
+ [9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1],
1181
+ [2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1],
1182
+ [11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1],
1183
+ [9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1],
1184
+ [5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1],
1185
+ [11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1],
1186
+ [11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1187
+ [10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1188
+ [0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1189
+ [9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1190
+ [1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1],
1191
+ [1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1192
+ [1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1],
1193
+ [9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1],
1194
+ [5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1],
1195
+ [2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1196
+ [11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1],
1197
+ [0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1],
1198
+ [5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1],
1199
+ [6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1],
1200
+ [0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1],
1201
+ [3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1],
1202
+ [6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1],
1203
+ [5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1204
+ [4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1],
1205
+ [1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1],
1206
+ [10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1],
1207
+ [6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1],
1208
+ [1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1],
1209
+ [8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1],
1210
+ [7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1],
1211
+ [3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1],
1212
+ [5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1],
1213
+ [0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1],
1214
+ [9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1],
1215
+ [8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1],
1216
+ [5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1],
1217
+ [0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1],
1218
+ [6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1],
1219
+ [10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1220
+ [4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1],
1221
+ [10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1],
1222
+ [8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1],
1223
+ [1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1],
1224
+ [3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1],
1225
+ [0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1226
+ [8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1],
1227
+ [10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1],
1228
+ [0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1],
1229
+ [3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1],
1230
+ [6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1],
1231
+ [9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1],
1232
+ [8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1],
1233
+ [3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1],
1234
+ [6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1235
+ [7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1],
1236
+ [0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1],
1237
+ [10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1],
1238
+ [10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1],
1239
+ [1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1],
1240
+ [2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1],
1241
+ [7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1],
1242
+ [7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1243
+ [2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1],
1244
+ [2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1],
1245
+ [1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1],
1246
+ [11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1],
1247
+ [8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1],
1248
+ [0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1249
+ [7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1],
1250
+ [7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1251
+ [7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1252
+ [3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1253
+ [0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1254
+ [8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1],
1255
+ [10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1256
+ [1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1],
1257
+ [2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1],
1258
+ [6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1],
1259
+ [7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1260
+ [7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1],
1261
+ [2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1],
1262
+ [1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1],
1263
+ [10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1],
1264
+ [10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1],
1265
+ [0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1],
1266
+ [7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1],
1267
+ [6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1268
+ [3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1],
1269
+ [8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1],
1270
+ [9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1],
1271
+ [6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1],
1272
+ [1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1],
1273
+ [4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1],
1274
+ [10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1],
1275
+ [8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1],
1276
+ [0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1277
+ [1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1],
1278
+ [1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1],
1279
+ [8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1],
1280
+ [10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1],
1281
+ [4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1],
1282
+ [10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1283
+ [4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1284
+ [0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1],
1285
+ [5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1],
1286
+ [11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1],
1287
+ [9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1],
1288
+ [6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1],
1289
+ [7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1],
1290
+ [3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1],
1291
+ [7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1],
1292
+ [9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1],
1293
+ [3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1],
1294
+ [6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1],
1295
+ [9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1],
1296
+ [1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1],
1297
+ [4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1],
1298
+ [7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1],
1299
+ [6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1],
1300
+ [3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1],
1301
+ [0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1],
1302
+ [6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1],
1303
+ [1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1],
1304
+ [0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1],
1305
+ [11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1],
1306
+ [6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1],
1307
+ [5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1],
1308
+ [9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1],
1309
+ [1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1],
1310
+ [1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1311
+ [1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1],
1312
+ [10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1],
1313
+ [0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1314
+ [10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1315
+ [11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1316
+ [11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1],
1317
+ [5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1],
1318
+ [10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1],
1319
+ [11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1],
1320
+ [0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1],
1321
+ [9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1],
1322
+ [7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1],
1323
+ [2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1],
1324
+ [8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1],
1325
+ [9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1],
1326
+ [9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1],
1327
+ [1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1328
+ [0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1],
1329
+ [9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1],
1330
+ [9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1331
+ [5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1],
1332
+ [5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1],
1333
+ [0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1],
1334
+ [10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1],
1335
+ [2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1],
1336
+ [0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1],
1337
+ [0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1],
1338
+ [9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1339
+ [2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1],
1340
+ [5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1],
1341
+ [3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1],
1342
+ [5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1],
1343
+ [8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1],
1344
+ [0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1345
+ [8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1],
1346
+ [9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1347
+ [4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1],
1348
+ [0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1],
1349
+ [1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1],
1350
+ [3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1],
1351
+ [4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1],
1352
+ [9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1],
1353
+ [11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1],
1354
+ [11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1],
1355
+ [2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1],
1356
+ [9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1],
1357
+ [3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1],
1358
+ [1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1359
+ [4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1],
1360
+ [4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1],
1361
+ [4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1362
+ [4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1363
+ [9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1364
+ [3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1],
1365
+ [0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1],
1366
+ [3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1367
+ [1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1],
1368
+ [3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1],
1369
+ [0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1370
+ [3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1371
+ [2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1],
1372
+ [9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1373
+ [2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1],
1374
+ [1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1375
+ [1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1376
+ [0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1377
+ [0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
1378
+ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]]) + 1
1379
+
1380
+ return [edgeTable, triTable]
1381
+
1382
+
1383
+ def main():
1384
+ """ Main routine """
1385
+
1386
+ # Create model
1387
+
1388
+ # lmod = quick_model(numx=3, numy=3, numz=3, dxy=100, d_z=100,
1389
+ # tlx=0, tly=0, tlz=0, mht=100, ght=45, finc=90, fdec=0,
1390
+ # inputliths=['Generic'], susc=[0.01], dens=[3.0])
1391
+ #
1392
+ # lmod.lith_index[2, 2, 2] = 1
1393
+
1394
+
1395
+ # faces, norms, corners = trimain(lmod.lith_index, 0.1)
1396
+ #
1397
+
1398
+ c = np.zeros([5, 5, 5])
1399
+ c[1:4, 1:4, 1:4] = 1
1400
+ c = zoom(c, 1, order=1)
1401
+
1402
+ x = np.arange(c.shape[1])
1403
+ y = np.arange(c.shape[0])
1404
+ z = np.arange(c.shape[2])
1405
+ xx, yy, zz = np.meshgrid(x, y, z)
1406
+ faces, vtx = MarchingCubes(xx, yy, zz, c, .5)
1407
+
1408
+ # x = np.linspace(0, 2, 20)
1409
+ # y = np.linspace(0, 2, 20)
1410
+ # z = np.linspace(0, 2, 20)
1411
+ # xx, yy, zz = np.meshgrid(x, y, z)
1412
+ # c = (xx-.5)**2 + (yy-.5)**2 + (zz-.5)**2
1413
+ # faces, vtx = MarchingCubes(xx, yy, zz, c, .5)
1414
+
1415
+ app = QtGui.QApplication(sys.argv)
1416
+ wid = Mod3dDisplay()
1417
+ wid.setWindowState(wid.windowState() & ~QtCore.Qt.WindowMinimized |
1418
+ QtCore.Qt.WindowActive)
1419
+
1420
+ # this will activate the window
1421
+
1422
+ ###############################
1423
+ faces = np.array(faces)
1424
+ vtx = np.array(vtx)
1425
+ # Create a zeroed array with the same type and shape as our vertices i.e.,
1426
+ # per vertex normal
1427
+ norm = np.zeros(vtx.shape, dtype=vtx.dtype)
1428
+ # Create an indexed view into the vertex array using the array of three indices
1429
+ # for triangles
1430
+ tris = vtx[faces]
1431
+ # Calculate the normal for all the triangles, by taking the cross product of
1432
+ # the vectors v1-v0, and v2-v0 in each triangle
1433
+ n = np.cross(tris[::, 1] - tris[::, 0], tris[::, 2] - tris[::, 0])
1434
+ # n is now an array of normals per triangle. The length of each normal is
1435
+ # dependent the vertices, we need to normalize these, so that our next step
1436
+ # weights each normal equally.
1437
+ normalize_v3(n)
1438
+ # n[2] *= -1
1439
+ # now we have a normalized array of normals, one per triangle, i.e., per
1440
+ # triangle normals. But instead of one per triangle (i.e., flat shading), we
1441
+ # add to each vertex in that triangle, the triangles' normal. Multiple
1442
+ # triangles would then contribute to every vertex, so we need to normalize
1443
+ # again afterwards. The cool part, we can actually add the normals through an
1444
+ # indexed view of our (zeroed) per vertex normal array.
1445
+
1446
+ norm[faces[:, 0]] += n
1447
+ norm[faces[:, 1]] += n
1448
+ norm[faces[:, 2]] += n
1449
+ normalize_v3(norm)
1450
+
1451
+ # Now we have a vertex array, vertices, a normal array, norm, and the index
1452
+ # array, faces, and we are ready to pass it on to our rendering algorithm.
1453
+ # To render without the index list, we create a flattened array where
1454
+ # the triangle indices are replaced with the actual vertices.
1455
+
1456
+ cptp = vtx.ptp(0).max()/100
1457
+ cmin = vtx.min(0)
1458
+ cptpd2 = vtx.ptp(0)/2.
1459
+ vtx = (vtx-cmin-cptpd2)/cptp
1460
+
1461
+ wid.glwidget.hastriangles = True
1462
+ wid.glwidget.cubeVtxArray = vtx
1463
+ wid.glwidget.cubeClrArray = (np.zeros([vtx.shape[0], 4]) +
1464
+ np.array([0.9, 0.4, 0.0, 0.5]))
1465
+ wid.glwidget.cubeNrmArray = norm
1466
+
1467
+ # ftmp = np.transpose(faces)
1468
+ # I = np.lexsort(ftmp)
1469
+ # faces = faces[I]
1470
+
1471
+ wid.glwidget.cubeIdxArray = faces.flatten().astype(np.uint32)
1472
+
1473
+ # This activates the opengl stuff
1474
+
1475
+ # wid.glwidget.init_object()
1476
+ print('widshow')
1477
+ wid.show()
1478
+ # wid.activateWindow()
1479
+
1480
+ # wid.glwidget.updateGL()
1481
+ #
1482
+ # wid.run()
1483
+
1484
+ sys.exit(app.exec_())
1485
+
1486
+
1487
+ if __name__ == "__main__":
1488
+ main()