'use strict'; var createMesh = require('../../../stackgl_modules').gl_mesh3d; var parseColorScale = require('../../lib/gl_format_color').parseColorScale; var isArrayOrTypedArray = require('../../lib').isArrayOrTypedArray; var str2RgbaArray = require('../../lib/str2rgbarray'); var extractOpts = require('../../components/colorscale').extractOpts; var zip3 = require('../../plots/gl3d/zip3'); var findNearestOnAxis = function(w, arr) { for(var q = arr.length - 1; q > 0; q--) { var min = Math.min(arr[q], arr[q - 1]); var max = Math.max(arr[q], arr[q - 1]); if(max > min && min < w && w <= max) { return { id: q, distRatio: (max - w) / (max - min) }; } } return { id: 0, distRatio: 0 }; }; function IsosurfaceTrace(scene, mesh, uid) { this.scene = scene; this.uid = uid; this.mesh = mesh; this.name = ''; this.data = null; this.showContour = false; } var proto = IsosurfaceTrace.prototype; proto.handlePick = function(selection) { if(selection.object === this.mesh) { var rawId = selection.data.index; var x = this.data._meshX[rawId]; var y = this.data._meshY[rawId]; var z = this.data._meshZ[rawId]; var height = this.data._Ys.length; var depth = this.data._Zs.length; var i = findNearestOnAxis(x, this.data._Xs).id; var j = findNearestOnAxis(y, this.data._Ys).id; var k = findNearestOnAxis(z, this.data._Zs).id; var selectIndex = selection.index = k + depth * j + depth * height * i; selection.traceCoordinate = [ this.data._meshX[selectIndex], this.data._meshY[selectIndex], this.data._meshZ[selectIndex], this.data._value[selectIndex] ]; var text = this.data.hovertext || this.data.text; if(isArrayOrTypedArray(text) && text[selectIndex] !== undefined) { selection.textLabel = text[selectIndex]; } else if(text) { selection.textLabel = text; } return true; } }; proto.update = function(data) { var scene = this.scene; var layout = scene.fullSceneLayout; this.data = generateIsoMeshes(data); // Unpack position data function toDataCoords(axis, coord, scale, calendar) { return coord.map(function(x) { return axis.d2l(x, 0, calendar) * scale; }); } var positions = zip3( toDataCoords(layout.xaxis, data._meshX, scene.dataScale[0], data.xcalendar), toDataCoords(layout.yaxis, data._meshY, scene.dataScale[1], data.ycalendar), toDataCoords(layout.zaxis, data._meshZ, scene.dataScale[2], data.zcalendar)); var cells = zip3(data._meshI, data._meshJ, data._meshK); var config = { positions: positions, cells: cells, lightPosition: [data.lightposition.x, data.lightposition.y, data.lightposition.z], ambient: data.lighting.ambient, diffuse: data.lighting.diffuse, specular: data.lighting.specular, roughness: data.lighting.roughness, fresnel: data.lighting.fresnel, vertexNormalsEpsilon: data.lighting.vertexnormalsepsilon, faceNormalsEpsilon: data.lighting.facenormalsepsilon, opacity: data.opacity, contourEnable: data.contour.show, contourColor: str2RgbaArray(data.contour.color).slice(0, 3), contourWidth: data.contour.width, useFacetNormals: data.flatshading }; var cOpts = extractOpts(data); config.vertexIntensity = data._meshIntensity; config.vertexIntensityBounds = [cOpts.min, cOpts.max]; config.colormap = parseColorScale(data); // Update mesh this.mesh.update(config); }; proto.dispose = function() { this.scene.glplot.remove(this.mesh); this.mesh.dispose(); }; var GRID_TYPES = ['xyz', 'xzy', 'yxz', 'yzx', 'zxy', 'zyx']; function generateIsoMeshes(data) { data._meshI = []; data._meshJ = []; data._meshK = []; var showSurface = data.surface.show; var showSpaceframe = data.spaceframe.show; var surfaceFill = data.surface.fill; var spaceframeFill = data.spaceframe.fill; var drawingSurface = false; var drawingSpaceframe = false; var numFaces = 0; var numVertices; var beginVertextLength; var Xs = data._Xs; var Ys = data._Ys; var Zs = data._Zs; var width = Xs.length; var height = Ys.length; var depth = Zs.length; var filled = GRID_TYPES.indexOf(data._gridFill.replace(/-/g, '').replace(/\+/g, '')); var getIndex = function(i, j, k) { switch(filled) { case 5: // 'zyx' return k + depth * j + depth * height * i; case 4: // 'zxy' return k + depth * i + depth * width * j; case 3: // 'yzx' return j + height * k + height * depth * i; case 2: // 'yxz' return j + height * i + height * width * k; case 1: // 'xzy' return i + width * k + width * depth * j; default: // case 0: // 'xyz' return i + width * j + width * height * k; } }; var minValues = data._minValues; var maxValues = data._maxValues; var vMin = data._vMin; var vMax = data._vMax; var allXs; var allYs; var allZs; var allVs; function findVertexId(x, y, z) { // could be used to find the vertex id of previously generated vertex within the group var len = allVs.length; for(var f = beginVertextLength; f < len; f++) { if( x === allXs[f] && y === allYs[f] && z === allZs[f] ) { return f; } } return -1; } function beginGroup() { beginVertextLength = numVertices; } function emptyVertices() { allXs = []; allYs = []; allZs = []; allVs = []; numVertices = 0; beginGroup(); } function addVertex(x, y, z, v) { allXs.push(x); allYs.push(y); allZs.push(z); allVs.push(v); numVertices++; return numVertices - 1; } function addFace(a, b, c) { data._meshI.push(a); data._meshJ.push(b); data._meshK.push(c); numFaces++; return numFaces - 1; } function getCenter(A, B, C) { var M = []; for(var i = 0; i < A.length; i++) { M[i] = (A[i] + B[i] + C[i]) / 3.0; } return M; } function getBetween(A, B, r) { var M = []; for(var i = 0; i < A.length; i++) { M[i] = A[i] * (1 - r) + r * B[i]; } return M; } var activeFill; function setFill(fill) { activeFill = fill; } function createOpenTri(xyzv, abc) { var A = xyzv[0]; var B = xyzv[1]; var C = xyzv[2]; var G = getCenter(A, B, C); var r = Math.sqrt(1 - activeFill); var p1 = getBetween(G, A, r); var p2 = getBetween(G, B, r); var p3 = getBetween(G, C, r); var a = abc[0]; var b = abc[1]; var c = abc[2]; return { xyzv: [ [A, B, p2], [p2, p1, A], [B, C, p3], [p3, p2, B], [C, A, p1], [p1, p3, C] ], abc: [ [a, b, -1], [-1, -1, a], [b, c, -1], [-1, -1, b], [c, a, -1], [-1, -1, c] ] }; } function styleIncludes(style, char) { if(style === 'all' || style === null) return true; return (style.indexOf(char) > -1); } function mapValue(style, value) { if(style === null) return value; return style; } function drawTri(style, xyzv, abc) { beginGroup(); var allXYZVs = [xyzv]; var allABCs = [abc]; if(activeFill >= 1) { allXYZVs = [xyzv]; allABCs = [abc]; } else if(activeFill > 0) { var openTri = createOpenTri(xyzv, abc); allXYZVs = openTri.xyzv; allABCs = openTri.abc; } for(var f = 0; f < allXYZVs.length; f++) { xyzv = allXYZVs[f]; abc = allABCs[f]; var pnts = []; for(var i = 0; i < 3; i++) { var x = xyzv[i][0]; var y = xyzv[i][1]; var z = xyzv[i][2]; var v = xyzv[i][3]; var id = (abc[i] > -1) ? abc[i] : findVertexId(x, y, z); if(id > -1) { pnts[i] = id; } else { pnts[i] = addVertex(x, y, z, mapValue(style, v)); } } addFace(pnts[0], pnts[1], pnts[2]); } } function drawQuad(style, xyzv, abcd) { var makeTri = function(i, j, k) { drawTri(style, [xyzv[i], xyzv[j], xyzv[k]], [abcd[i], abcd[j], abcd[k]]); }; makeTri(0, 1, 2); makeTri(2, 3, 0); } function drawTetra(style, xyzv, abcd) { var makeTri = function(i, j, k) { drawTri(style, [xyzv[i], xyzv[j], xyzv[k]], [abcd[i], abcd[j], abcd[k]]); }; makeTri(0, 1, 2); makeTri(3, 0, 1); makeTri(2, 3, 0); makeTri(1, 2, 3); } function calcIntersection(pointOut, pointIn, min, max) { var value = pointOut[3]; if(value < min) value = min; if(value > max) value = max; var ratio = (pointOut[3] - value) / (pointOut[3] - pointIn[3] + 0.000000001); // we had to add this error to force solve the tiny caps var result = []; for(var s = 0; s < 4; s++) { result[s] = (1 - ratio) * pointOut[s] + ratio * pointIn[s]; } return result; } function inRange(value, min, max) { return ( value >= min && value <= max ); } function almostInFinalRange(value) { var vErr = 0.001 * (vMax - vMin); return ( value >= vMin - vErr && value <= vMax + vErr ); } function getXYZV(indecies) { var xyzv = []; for(var q = 0; q < 4; q++) { var index = indecies[q]; xyzv.push( [ data._x[index], data._y[index], data._z[index], data._value[index] ] ); } return xyzv; } var MAX_PASS = 3; function tryCreateTri(style, xyzv, abc, min, max, nPass) { if(!nPass) nPass = 1; abc = [-1, -1, -1]; // Note: for the moment we override indices // to run faster! But it is possible to comment this line // to reduce the number of vertices. var result = false; var ok = [ inRange(xyzv[0][3], min, max), inRange(xyzv[1][3], min, max), inRange(xyzv[2][3], min, max) ]; if(!ok[0] && !ok[1] && !ok[2]) { return false; } var tryDrawTri = function(style, xyzv, abc) { if( // we check here if the points are in `real` iso-min/max range almostInFinalRange(xyzv[0][3]) && almostInFinalRange(xyzv[1][3]) && almostInFinalRange(xyzv[2][3]) ) { drawTri(style, xyzv, abc); return true; } else if(nPass < MAX_PASS) { return tryCreateTri(style, xyzv, abc, vMin, vMax, ++nPass); // i.e. second pass using actual vMin vMax bounds } return false; }; if(ok[0] && ok[1] && ok[2]) { return tryDrawTri(style, xyzv, abc) || result; } var interpolated = false; [ [0, 1, 2], [2, 0, 1], [1, 2, 0] ].forEach(function(e) { if(ok[e[0]] && ok[e[1]] && !ok[e[2]]) { var A = xyzv[e[0]]; var B = xyzv[e[1]]; var C = xyzv[e[2]]; var p1 = calcIntersection(C, A, min, max); var p2 = calcIntersection(C, B, min, max); result = tryDrawTri(style, [p2, p1, A], [-1, -1, abc[e[0]]]) || result; result = tryDrawTri(style, [A, B, p2], [abc[e[0]], abc[e[1]], -1]) || result; interpolated = true; } }); if(interpolated) return result; [ [0, 1, 2], [1, 2, 0], [2, 0, 1] ].forEach(function(e) { if(ok[e[0]] && !ok[e[1]] && !ok[e[2]]) { var A = xyzv[e[0]]; var B = xyzv[e[1]]; var C = xyzv[e[2]]; var p1 = calcIntersection(B, A, min, max); var p2 = calcIntersection(C, A, min, max); result = tryDrawTri(style, [p2, p1, A], [-1, -1, abc[e[0]]]) || result; interpolated = true; } }); return result; } function tryCreateTetra(style, abcd, min, max) { var result = false; var xyzv = getXYZV(abcd); var ok = [ inRange(xyzv[0][3], min, max), inRange(xyzv[1][3], min, max), inRange(xyzv[2][3], min, max), inRange(xyzv[3][3], min, max) ]; if(!ok[0] && !ok[1] && !ok[2] && !ok[3]) { return result; } if(ok[0] && ok[1] && ok[2] && ok[3]) { if(drawingSpaceframe) { result = drawTetra(style, xyzv, abcd) || result; } return result; } var interpolated = false; [ [0, 1, 2, 3], [3, 0, 1, 2], [2, 3, 0, 1], [1, 2, 3, 0] ].forEach(function(e) { if(ok[e[0]] && ok[e[1]] && ok[e[2]] && !ok[e[3]]) { var A = xyzv[e[0]]; var B = xyzv[e[1]]; var C = xyzv[e[2]]; var D = xyzv[e[3]]; if(drawingSpaceframe) { result = drawTri(style, [A, B, C], [abcd[e[0]], abcd[e[1]], abcd[e[2]]]) || result; } else { var p1 = calcIntersection(D, A, min, max); var p2 = calcIntersection(D, B, min, max); var p3 = calcIntersection(D, C, min, max); result = drawTri(null, [p1, p2, p3], [-1, -1, -1]) || result; } interpolated = true; } }); if(interpolated) return result; [ [0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 0, 1, 2], [0, 2, 3, 1], [1, 3, 2, 0] ].forEach(function(e) { if(ok[e[0]] && ok[e[1]] && !ok[e[2]] && !ok[e[3]]) { var A = xyzv[e[0]]; var B = xyzv[e[1]]; var C = xyzv[e[2]]; var D = xyzv[e[3]]; var p1 = calcIntersection(C, A, min, max); var p2 = calcIntersection(C, B, min, max); var p3 = calcIntersection(D, B, min, max); var p4 = calcIntersection(D, A, min, max); if(drawingSpaceframe) { result = drawTri(style, [A, p4, p1], [abcd[e[0]], -1, -1]) || result; result = drawTri(style, [B, p2, p3], [abcd[e[1]], -1, -1]) || result; } else { result = drawQuad(null, [p1, p2, p3, p4], [-1, -1, -1, -1]) || result; } interpolated = true; } }); if(interpolated) return result; [ [0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 0, 1, 2] ].forEach(function(e) { if(ok[e[0]] && !ok[e[1]] && !ok[e[2]] && !ok[e[3]]) { var A = xyzv[e[0]]; var B = xyzv[e[1]]; var C = xyzv[e[2]]; var D = xyzv[e[3]]; var p1 = calcIntersection(B, A, min, max); var p2 = calcIntersection(C, A, min, max); var p3 = calcIntersection(D, A, min, max); if(drawingSpaceframe) { result = drawTri(style, [A, p1, p2], [abcd[e[0]], -1, -1]) || result; result = drawTri(style, [A, p2, p3], [abcd[e[0]], -1, -1]) || result; result = drawTri(style, [A, p3, p1], [abcd[e[0]], -1, -1]) || result; } else { result = drawTri(null, [p1, p2, p3], [-1, -1, -1]) || result; } interpolated = true; } }); return result; } function addCube(style, p000, p001, p010, p011, p100, p101, p110, p111, min, max) { var result = false; if(drawingSurface) { if(styleIncludes(style, 'A')) { result = tryCreateTetra(null, [p000, p001, p010, p100], min, max) || result; } if(styleIncludes(style, 'B')) { result = tryCreateTetra(null, [p001, p010, p011, p111], min, max) || result; } if(styleIncludes(style, 'C')) { result = tryCreateTetra(null, [p001, p100, p101, p111], min, max) || result; } if(styleIncludes(style, 'D')) { result = tryCreateTetra(null, [p010, p100, p110, p111], min, max) || result; } if(styleIncludes(style, 'E')) { result = tryCreateTetra(null, [p001, p010, p100, p111], min, max) || result; } } if(drawingSpaceframe) { result = tryCreateTetra(style, [p001, p010, p100, p111], min, max) || result; } return result; } function addRect(style, a, b, c, d, min, max, previousResult) { return [ (previousResult[0] === true) ? true : tryCreateTri(style, getXYZV([a, b, c]), [a, b, c], min, max), (previousResult[1] === true) ? true : tryCreateTri(style, getXYZV([c, d, a]), [c, d, a], min, max) ]; } function begin2dCell(style, p00, p01, p10, p11, min, max, isEven, previousResult) { // used to create caps and/or slices on exact axis points if(isEven) { return addRect(style, p00, p01, p11, p10, min, max, previousResult); } else { return addRect(style, p01, p11, p10, p00, min, max, previousResult); } } function beginSection(style, i, j, k, min, max, distRatios) { // used to create slices between axis points var result = false; var A, B, C, D; var makeSection = function() { result = tryCreateTri(style, [A, B, C], [-1, -1, -1], min, max) || result; result = tryCreateTri(style, [C, D, A], [-1, -1, -1], min, max) || result; }; var rX = distRatios[0]; var rY = distRatios[1]; var rZ = distRatios[2]; if(rX) { A = getBetween(getXYZV([getIndex(i, j - 0, k - 0)])[0], getXYZV([getIndex(i - 1, j - 0, k - 0)])[0], rX); B = getBetween(getXYZV([getIndex(i, j - 0, k - 1)])[0], getXYZV([getIndex(i - 1, j - 0, k - 1)])[0], rX); C = getBetween(getXYZV([getIndex(i, j - 1, k - 1)])[0], getXYZV([getIndex(i - 1, j - 1, k - 1)])[0], rX); D = getBetween(getXYZV([getIndex(i, j - 1, k - 0)])[0], getXYZV([getIndex(i - 1, j - 1, k - 0)])[0], rX); makeSection(); } if(rY) { A = getBetween(getXYZV([getIndex(i - 0, j, k - 0)])[0], getXYZV([getIndex(i - 0, j - 1, k - 0)])[0], rY); B = getBetween(getXYZV([getIndex(i - 0, j, k - 1)])[0], getXYZV([getIndex(i - 0, j - 1, k - 1)])[0], rY); C = getBetween(getXYZV([getIndex(i - 1, j, k - 1)])[0], getXYZV([getIndex(i - 1, j - 1, k - 1)])[0], rY); D = getBetween(getXYZV([getIndex(i - 1, j, k - 0)])[0], getXYZV([getIndex(i - 1, j - 1, k - 0)])[0], rY); makeSection(); } if(rZ) { A = getBetween(getXYZV([getIndex(i - 0, j - 0, k)])[0], getXYZV([getIndex(i - 0, j - 0, k - 1)])[0], rZ); B = getBetween(getXYZV([getIndex(i - 0, j - 1, k)])[0], getXYZV([getIndex(i - 0, j - 1, k - 1)])[0], rZ); C = getBetween(getXYZV([getIndex(i - 1, j - 1, k)])[0], getXYZV([getIndex(i - 1, j - 1, k - 1)])[0], rZ); D = getBetween(getXYZV([getIndex(i - 1, j - 0, k)])[0], getXYZV([getIndex(i - 1, j - 0, k - 1)])[0], rZ); makeSection(); } return result; } function begin3dCell(style, p000, p001, p010, p011, p100, p101, p110, p111, min, max, isEven) { // used to create spaceframe and/or iso-surfaces var cellStyle = style; if(isEven) { if(drawingSurface && style === 'even') cellStyle = null; return addCube(cellStyle, p000, p001, p010, p011, p100, p101, p110, p111, min, max); } else { if(drawingSurface && style === 'odd') cellStyle = null; return addCube(cellStyle, p111, p110, p101, p100, p011, p010, p001, p000, min, max); } } function draw2dX(style, items, min, max, previousResult) { var result = []; var n = 0; for(var q = 0; q < items.length; q++) { var i = items[q]; for(var k = 1; k < depth; k++) { for(var j = 1; j < height; j++) { result.push( begin2dCell(style, getIndex(i, j - 1, k - 1), getIndex(i, j - 1, k), getIndex(i, j, k - 1), getIndex(i, j, k), min, max, (i + j + k) % 2, (previousResult && previousResult[n]) ? previousResult[n] : [] ) ); n++; } } } return result; } function draw2dY(style, items, min, max, previousResult) { var result = []; var n = 0; for(var q = 0; q < items.length; q++) { var j = items[q]; for(var i = 1; i < width; i++) { for(var k = 1; k < depth; k++) { result.push( begin2dCell(style, getIndex(i - 1, j, k - 1), getIndex(i, j, k - 1), getIndex(i - 1, j, k), getIndex(i, j, k), min, max, (i + j + k) % 2, (previousResult && previousResult[n]) ? previousResult[n] : [] ) ); n++; } } } return result; } function draw2dZ(style, items, min, max, previousResult) { var result = []; var n = 0; for(var q = 0; q < items.length; q++) { var k = items[q]; for(var j = 1; j < height; j++) { for(var i = 1; i < width; i++) { result.push( begin2dCell(style, getIndex(i - 1, j - 1, k), getIndex(i - 1, j, k), getIndex(i, j - 1, k), getIndex(i, j, k), min, max, (i + j + k) % 2, (previousResult && previousResult[n]) ? previousResult[n] : [] ) ); n++; } } } return result; } function draw3d(style, min, max) { for(var k = 1; k < depth; k++) { for(var j = 1; j < height; j++) { for(var i = 1; i < width; i++) { begin3dCell(style, getIndex(i - 1, j - 1, k - 1), getIndex(i - 1, j - 1, k), getIndex(i - 1, j, k - 1), getIndex(i - 1, j, k), getIndex(i, j - 1, k - 1), getIndex(i, j - 1, k), getIndex(i, j, k - 1), getIndex(i, j, k), min, max, (i + j + k) % 2 ); } } } } function drawSpaceframe(style, min, max) { drawingSpaceframe = true; draw3d(style, min, max); drawingSpaceframe = false; } function drawSurface(style, min, max) { drawingSurface = true; draw3d(style, min, max); drawingSurface = false; } function drawSectionX(style, items, min, max, distRatios, previousResult) { var result = []; var n = 0; for(var q = 0; q < items.length; q++) { var i = items[q]; for(var k = 1; k < depth; k++) { for(var j = 1; j < height; j++) { result.push( beginSection(style, i, j, k, min, max, distRatios[q], (previousResult && previousResult[n]) ? previousResult[n] : [] ) ); n++; } } } return result; } function drawSectionY(style, items, min, max, distRatios, previousResult) { var result = []; var n = 0; for(var q = 0; q < items.length; q++) { var j = items[q]; for(var i = 1; i < width; i++) { for(var k = 1; k < depth; k++) { result.push( beginSection(style, i, j, k, min, max, distRatios[q], (previousResult && previousResult[n]) ? previousResult[n] : [] ) ); n++; } } } return result; } function drawSectionZ(style, items, min, max, distRatios, previousResult) { var result = []; var n = 0; for(var q = 0; q < items.length; q++) { var k = items[q]; for(var j = 1; j < height; j++) { for(var i = 1; i < width; i++) { result.push( beginSection(style, i, j, k, min, max, distRatios[q], (previousResult && previousResult[n]) ? previousResult[n] : [] ) ); n++; } } } return result; } function createRange(a, b) { var range = []; for(var q = a; q < b; q++) { range.push(q); } return range; } function insertGridPoints() { for(var i = 0; i < width; i++) { for(var j = 0; j < height; j++) { for(var k = 0; k < depth; k++) { var index = getIndex(i, j, k); addVertex( data._x[index], data._y[index], data._z[index], data._value[index] ); } } } } function drawAll() { emptyVertices(); // insert grid points insertGridPoints(); var activeStyle = null; // draw spaceframes if(showSpaceframe && spaceframeFill) { setFill(spaceframeFill); drawSpaceframe(activeStyle, vMin, vMax); } // draw iso-surfaces if(showSurface && surfaceFill) { setFill(surfaceFill); var surfacePattern = data.surface.pattern; var surfaceCount = data.surface.count; for(var q = 0; q < surfaceCount; q++) { var ratio = (surfaceCount === 1) ? 0.5 : q / (surfaceCount - 1); var level = (1 - ratio) * vMin + ratio * vMax; var d1 = Math.abs(level - minValues); var d2 = Math.abs(level - maxValues); var ranges = (d1 > d2) ? [minValues, level] : [level, maxValues]; drawSurface(surfacePattern, ranges[0], ranges[1]); } } var setupMinMax = [ [ Math.min(vMin, maxValues), Math.max(vMin, maxValues) ], [ Math.min(minValues, vMax), Math.max(minValues, vMax) ] ]; ['x', 'y', 'z'].forEach(function(e) { var preRes = []; for(var s = 0; s < setupMinMax.length; s++) { var count = 0; var activeMin = setupMinMax[s][0]; var activeMax = setupMinMax[s][1]; // draw slices var slice = data.slices[e]; if(slice.show && slice.fill) { setFill(slice.fill); var exactIndices = []; var ceilIndices = []; var distRatios = []; if(slice.locations.length) { for(var q = 0; q < slice.locations.length; q++) { var near = findNearestOnAxis( slice.locations[q], (e === 'x') ? Xs : (e === 'y') ? Ys : Zs ); if(near.distRatio === 0) { exactIndices.push(near.id); } else if(near.id > 0) { ceilIndices.push(near.id); if(e === 'x') { distRatios.push([near.distRatio, 0, 0]); } else if(e === 'y') { distRatios.push([0, near.distRatio, 0]); } else { distRatios.push([0, 0, near.distRatio]); } } } } else { if(e === 'x') { exactIndices = createRange(1, width - 1); } else if(e === 'y') { exactIndices = createRange(1, height - 1); } else { exactIndices = createRange(1, depth - 1); } } if(ceilIndices.length > 0) { if(e === 'x') { preRes[count] = drawSectionX(activeStyle, ceilIndices, activeMin, activeMax, distRatios, preRes[count]); } else if(e === 'y') { preRes[count] = drawSectionY(activeStyle, ceilIndices, activeMin, activeMax, distRatios, preRes[count]); } else { preRes[count] = drawSectionZ(activeStyle, ceilIndices, activeMin, activeMax, distRatios, preRes[count]); } count++; } if(exactIndices.length > 0) { if(e === 'x') { preRes[count] = draw2dX(activeStyle, exactIndices, activeMin, activeMax, preRes[count]); } else if(e === 'y') { preRes[count] = draw2dY(activeStyle, exactIndices, activeMin, activeMax, preRes[count]); } else { preRes[count] = draw2dZ(activeStyle, exactIndices, activeMin, activeMax, preRes[count]); } count++; } } // draw caps var cap = data.caps[e]; if(cap.show && cap.fill) { setFill(cap.fill); if(e === 'x') { preRes[count] = draw2dX(activeStyle, [0, width - 1], activeMin, activeMax, preRes[count]); } else if(e === 'y') { preRes[count] = draw2dY(activeStyle, [0, height - 1], activeMin, activeMax, preRes[count]); } else { preRes[count] = draw2dZ(activeStyle, [0, depth - 1], activeMin, activeMax, preRes[count]); } count++; } } }); // remove vertices arrays (i.e. grid points) in case no face was created. if(numFaces === 0) { emptyVertices(); } data._meshX = allXs; data._meshY = allYs; data._meshZ = allZs; data._meshIntensity = allVs; data._Xs = Xs; data._Ys = Ys; data._Zs = Zs; } drawAll(); return data; } function createIsosurfaceTrace(scene, data) { var gl = scene.glplot.gl; var mesh = createMesh({gl: gl}); var result = new IsosurfaceTrace(scene, mesh, data.uid); mesh._trace = result; result.update(data); scene.glplot.add(mesh); return result; } module.exports = { findNearestOnAxis: findNearestOnAxis, generateIsoMeshes: generateIsoMeshes, createIsosurfaceTrace: createIsosurfaceTrace, };