lavavu-osmesa 1.8.43__cp311-cp311-manylinux_2_24_x86_64.whl

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 (138) hide show
  1. lavavu/LavaVuPython.py +578 -0
  2. lavavu/_LavaVuPython.cpython-311-x86_64-linux-gnu.so +0 -0
  3. lavavu/__init__.py +15 -0
  4. lavavu/__main__.py +12 -0
  5. lavavu/amalgamate.py +11 -0
  6. lavavu/aserver.py +357 -0
  7. lavavu/control.py +1699 -0
  8. lavavu/convert.py +853 -0
  9. lavavu/dict.json +2485 -0
  10. lavavu/font.bin +0 -0
  11. lavavu/html/LavaVu-amalgamated.css +282 -0
  12. lavavu/html/OK-min.js +99 -0
  13. lavavu/html/baseviewer.js +307 -0
  14. lavavu/html/control.css +104 -0
  15. lavavu/html/control.js +335 -0
  16. lavavu/html/dat-gui-light-theme.css +68 -0
  17. lavavu/html/dat.gui.min.js +2 -0
  18. lavavu/html/draw.js +2259 -0
  19. lavavu/html/drawbox.js +1030 -0
  20. lavavu/html/emscripten-template.js +184 -0
  21. lavavu/html/emscripten.css +92 -0
  22. lavavu/html/favicon.ico +0 -0
  23. lavavu/html/gl-matrix-min.js +47 -0
  24. lavavu/html/gui.css +25 -0
  25. lavavu/html/menu.js +609 -0
  26. lavavu/html/server.js +226 -0
  27. lavavu/html/stats.min.js +5 -0
  28. lavavu/html/styles.css +58 -0
  29. lavavu/html/webview-template.html +43 -0
  30. lavavu/html/webview.html +43 -0
  31. lavavu/lavavu.py +5635 -0
  32. lavavu/points.py +191 -0
  33. lavavu/server.py +343 -0
  34. lavavu/shaders/default.frag +20 -0
  35. lavavu/shaders/default.vert +17 -0
  36. lavavu/shaders/fontShader.frag +25 -0
  37. lavavu/shaders/fontShader.vert +18 -0
  38. lavavu/shaders/lineShader.frag +43 -0
  39. lavavu/shaders/lineShader.vert +28 -0
  40. lavavu/shaders/pointShader.frag +132 -0
  41. lavavu/shaders/pointShader.vert +57 -0
  42. lavavu/shaders/triShader.frag +170 -0
  43. lavavu/shaders/triShader.vert +55 -0
  44. lavavu/shaders/volumeShader.frag +463 -0
  45. lavavu/shaders/volumeShader.vert +5 -0
  46. lavavu/tracers.py +124 -0
  47. lavavu/vutils.py +213 -0
  48. lavavu_osmesa-1.8.43.dist-info/LICENSE.md +179 -0
  49. lavavu_osmesa-1.8.43.dist-info/METADATA +33 -0
  50. lavavu_osmesa-1.8.43.dist-info/RECORD +138 -0
  51. lavavu_osmesa-1.8.43.dist-info/WHEEL +5 -0
  52. lavavu_osmesa-1.8.43.dist-info/entry_points.txt +3 -0
  53. lavavu_osmesa-1.8.43.dist-info/top_level.txt +1 -0
  54. lavavu_osmesa.libs/libLLVM-3-6d00db57.8.so.1 +0 -0
  55. lavavu_osmesa.libs/libOSMesa-29f606eb.so.8.0.0 +0 -0
  56. lavavu_osmesa.libs/libXau-6ab8808d.so.6.0.0 +0 -0
  57. lavavu_osmesa.libs/libXdmcp-911ecd1c.so.6.0.0 +0 -0
  58. lavavu_osmesa.libs/libXfixes-af4baa9b.so.3.1.0 +0 -0
  59. lavavu_osmesa.libs/libavcodec-10cacdd4.so.57.64.101 +0 -0
  60. lavavu_osmesa.libs/libavformat-afa92877.so.57.56.101 +0 -0
  61. lavavu_osmesa.libs/libavutil-837eb790.so.55.34.101 +0 -0
  62. lavavu_osmesa.libs/libbluray-0b5d9dbd.so.1.10.0 +0 -0
  63. lavavu_osmesa.libs/libbsd-4a4ec721.so.0.8.3 +0 -0
  64. lavavu_osmesa.libs/libbz2-9ebec8ea.so.1.0.4 +0 -0
  65. lavavu_osmesa.libs/libcairo-4217ca50.so.2.11400.8 +0 -0
  66. lavavu_osmesa.libs/libchromaprint-c4f82352.so.1.4.2 +0 -0
  67. lavavu_osmesa.libs/libcom_err-b4bd5c72.so.2.1 +0 -0
  68. lavavu_osmesa.libs/libcrystalhd-e4ea0de0.so.3.6 +0 -0
  69. lavavu_osmesa.libs/libdrm-28f5b5e7.so.2.4.0 +0 -0
  70. lavavu_osmesa.libs/libedit-7f8577df.so.2.0.55 +0 -0
  71. lavavu_osmesa.libs/libffi-1c6807d3.so.6.0.4 +0 -0
  72. lavavu_osmesa.libs/libfontconfig-e9a06300.so.1.8.0 +0 -0
  73. lavavu_osmesa.libs/libfreetype-851758a3.so.6.12.3 +0 -0
  74. lavavu_osmesa.libs/libgcrypt-0005395c.so.20.1.6 +0 -0
  75. lavavu_osmesa.libs/libglapi-cf95372b.so.0.0.0 +0 -0
  76. lavavu_osmesa.libs/libgme-5f850ce8.so.0.6.0 +0 -0
  77. lavavu_osmesa.libs/libgmp-742f5e74.so.10.3.2 +0 -0
  78. lavavu_osmesa.libs/libgnutls-1ec2cd13.so.30.13.1 +0 -0
  79. lavavu_osmesa.libs/libgomp-ce6cf6a9.so.1.0.0 +0 -0
  80. lavavu_osmesa.libs/libgpg-error-24781f22.so.0.21.0 +0 -0
  81. lavavu_osmesa.libs/libgsm-aa736f52.so.1.0.12 +0 -0
  82. lavavu_osmesa.libs/libgssapi_krb5-e296a08d.so.2.2 +0 -0
  83. lavavu_osmesa.libs/libhogweed-9d325a8d.so.4.3 +0 -0
  84. lavavu_osmesa.libs/libicudata-79cf9efa.so.57.1 +0 -0
  85. lavavu_osmesa.libs/libicui18n-03536ef3.so.57.1 +0 -0
  86. lavavu_osmesa.libs/libicuuc-5743fca1.so.57.1 +0 -0
  87. lavavu_osmesa.libs/libidn-fd653b64.so.11.6.16 +0 -0
  88. lavavu_osmesa.libs/libjbig-b30cd8bd.so.0 +0 -0
  89. lavavu_osmesa.libs/libjpeg-8afa139c.so.62.2.0 +0 -0
  90. lavavu_osmesa.libs/libk5crypto-93afd15e.so.3.1 +0 -0
  91. lavavu_osmesa.libs/libkeyutils-46318358.so.1.5 +0 -0
  92. lavavu_osmesa.libs/libkrb5-061fe33b.so.3.3 +0 -0
  93. lavavu_osmesa.libs/libkrb5support-86ac49ad.so.0.1 +0 -0
  94. lavavu_osmesa.libs/liblzma-9c0610aa.so.5.2.2 +0 -0
  95. lavavu_osmesa.libs/libmp3lame-249ae4b0.so.0.0.0 +0 -0
  96. lavavu_osmesa.libs/libmpg123-13a39b0e.so.0.42.3 +0 -0
  97. lavavu_osmesa.libs/libncurses-09dfda50.so.5.9 +0 -0
  98. lavavu_osmesa.libs/libnettle-2482db45.so.6.3 +0 -0
  99. lavavu_osmesa.libs/libnuma-c8473f23.so.1.0.0 +0 -0
  100. lavavu_osmesa.libs/libogg-b6ceea65.so.0.8.2 +0 -0
  101. lavavu_osmesa.libs/libopenjp2-a0c5d12e.so.2.1.2 +0 -0
  102. lavavu_osmesa.libs/libopenmpt-58b855da.so.0.0.20 +0 -0
  103. lavavu_osmesa.libs/libopus-37a3229e.so.0.5.3 +0 -0
  104. lavavu_osmesa.libs/libp11-kit-d06ac4a7.so.0.2.0 +0 -0
  105. lavavu_osmesa.libs/libpixman-1-7369dbb3.so.0.34.0 +0 -0
  106. lavavu_osmesa.libs/libpng16-121b9de7.so.16.28.0 +0 -0
  107. lavavu_osmesa.libs/libshine-b48eced9.so.3.0.1 +0 -0
  108. lavavu_osmesa.libs/libsnappy-1125e350.so.1.3.0 +0 -0
  109. lavavu_osmesa.libs/libsoxr-e0d4d3e4.so.0.1.1 +0 -0
  110. lavavu_osmesa.libs/libspeex-6f258c6c.so.1.5.0 +0 -0
  111. lavavu_osmesa.libs/libssh-gcrypt-90c7dd19.so.4.5.1 +0 -0
  112. lavavu_osmesa.libs/libswresample-cb1bf771.so.2.3.100 +0 -0
  113. lavavu_osmesa.libs/libswscale-876dcddb.so.4.2.100 +0 -0
  114. lavavu_osmesa.libs/libtasn1-44938221.so.6.5.3 +0 -0
  115. lavavu_osmesa.libs/libtheoradec-02a81176.so.1.1.4 +0 -0
  116. lavavu_osmesa.libs/libtheoraenc-b508ccf1.so.1.1.2 +0 -0
  117. lavavu_osmesa.libs/libtiff-e2a5092b.so.5.2.6 +0 -0
  118. lavavu_osmesa.libs/libtinfo-33626a82.so.5.9 +0 -0
  119. lavavu_osmesa.libs/libtwolame-6fcc2d32.so.0.0.0 +0 -0
  120. lavavu_osmesa.libs/libva-0f7a824e.so.1.3904.0 +0 -0
  121. lavavu_osmesa.libs/libva-drm-178eb7ac.so.1.3904.0 +0 -0
  122. lavavu_osmesa.libs/libva-x11-d220c497.so.1.3904.0 +0 -0
  123. lavavu_osmesa.libs/libvdpau-0391b780.so.1.0.0 +0 -0
  124. lavavu_osmesa.libs/libvorbis-378bad15.so.0.4.8 +0 -0
  125. lavavu_osmesa.libs/libvorbisenc-d605e0e1.so.2.0.11 +0 -0
  126. lavavu_osmesa.libs/libvorbisfile-5692671f.so.3.3.7 +0 -0
  127. lavavu_osmesa.libs/libvpx-560f7a88.so.4.1.0 +0 -0
  128. lavavu_osmesa.libs/libwavpack-8339806a.so.1.2.0 +0 -0
  129. lavavu_osmesa.libs/libwebp-63152597.so.6.0.2 +0 -0
  130. lavavu_osmesa.libs/libwebpmux-38ab8eb3.so.2.0.2 +0 -0
  131. lavavu_osmesa.libs/libx264-1c898326.so.148 +0 -0
  132. lavavu_osmesa.libs/libx265-51947861.so.95 +0 -0
  133. lavavu_osmesa.libs/libxcb-ffedb2d4.so.1.1.0 +0 -0
  134. lavavu_osmesa.libs/libxcb-render-f7692d1d.so.0.0.0 +0 -0
  135. lavavu_osmesa.libs/libxcb-shm-5702672e.so.0.0.0 +0 -0
  136. lavavu_osmesa.libs/libxml2-b8b306ab.so.2.9.4 +0 -0
  137. lavavu_osmesa.libs/libxvidcore-a773eded.so.4.3 +0 -0
  138. lavavu_osmesa.libs/libzvbi-2db02ce4.so.0.13.2 +0 -0
lavavu/html/drawbox.js ADDED
@@ -0,0 +1,1030 @@
1
+ //Bounding box only in WebGL
2
+ //Urgent TODO: move shared code with draw.js into common file
3
+ //maintaining two copies currently!
4
+ //Re-init using previous callback data
5
+
6
+ function initBox(el, cmd_callback, fixedsize) {
7
+ //console.log("INITBOX: " + el.id);
8
+ var canvas = document.createElement("canvas");
9
+ canvas.classList.add("resized");
10
+ if (!el) el = document.body.firstChild;
11
+ canvas.id = "canvas_" + el.id;
12
+ canvas.imgtarget = el
13
+ el.parentElement.appendChild(canvas);
14
+ canvas.style.cssText = "position: absolute; width: 100%; height: 100%; margin: 0px; padding: 0px; top: 0; left: 0; bottom: 0; right: 0; z-index: 11; border: none;"
15
+ var viewer = new BoxViewer(canvas);
16
+
17
+ //Canvas event handling
18
+ canvas.mouse = new Mouse(canvas, new MouseEventHandler(canvasBoxMouseClick, canvasBoxMouseWheel, canvasBoxMouseMove, canvasBoxMouseDown, null, null, canvasBoxMousePinch));
19
+ //Following two settings should probably be defaults?
20
+ canvas.mouse.moveUpdate = true; //Continual update of deltaX/Y
21
+ //canvas.mouse.setDefault();
22
+ canvas.mouse.wheelTimer = true; //Accumulate wheel scroll (prevents too many events backing up)
23
+ defaultMouse = document.mouse = canvas.mouse;
24
+
25
+ //Attach viewer object to canvas
26
+ canvas.viewer = viewer;
27
+
28
+ //Disable context menu and prevent bubbling
29
+ canvas.addEventListener('contextmenu', e => {e.preventDefault(); e.stopPropagation();});
30
+
31
+ //Command callback function
32
+ viewer.command = cmd_callback;
33
+
34
+ //Data dict and colourmap names stored in globals
35
+ viewer.dict = window.dictionary;
36
+ viewer.defaultcolourmaps = window.defaultcolourmaps;
37
+
38
+ //Enable to forward key presses to server directly
39
+ //(only used for full size viewers)
40
+ if (fixedsize == 1)
41
+ document.addEventListener('keyup', function(event) {keyPress(event, viewer);});
42
+
43
+ return viewer;
44
+ }
45
+
46
+ function keyModifiers(event) {
47
+ modifiers = '';
48
+ if (event.ctrlKey) modifiers += 'C';
49
+ if (event.shiftKey) modifiers += 'S';
50
+ if (event.altKey) modifiers += 'A';
51
+ if (event.metaKey) modifiers += 'M';
52
+ return modifiers;
53
+ }
54
+
55
+ function keyPress(event, viewer) {
56
+ // space and arrow keys, prevent scrolling
57
+ if ([' ', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key))
58
+ event.preventDefault();
59
+
60
+ if (event.target.tagName == 'INPUT') return;
61
+
62
+ //Special key codes
63
+ if (event.key == 'ArrowUp') key = 17;
64
+ else if (event.key == 'ArrowDown') key = 18;
65
+ else if (event.key == 'ArrowLeft') key = 20;
66
+ else if (event.key == 'ArrowRight') key = 19;
67
+ else if (event.key == 'PageUp') key = 24;
68
+ else if (event.key == 'PageDown') key = 25;
69
+ else if (event.key == 'PageUp') key = 24;
70
+ else if (event.key == 'Home') key = 22;
71
+ else if (event.key == 'End') key = 23;
72
+ else if (event.key == 'Backspace') key = 8;
73
+ else if (event.key == 'Tab') key = 9;
74
+ else if (event.key == 'Escape') key = 27;
75
+ else if (event.key == 'Enter') key = 13;
76
+ else if (event.key == 'Insert') key = 21;
77
+ else if (event.key == 'Delete') key = 127;
78
+ else if (event.key[0] == 'F' && event.key.length > 1)
79
+ key = 189 + parseInt(event.key.substr(1));
80
+ else if (event.key.length == 1) {
81
+ key = event.key.charCodeAt(0);
82
+ if (key > 127 && event.code.length == 4 && event.code.substr(0,3) == 'Key')
83
+ key = event.code.charCodeAt(3);
84
+ } else
85
+ return;
86
+
87
+ //console.log(event.key);
88
+ //console.log(event.code);
89
+ //console.log(key);
90
+
91
+ var modifiers = keyModifiers(event);
92
+
93
+ //Ignore CTRL+R, CTRL+SHIFT+R
94
+ if (key == 114 && modifiers == 'C' || key == 82 && modifiers == 'CS') return;
95
+
96
+ cmd = 'key key=' + key + ',modifiers=' + modifiers + ",x=" + defaultMouse.x + ",y=" + defaultMouse.y;
97
+ //console.log(cmd);
98
+ viewer.command(cmd);
99
+ }
100
+
101
+ function canvasBoxMouseClick(event, mouse) {
102
+ mouse.element.viewer.check_context(mouse);
103
+
104
+ if (mouse.element.viewer.rotating)
105
+ mouse.element.viewer.command('' + mouse.element.viewer.getRotationString());
106
+ else
107
+ mouse.element.viewer.command('' + mouse.element.viewer.getTranslationString());
108
+
109
+ if (mouse.element.viewer.rotating) {
110
+ mouse.element.viewer.rotating = false;
111
+ //mouse.element.viewer.reload = true;
112
+ }
113
+
114
+ //Clear the webgl box
115
+ mouse.element.viewer.clear();
116
+
117
+ return false;
118
+ }
119
+
120
+ function canvasBoxMouseDown(event, mouse) {
121
+ mouse.element.viewer.check_context(mouse);
122
+ //Just draw so the box appears
123
+ mouse.element.viewer.draw();
124
+ return false;
125
+ }
126
+
127
+ var hideBoxTimer;
128
+
129
+ function canvasBoxMouseMove(event, mouse) {
130
+ //GUI elements to show on mouseover
131
+ if (mouse.element && mouse.element.viewer && Object.keys(mouse.element.viewer.vis).length) {
132
+ var gui = mouse.element.viewer.gui;
133
+ var rect = mouse.element.getBoundingClientRect();
134
+ x = event.clientX-rect.left;
135
+ y = event.clientY-rect.top;
136
+ if (x >= 0 && y >= 0 && x < rect.width && y < rect.height) {
137
+ if (!gui && mouse.element.imgtarget)
138
+ mouse.element.imgtarget.nextElementSibling.style.display = "block";
139
+
140
+ if (gui) {
141
+ if (mouse.element.imgtarget) mouse.element.imgtarget.nextElementSibling.style.display = "none";
142
+ gui.domElement.style.display = "block";
143
+ }
144
+
145
+ if (hideBoxTimer)
146
+ clearTimeout(hideBoxTimer);
147
+
148
+ hideBoxTimer = setTimeout(function () { hideMenu(mouse.element, gui);}, 1000 );
149
+ }
150
+ }
151
+
152
+ if (!mouse.isdown || !mouse.element.viewer) return true;
153
+ mouse.element.viewer.rotating = false;
154
+
155
+ //Switch buttons for translate/rotate
156
+ var button = mouse.button;
157
+
158
+ if (mouse.element.viewer.mode == "Translate") {
159
+ //Swap rotate/translate buttons
160
+ if (button == 0)
161
+ button = 2
162
+ else if (button == 2)
163
+ button = 0;
164
+ } else if (button==0 && mouse.element.viewer.mode == "Zoom") {
165
+ button = 100;
166
+ }
167
+
168
+ //console.log(mouse.deltaX + "," + mouse.deltaY);
169
+ switch (button)
170
+ {
171
+ case 0:
172
+ mouse.element.viewer.rotateY(mouse.deltaX/5);
173
+ mouse.element.viewer.rotateX(mouse.deltaY/5);
174
+ mouse.element.viewer.rotating = true;
175
+ break;
176
+ case 1:
177
+ mouse.element.viewer.rotateZ(Math.sqrt(mouse.deltaX*mouse.deltaX + mouse.deltaY*mouse.deltaY)/5);
178
+ mouse.element.viewer.rotating = true;
179
+ break;
180
+ case 2:
181
+ var adjust = mouse.element.viewer.modelsize / 1000; //1/1000th of size
182
+ mouse.element.viewer.translate[0] += mouse.deltaX * adjust;
183
+ mouse.element.viewer.translate[1] -= mouse.deltaY * adjust;
184
+ break;
185
+ case 100:
186
+ var adjust = mouse.element.viewer.modelsize / 1000; //1/1000th of size
187
+ mouse.element.viewer.translate[2] += mouse.deltaX * adjust;
188
+ break;
189
+ }
190
+
191
+ mouse.element.viewer.draw();
192
+
193
+ return false;
194
+ }
195
+
196
+ function canvasBoxMouseWheel(event, mouse) {
197
+ mouse.element.viewer.check_context(mouse);
198
+ var scroll = event.deltaY < 0 ? 0.01 : -0.01;
199
+ //console.log(event.shiftKey,event.deltaY * -0.01);
200
+ if (event.shiftKey) {
201
+ mouse.element.viewer.zoomClip(scroll);
202
+ //mouse.element.viewer.zoomClip(event.spin*0.01);
203
+ } else {
204
+ mouse.element.viewer.zoom(scroll);
205
+ //mouse.element.viewer.zoom(event.spin*0.01);
206
+ }
207
+ return false; //Prevent default
208
+ }
209
+
210
+ function canvasBoxMousePinch(event, mouse) {
211
+ mouse.element.viewer.check_context(mouse);
212
+ if (event.distance != 0) {
213
+ var factor = event.distance * 0.0001;
214
+ mouse.element.viewer.zoom(factor);
215
+ //Clear the box after a second
216
+ setTimeout(function() {mouse.element.viewer.clear();}, 1000);
217
+ }
218
+ return false; //Prevent default
219
+ }
220
+
221
+ //This object encapsulates a vertex buffer and shader set
222
+ function BoxRenderer(gl, colour) {
223
+ this.gl = gl;
224
+ if (colour)
225
+ this.colour = colour;
226
+ else
227
+ this.colour = [0.5, 0.5, 0.5, 1.0];
228
+
229
+ //Line renderer
230
+ this.attribSizes = [3 * Float32Array.BYTES_PER_ELEMENT];
231
+
232
+ this.elements = 0;
233
+ this.elementSize = 0;
234
+ for (var i=0; i<this.attribSizes.length; i++)
235
+ this.elementSize += this.attribSizes[i];
236
+ }
237
+
238
+ var vs = "precision highp float; \n \
239
+ attribute vec3 aVertexPosition; \n \
240
+ attribute vec4 aVertexColour; \n \
241
+ uniform mat4 uMVMatrix; \n \
242
+ uniform mat4 uPMatrix; \n \
243
+ uniform vec4 uColour; \n \
244
+ varying vec4 vColour; \n \
245
+ void main(void) \n \
246
+ { \n \
247
+ vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0); \n \
248
+ gl_Position = uPMatrix * mvPosition; \n \
249
+ vColour = uColour; \n \
250
+ }";
251
+
252
+ var fs = "precision highp float; \n \
253
+ varying vec4 vColour; \n \
254
+ void main(void) \n \
255
+ { \n \
256
+ gl_FragColor = vColour; \n \
257
+ }";
258
+
259
+ BoxRenderer.prototype.init = function() {
260
+ //Compile the shaders
261
+ this.program = new WebGLProgram(this.gl, vs, fs);
262
+ if (this.program.errors) console.log(this.program.errors);
263
+ //Setup attribs/uniforms (flag set to skip enabling attribs)
264
+ this.program.setup(undefined, undefined, true);
265
+
266
+ return true;
267
+ }
268
+
269
+ BoxRenderer.prototype.updateBuffers = function(view) {
270
+ //Create buffer if not yet allocated
271
+ if (this.vertexBuffer == undefined) {
272
+ //Init shaders etc...
273
+ if (!this.init()) return;
274
+ this.vertexBuffer = this.gl.createBuffer();
275
+ this.indexBuffer = this.gl.createBuffer();
276
+ }
277
+
278
+ //Bind buffers
279
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
280
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
281
+
282
+ this.box(view.min, view.max);
283
+ }
284
+
285
+ BoxRenderer.prototype.box = function(min, max) {
286
+ var zero = [min[0]+0.5*(max[0] - min[0]), min[1]+0.5*(max[1] - min[1]), min[2]+0.5*(max[2] - min[2])];
287
+ var min10 = [min[0] + 0.45*(max[0] - min[0]), min[1]+0.45*(max[1] - min[1]), min[2]+0.45*(max[2] - min[2])];
288
+ var max10 = [min[0] + 0.55*(max[0] - min[0]), min[1]+0.55*(max[1] - min[1]), min[2]+0.55*(max[2] - min[2])];
289
+ var vertices = new Float32Array(
290
+ [
291
+ /* Bounding box */
292
+ min[0], min[1], max[2],
293
+ min[0], max[1], max[2],
294
+ max[0], max[1], max[2],
295
+ max[0], min[1], max[2],
296
+ min[0], min[1], min[2],
297
+ min[0], max[1], min[2],
298
+ max[0], max[1], min[2],
299
+ max[0], min[1], min[2],
300
+ /* 10% box */
301
+ min10[0], min10[1], max10[2],
302
+ min10[0], max10[1], max10[2],
303
+ max10[0], max10[1], max10[2],
304
+ max10[0], min10[1], max10[2],
305
+ min10[0], min10[1], min10[2],
306
+ min10[0], max10[1], min10[2],
307
+ max10[0], max10[1], min10[2],
308
+ max10[0], min10[1], min10[2],
309
+ /* Axis lines */
310
+ min[0], zero[1], zero[2],
311
+ max[0], zero[1], zero[2],
312
+ zero[0], min[1], zero[2],
313
+ zero[0], max[1], zero[2],
314
+ zero[0], zero[1], min[2],
315
+ zero[0], zero[1], max[2]
316
+ ]);
317
+
318
+ var indices = new Uint16Array(
319
+ [
320
+ /* Bounding box */
321
+ 0, 1, 1, 2, 2, 3, 3, 0,
322
+ 4, 5, 5, 6, 6, 7, 7, 4,
323
+ 0, 4, 3, 7, 1, 5, 2, 6,
324
+ /* 10% box */
325
+ 8, 9, 9, 10, 10, 11, 11, 8,
326
+ 12, 13, 13, 14, 14, 15, 15, 12,
327
+ 8, 12, 11, 15, 9, 13, 10, 14,
328
+ /* Axis lines */
329
+ 16, 17,
330
+ 18, 19,
331
+ 20, 21
332
+ ]
333
+ );
334
+ this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
335
+ this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, indices, this.gl.STATIC_DRAW);
336
+ this.elements = 24+24+6;
337
+ }
338
+
339
+ BoxRenderer.prototype.draw = function(webgl, nobox, noaxes) {
340
+ if (!this.elements) return;
341
+
342
+ if (this.program.attributes["aVertexPosition"] == undefined) return; //Require vertex buffer
343
+
344
+ webgl.use(this.program);
345
+ webgl.setMatrices();
346
+
347
+ //Bind buffers
348
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
349
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
350
+
351
+ //Enable attributes
352
+ for (var key in this.program.attributes)
353
+ this.gl.enableVertexAttribArray(this.program.attributes[key]);
354
+
355
+
356
+ //Line box render
357
+ this.gl.vertexAttribPointer(this.program.attributes["aVertexPosition"], 3, this.gl.FLOAT, false, 0, 0);
358
+ //Bounding box
359
+ if (!nobox) {
360
+ this.gl.uniform4f(this.program.uniforms["uColour"], this.colour[0], this.colour[1], this.colour[2], this.colour[3]);
361
+ this.gl.drawElements(this.gl.LINES, 24, this.gl.UNSIGNED_SHORT, 0);
362
+ }
363
+
364
+ //10% box (always draw)
365
+ this.gl.drawElements(this.gl.LINES, 24, this.gl.UNSIGNED_SHORT, 24 * 2);
366
+
367
+ //Axes (2 bytes per unsigned short)
368
+ if (!noaxes) {
369
+ this.gl.uniform4f(this.program.uniforms["uColour"], 1.0, 0.0, 0.0, 1.0);
370
+ this.gl.drawElements(this.gl.LINES, 2, this.gl.UNSIGNED_SHORT, (24+24) * 2);
371
+ this.gl.uniform4f(this.program.uniforms["uColour"], 0.0, 1.0, 0.0, 1.0);
372
+ this.gl.drawElements(this.gl.LINES, 2, this.gl.UNSIGNED_SHORT, (24+24+2) * 2);
373
+ this.gl.uniform4f(this.program.uniforms["uColour"], 0.0, 0.0, 1.0, 1.0);
374
+ this.gl.drawElements(this.gl.LINES, 2, this.gl.UNSIGNED_SHORT, (24+24+4) * 2);
375
+ }
376
+
377
+ //Disable attribs
378
+ for (var key in this.program.attributes)
379
+ this.gl.disableVertexAttribArray(this.program.attributes[key]);
380
+
381
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
382
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);
383
+ this.gl.useProgram(null);
384
+ }
385
+
386
+ //This object holds the viewer details and calls the renderers
387
+ function BoxViewer(canvas) {
388
+ this.vis = {};
389
+ this.vis.objects = [];
390
+ this.vis.colourmaps = [];
391
+ this.canvas = canvas;
392
+ if (!canvas) {alert("Invalid Canvas"); return;}
393
+ try {
394
+ this.webgl = new WebGL(this.canvas, {antialias: true}); //, premultipliedAlpha: false});
395
+ this.gl = this.webgl.gl;
396
+ canvas.addEventListener("webglcontextlost", function(event) {
397
+ //event.preventDefault();
398
+ console.log("Context loss detected, clearing data/state and flagging defunct");
399
+ this.mouse.lostContext = true;
400
+ }, false);
401
+
402
+ canvas.addEventListener("webglcontextrestored", function(event) {
403
+ console.log("Context restored");
404
+ }, false);
405
+
406
+ } catch(e) {
407
+ //No WebGL
408
+ console.log("No WebGL: " + e);
409
+ }
410
+
411
+ this.rotating = false;
412
+ this.translate = [0,0,0];
413
+ this.rotate = quat4.create();
414
+ quat4.identity(this.rotate);
415
+ this.fov = 45;
416
+ this.focus = [0,0,0];
417
+ this.centre = [0,0,0];
418
+ this.near_clip = this.far_clip = 0.0;
419
+ this.modelsize = 1;
420
+ this.scale = [1, 1, 1];
421
+ this.orientation = 1.0; //1.0 for RH, -1.0 for LH
422
+
423
+ //Non-persistant settings
424
+ this.mode = 'Rotate';
425
+ if (!this.gl) return;
426
+
427
+ //Create the renderers
428
+ this.border = new BoxRenderer(this.gl, [0.5,0.5,0.5,1]);
429
+
430
+ this.gl.enable(this.gl.DEPTH_TEST);
431
+ this.gl.depthFunc(this.gl.LEQUAL);
432
+ //this.gl.depthMask(this.gl.FALSE);
433
+ this.gl.enable(this.gl.BLEND);
434
+ //this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
435
+ //this.gl.blendFuncSeparate(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, this.gl.ZERO, this.gl.ONE);
436
+ this.gl.blendFuncSeparate(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
437
+ }
438
+
439
+ BoxViewer.prototype.check_context = function(mouse) {
440
+ if (mouse.lostContext) {
441
+ console.log("Recreating viewer after context loss");
442
+ //Reinit on timer? on click?
443
+ var box = initBox(this.canvas.imgtarget, this.command);
444
+ box.loadFile(JSON.stringify(this.vis));
445
+ //Delete the old canvas now
446
+ this.canvas.parentNode.removeChild(this.canvas);
447
+ this.vis = null;
448
+ mouse.lostContext = false;
449
+ this.deleted = true;
450
+ }
451
+ }
452
+
453
+ BoxViewer.prototype.reload = function() {
454
+ this.command('reload');
455
+ }
456
+
457
+ BoxViewer.prototype.checkPointMinMax = function(coord) {
458
+ for (var i=0; i<3; i++) {
459
+ this.view.min[i] = Math.min(coord[i], this.view.min[i]);
460
+ this.view.max[i] = Math.max(coord[i], this.view.max[i]);
461
+ }
462
+ //console.log(JSON.stringify(this.view.min) + " -- " + JSON.stringify(this.view.max));
463
+ }
464
+
465
+ function Merge(obj1, obj2) {
466
+ for (var p in obj2) {
467
+ try {
468
+ //console.log(p + " ==> " + obj2[p].constructor);
469
+ // Property in destination object set; update its value.
470
+ if (!obj2.hasOwnProperty(p)) continue;
471
+ if (obj2[p].constructor == Object || obj2[p].constructor == Array) {
472
+ obj1[p] = Merge(obj1[p], obj2[p]);
473
+ } else {
474
+ //Just copy
475
+ obj1[p] = obj2[p];
476
+ }
477
+ } catch(e) {
478
+ // Property in destination object not set; create it and set its value.
479
+ obj1[p] = obj2[p];
480
+ }
481
+ }
482
+
483
+ //Clear any keys in obj1 that are not in obj2
484
+ for (var p in obj1) {
485
+ if (!obj1.hasOwnProperty(p)) continue; //Ignore built in keys
486
+ if (p in obj2) continue;
487
+ if (typeof(obj1[p]) != 'object') {
488
+ //Just delete
489
+ delete obj1[p]
490
+ }
491
+ }
492
+
493
+ return obj1;
494
+ }
495
+
496
+ BoxViewer.prototype.exportJson = function(nocam) {
497
+ return {"objects" : this.exportObjects(),
498
+ "colourmaps" : this.vis.colourmaps,
499
+ "views" : this.exportView(nocam),
500
+ "properties" : this.vis.properties};
501
+ }
502
+
503
+ BoxViewer.prototype.sendState = function(reload) {
504
+ var exp = this.exportJson();
505
+ exp.reload = reload;
506
+ this.command(JSON.stringify(exp));
507
+ }
508
+
509
+ BoxViewer.prototype.toString = function(nocam, reload, noformat) {
510
+ var exp = this.exportJson(nocam);
511
+ exp.exported = true;
512
+ exp.reload = reload ? true : false;
513
+
514
+ if (noformat)
515
+ return JSON.stringify(exp);
516
+ //Export with 2 space indentation
517
+ return JSON.stringify(exp, undefined, 2);
518
+ }
519
+
520
+ BoxViewer.prototype.exportView = function(nocam) {
521
+ //Update camera settings of current view
522
+ if (nocam)
523
+ this.view = {};
524
+ else {
525
+ this.view.rotate = this.getRotation();
526
+ this.view.focus = this.focus;
527
+ this.view.translate = this.translate;
528
+ //Allows scale editing in UI by commenting this
529
+ //this.view.scale = this.scale;
530
+ }
531
+ /*
532
+ * If we overwrite these, changes from menu will not apply
533
+ *
534
+ this.view.fov = this.fov;
535
+ this.view.near = this.near_clip;
536
+ this.view.far = this.far_clip;
537
+ this.view.border = this.showBorder ? 1 : 0;
538
+ this.view.axis = this.axes;
539
+ */
540
+ //this.view.background = this.background.toString();
541
+
542
+ //Never export min/max
543
+ var V = Object.assign(this.view);
544
+ V.min = undefined;
545
+ V.max = undefined;
546
+ return [V];
547
+ }
548
+
549
+ BoxViewer.prototype.exportObjects = function() {
550
+ objs = [];
551
+ for (var id in this.vis.objects) {
552
+ objs[id] = {};
553
+ //Skip geometry data
554
+ for (var type in this.vis.objects[id]) {
555
+ if (type != "triangles" && type != "points" && type != 'lines' && type != "volume") {
556
+ objs[id][type] = this.vis.objects[id][type];
557
+ }
558
+ }
559
+ }
560
+ //console.log("OBJECTS: " + JSON.stringify(objs));
561
+
562
+ return objs;
563
+ }
564
+
565
+ BoxViewer.prototype.exportColourMaps = function() {
566
+ return this.vis.colourmaps;
567
+ //DEPRECATED
568
+ //Below extracts map from gui editor, not needed unless editor hasn't updated vis object
569
+ cmaps = [];
570
+ if (this.vis.colourmaps) {
571
+ for (var i=0; i<this.vis.colourmaps.length; i++) {
572
+ console.log(i + " - " + this.vis.colourmaps[i].palette);
573
+ if (!this.vis.colourmaps[i].palette) continue;
574
+ cmaps[i] = this.vis.colourmaps[i].palette.get();
575
+ //Copy additional properties
576
+ for (var type in this.vis.colourmaps[i]) {
577
+ if (type != "palette" && type != "colours")
578
+ cmaps[i][type] = this.vis.colourmaps[i][type];
579
+ }
580
+ }
581
+ }
582
+ return cmaps;
583
+ }
584
+
585
+ BoxViewer.prototype.exportFile = function() {
586
+ window.open('data:text/plain;base64,' + window.btoa(this.toString(false, true)));
587
+ }
588
+
589
+ BoxViewer.prototype.loadFile = function(source) {
590
+ //Skip update to rotate/translate etc if in process of updating
591
+ //if (document.mouse.isdown) return;
592
+ if (source.length < 3) {
593
+ console.log('Invalid source data, ignoring');
594
+ console.log(source);
595
+ console.log(BoxViewer.prototype.loadFile.caller);
596
+ return; //Invalid
597
+ }
598
+
599
+ if (!this.vis)
600
+ this.vis = {};
601
+
602
+ //Parse data
603
+ var src = {};
604
+ try {
605
+ src = JSON.parse(source);
606
+ } catch(e) {
607
+ console.log(source);
608
+ console.log("Parse Error: " + e);
609
+ return;
610
+ }
611
+
612
+ //Before merge, delete all colourmap data if changed
613
+ for (var c in this.vis.colourmaps) {
614
+ //Name or colour count mismatch? delete so can be recreated
615
+ if (this.vis.colourmaps[c].name != src.colourmaps[c].name ||
616
+ this.vis.colourmaps[c].colours.length != src.colourmaps[c].colours.length) {
617
+ //Delete the colourmap folder for this map, will be re-created
618
+ if (this.cgui && this.cgui.__folders[this.vis.colourmaps[c].name]) {
619
+ this.cgui.removeFolder(this.cgui.__folders[this.vis.colourmaps[c].name]);
620
+ this.cgui.__folders[this.vis.colourmaps[c].name] = undefined;
621
+ }
622
+ //Clear all the colours so new data will replace in merge
623
+ this.vis.colourmaps[c].colours = undefined;
624
+ }
625
+ }
626
+
627
+ //Merge keys - preserves original objects for gui access
628
+ Merge(this.vis, src);
629
+
630
+ //No model loaded? Prevents errors so default are loaded
631
+ if (!this.vis.properties)
632
+ this.vis.properties = {};
633
+
634
+ //Set active view (always first for now)
635
+ this.view = this.vis.views[0];
636
+
637
+ //Always set a bounding box, get from objects if not in view
638
+ var objbb = false;
639
+ if (!this.view.min || !this.view.max) {
640
+ this.view.min = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE];
641
+ this.view.max = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
642
+ objbb = true;
643
+ }
644
+ //console.log(JSON.stringify(this.view,null, 2));
645
+
646
+ if (this.view) {
647
+ this.fov = this.view.fov || 45;
648
+ this.near_clip = this.view.near || 0;
649
+ this.far_clip = this.view.far || 0;
650
+ this.orientation = this.view.orientation || 1;
651
+ this.axes = this.view.axis == undefined ? true : this.view.axis;
652
+ }
653
+
654
+ if (this.vis.properties.resolution && this.vis.properties.resolution[0] && this.vis.properties.resolution[1]) {
655
+ this.width = this.vis.properties.resolution[0];
656
+ this.height = this.vis.properties.resolution[1];
657
+ //this.canvas.style.width = "";
658
+ //this.canvas.style.height = "";
659
+ } else {
660
+ //Autosize when img loaded
661
+ this.width = 0;
662
+ this.height = 0;
663
+ }
664
+
665
+ //Process object data
666
+ for (var id in this.vis.objects) {
667
+ //Apply object bounding box
668
+ if (objbb && this.vis.objects[id].min)
669
+ this.checkPointMinMax(this.vis.objects[id].min);
670
+ if (objbb && this.vis.objects[id].max)
671
+ this.checkPointMinMax(this.vis.objects[id].max);
672
+ }
673
+
674
+ this.updateDims(this.view);
675
+
676
+ //Update display
677
+ if (!this.gl) return;
678
+ this.draw();
679
+ this.clear();
680
+
681
+ //Create UI - disable by omitting dat.gui.min.js
682
+ //(If menu doesn't exist or is open, update immediately
683
+ // otherwise, wait until clicked/opened as update is slow)
684
+ if (!this.gui || !this.gui.closed)
685
+ this.menu();
686
+ else
687
+ this.reloadgui = true;
688
+
689
+ //Copy updated values to all generated controls
690
+ //This allows data changed by other means (ie: through python) to
691
+ // be reflected in the HTML control values
692
+ var that = this;
693
+ var getValWithIndex = function(prop, val, idx) {
694
+ if (val === undefined) return;
695
+ if (idx != null && idx >= 0 && val.length > idx)
696
+ val = val[idx];
697
+ //Round off floating point numbers
698
+ if (that.dict[property].type.indexOf('real') >= 0)
699
+ return val.toFixed(6) / 1; //toFixed() / 1 rounds to fixed position and removes trailing zeros
700
+ return val;
701
+ }
702
+ var pel = this.canvas.parentElement.parentElement;
703
+ var children = pel.getElementsByTagName('*');
704
+ for (var i=0; i<children.length; i++) {
705
+ //Process property controls
706
+ var id = children[i].id;
707
+ if (id.indexOf('lvctrl') >= 0) {
708
+ var target = children[i].getAttribute("data-target");
709
+ var property = children[i].getAttribute("data-property");
710
+ var idx = children[i].getAttribute("data-index");
711
+ //console.log(id + " : " + target + " : " + property + " [" + idx + "]");
712
+ if (property) {
713
+ if (target) {
714
+ //Loop through objects, find those whose name matches element target
715
+ for (var o in this.vis.objects) {
716
+ var val = this.vis.objects[o][property];
717
+ if (val === undefined) continue;
718
+ if (this.vis.objects[o].name == target) {
719
+ if (idx != null && idx >= 0)
720
+ val = val[idx];
721
+ //console.log(target + " ==> SET " + id + " : ['" + property + "'] VALUE TO " + val);
722
+ //console.log("TAG: " + children[i].tagName);
723
+ if (children[i].type == 'checkbox')
724
+ children[i].checked = val;
725
+ else if (children[i].tagName == 'SELECT') {
726
+ //If integer, set by index, otherwise set by value
727
+ var parsed = parseInt(val);
728
+ if (isNaN(parsed) || parsed.toString() != val) {
729
+ //If the value is in the options, set it, otherwise leave as is
730
+ for (var c in children[i].options) {
731
+ if (children[i].options[c].value == val) {
732
+ children[i].selectedIndex = c;
733
+ break;
734
+ }
735
+ }
736
+ } else {
737
+ children[i].selectedIndex = parsed;
738
+ }
739
+ } else if (children[i].tagName == 'DIV') {
740
+ children[i].style.background = new Colour(val).html();
741
+ } else if (children[i].tagName == 'CANVAS' && children[i].gradient) {
742
+ //Store full list of colourmaps
743
+ var el = children[i]; //canvas element
744
+ //Ensure we aren't merging the same object
745
+ el.colourmaps = Merge(JSON.parse(JSON.stringify(el.colourmaps)), this.vis.colourmaps);
746
+ //Load the initial colourmap
747
+ if (!el.selectedIndex >= 0) {
748
+ //Get the selected index from the property value
749
+ for (var c in this.vis.colourmaps) {
750
+ if (this.vis.colourmaps[c].name == val) {
751
+ el.selectedIndex = c;
752
+ //Copy, don't link
753
+ el.currentmap = JSON.parse(JSON.stringify(this.vis.colourmaps[c]));
754
+ //el.currentmap = Object.assign(this.vis.colourmaps[c]);
755
+ break;
756
+ }
757
+ }
758
+ }
759
+ //Can't use gradient.read() here as it triggers another state load,
760
+ //looping infinitely - so load the palette change directly
761
+ el.gradient.palette = new Palette(this.vis.colourmaps[el.selectedIndex].colours, true);
762
+ //el.gradient.reset(); //For some reason this screws up colour editing
763
+ el.gradient.update(true); //Update without triggering callback that triggers a state reload
764
+ } else {
765
+ //console.log(id + " : " + target + " : " + property + " = " + val);
766
+ children[i].value = getValWithIndex(property, val, idx);
767
+ }
768
+ }
769
+ }
770
+ } else if (this.vis.views[0][property] != null) {
771
+ //View property
772
+ var val = this.vis.views[0][property];
773
+ //console.log("SET " + id + " : ['" + property + "'] VIEW PROP VALUE TO " + val);
774
+ children[i].value = getValWithIndex(property, val, idx);
775
+ } else if (this.vis.properties[property] != null) {
776
+ //Global property
777
+ var val = this.vis.properties[property];
778
+ //console.log("SET " + id + " : ['" + property + "'] GLOBAL VALUE TO " + val);
779
+ children[i].value = getValWithIndex(property, val, idx);
780
+ }
781
+ }
782
+ }
783
+ }
784
+ }
785
+
786
+ BoxViewer.prototype.menu = function() {
787
+ //Create UI - disable by omitting dat.gui.min.js
788
+ //This is slow! Don't call while animating
789
+ var viewer = this;
790
+ var changefn = function(value, reload) {
791
+ //console.log(JSON.stringify(Object.keys(this)));
792
+ //console.log(value);
793
+ if (reload == undefined) {
794
+ reload = true;
795
+ if (this.property && viewer.dict[this.property])
796
+ {
797
+ //Get reload level from prop dict
798
+ //console.log(this.property + " REDRAW: " + viewer.dict[this.property].redraw);
799
+ reload = viewer.dict[this.property].redraw;
800
+ }
801
+ }
802
+
803
+ //Sync state and reload
804
+ viewer.sendState(reload);
805
+ };
806
+
807
+ if (!this.gui || this.gui.closed) {
808
+ //Re-create from scratch if closed or not present
809
+ createMenu(this, changefn);
810
+ } else {
811
+ updateMenu(this, changefn);
812
+ }
813
+ this.reloadgui = false;
814
+ }
815
+
816
+ BoxViewer.prototype.clear = function() {
817
+ if (!this.gl) return;
818
+ this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
819
+ }
820
+
821
+ BoxViewer.prototype.draw = function() {
822
+ if (!this.canvas) return;
823
+
824
+ //Get the dimensions from the current canvas
825
+ if (this.width != this.canvas.offsetWidth || this.height != this.canvas.offsetHeight) {
826
+ this.width = this.canvas.offsetWidth;
827
+ this.height = this.canvas.offsetHeight;
828
+ //Need to set this too for some reason
829
+ this.canvas.width = this.width;
830
+ this.canvas.height = this.height;
831
+ if (this.gl) {
832
+ this.gl.viewportWidth = this.width;
833
+ this.gl.viewportHeight = this.height;
834
+ this.webgl.viewport = new Viewport(0, 0, this.width, this.height);
835
+ }
836
+ }
837
+
838
+ /*/Attempt to prevent element resizing to 0,0 when a frame is dropped
839
+ if (this.width)
840
+ this.canvas.parentElement.style.minWidth = this.width + 'px';
841
+ if (this.height)
842
+ this.canvas.parentElement.style.minHeight = this.height + 'px';
843
+ */
844
+
845
+ if (!this.gl) return;
846
+
847
+ //Check isContextLost
848
+ if (this.gl.isContextLost()) {
849
+ console.log("boxviewer_draw_: context lost");
850
+ this.mouse.lostContext = true;
851
+ return;
852
+ }
853
+
854
+ this.gl.viewport(0, 0, this.gl.viewportWidth, this.gl.viewportHeight);
855
+ //this.gl.clearColor(1, 1, 1, 0);
856
+ this.gl.clearColor(0, 0, 0, 0);
857
+ this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
858
+
859
+ this.webgl.view(this);
860
+
861
+ //Render objects
862
+ this.border.draw(this.webgl, false, true);
863
+
864
+ //Remove translation and re-render axes
865
+ var tr = this.translate.slice();
866
+ this.translate = [0,0,-this.modelsize*1.25];
867
+ this.webgl.apply(this);
868
+ this.border.draw(this.webgl, true, false);
869
+ this.translate = tr;
870
+ }
871
+
872
+ BoxViewer.prototype.syncRotation = function(rot) {
873
+ if (rot)
874
+ this.rotate = quat4.create(rot);
875
+ this.rotated = true;
876
+ this.draw();
877
+ rstr = '' + this.getRotationString();
878
+ that = this;
879
+ window.requestAnimationFrame(function() {that.command(rstr);});
880
+ }
881
+
882
+ BoxViewer.prototype.rotateX = function(deg) {
883
+ this.rotation(deg, [1,0,0]);
884
+ }
885
+
886
+ BoxViewer.prototype.rotateY = function(deg) {
887
+ this.rotation(deg, [0,1,0]);
888
+ }
889
+
890
+ BoxViewer.prototype.rotateZ = function(deg) {
891
+ this.rotation(deg, [0,0,1]);
892
+ }
893
+
894
+ BoxViewer.prototype.rotation = function(deg, axis) {
895
+ //Quaterion rotate
896
+ var arad = deg * Math.PI / 180.0;
897
+ var rotation = quat4.fromAngleAxis(arad, axis);
898
+ rotation = quat4.normalize(rotation);
899
+ this.rotate = quat4.multiply(rotation, this.rotate);
900
+ }
901
+
902
+ BoxViewer.prototype.getRotation = function() {
903
+ return [this.rotate[0], this.rotate[1], this.rotate[2], this.rotate[3]];
904
+ }
905
+
906
+ BoxViewer.prototype.getRotationString = function() {
907
+ //Return current rotation quaternion as string
908
+ var q = this.getRotation();
909
+ return 'rotation ' + q[0] + ' ' + q[1] + ' ' + q[2] + ' ' + q[3];
910
+ }
911
+
912
+ BoxViewer.prototype.getTranslationString = function() {
913
+ return 'translation ' + this.translate[0] + ' ' + this.translate[1] + ' ' + this.translate[2];
914
+ }
915
+
916
+ BoxViewer.prototype.reset = function() {
917
+ if (this.gl) {
918
+ this.updateDims(this.view);
919
+ this.draw();
920
+ }
921
+
922
+ this.command('reset');
923
+ }
924
+
925
+ BoxViewer.prototype.zoom = function(factor) {
926
+ if (this.gl) {
927
+ this.translate[2] += factor * Math.max(0.01*this.modelsize, Math.abs(this.translate[2]));
928
+ this.draw();
929
+ }
930
+
931
+ var that = this;
932
+ if (this.zoomTimer)
933
+ clearTimeout(this.zoomTimer);
934
+ this.zoomTimer = setTimeout(function () {that.command('' + that.getTranslationString()); that.clear(); that.zoomTimer = null;}, 500 );
935
+
936
+ //this.command('' + this.getTranslationString());
937
+ //this.command('zoom ' + factor);
938
+ }
939
+
940
+ BoxViewer.prototype.zoomClip = function(factor) {
941
+ var near_clip = this.near_clip + factor * this.modelsize;
942
+ if (near_clip >= this.modelsize * 0.001)
943
+ this.near_clip = near_clip;
944
+
945
+ if (this.gl) this.draw();
946
+
947
+ var that = this;
948
+ if (this.zoomTimer) clearTimeout(this.zoomTimer);
949
+ //this.zoomTimer = setTimeout(function () {that.command('zoomclip ' + factor); that.clear();}, 500 );
950
+ this.zoomTimer = setTimeout(function () {that.command('nearclip ' + that.near_clip); that.clear();}, 500 );
951
+
952
+ //this.command('zoomclip ' + factor);
953
+ }
954
+
955
+ BoxViewer.prototype.updateDims = function(view) {
956
+ if (!view) return;
957
+ var oldsize = this.modelsize;
958
+
959
+ //Check for valid dims
960
+ for (var i=0; i<3; i++) {
961
+ if (view.bounds && view.max[i] < view.bounds.max[i])
962
+ view.max[i] = view.bounds.max[i];
963
+ if (view.bounds && view.min[i] > view.bounds.min[i])
964
+ view.min[i] = view.bounds.min[i];
965
+ /*if (view.max[i] < view.min[i] <= 0.0) {
966
+ view.max[i] = 1.0;
967
+ view.min[i] = -1.0;
968
+ }
969
+ }*/
970
+ }
971
+
972
+ this.dims = [view.max[0] - view.min[0], view.max[1] - view.min[1], view.max[2] - view.min[2]];
973
+ this.modelsize = Math.sqrt(this.dims[0]*this.dims[0] + this.dims[1]*this.dims[1] + this.dims[2]*this.dims[2]);
974
+
975
+ this.focus = [view.min[0] + 0.5*this.dims[0], view.min[1] + 0.5*this.dims[1], view.min[2] + 0.5*this.dims[2]];
976
+ this.centre = [this.focus[0],this.focus[1],this.focus[2]];
977
+
978
+ this.translate = [0,0,0];
979
+ if (this.modelsize != oldsize) this.translate[2] = -this.modelsize*1.25;
980
+
981
+ if (this.near_clip == 0.0) this.near_clip = this.modelsize / 10.0;
982
+ if (this.far_clip == 0.0) this.far_clip = this.modelsize * 10.0;
983
+
984
+ quat4.identity(this.rotate);
985
+
986
+ if (view) {
987
+ //Initial rotation
988
+ if (view.rotate) {
989
+ if (view.rotate.length == 3) {
990
+ this.rotateZ(-view.rotate[2]);
991
+ this.rotateY(-view.rotate[1]);
992
+ this.rotateX(-view.rotate[0]);
993
+ } else if (view.rotate.length == 4) {
994
+ this.rotate = quat4.create(view.rotate);
995
+ }
996
+ }
997
+
998
+ //Translate
999
+ if (view.translate) {
1000
+ this.translate[0] = view.translate[0];
1001
+ this.translate[1] = view.translate[1];
1002
+ this.translate[2] = view.translate[2];
1003
+ }
1004
+
1005
+ //Scale
1006
+ if (view.scale) {
1007
+ this.scale[0] = view.scale[0];
1008
+ this.scale[1] = view.scale[1];
1009
+ this.scale[2] = view.scale[2];
1010
+ }
1011
+
1012
+ //Focal point
1013
+ if (view.focus) {
1014
+ this.focus[0] = this.centre[0] = view.focus[0];
1015
+ this.focus[1] = this.centre[1] = view.focus[1];
1016
+ this.focus[2] = this.centre[2] = view.focus[2];
1017
+ }
1018
+
1019
+ }
1020
+
1021
+ //console.log("DIMS: " + view.min[0] + " to " + view.max[0] + "," + view.min[1] + " to " + view.max[1] + "," + view.min[2] + " to " + view.max[2]);
1022
+ //console.log("New model size: " + this.modelsize + ", Focal point: " + this.focus[0] + "," + this.focus[1] + "," + this.focus[2]);
1023
+ //console.log("Translate: " + this.translate[0] + "," + this.translate[1] + "," + this.translate[2]);
1024
+
1025
+ if (!this.gl) return;
1026
+
1027
+ //Create the bounding box vertex buffer
1028
+ this.border.updateBuffers(this.view);
1029
+ }
1030
+