package.src.traces.isosurface.convert.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plotly.js Show documentation
Show all versions of plotly.js Show documentation
The open source javascript graphing library that powers plotly
The newest version!
'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,
};