From 892e7ed03ab826f8f18c244ac0005279cc7259b2 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Mon, 18 Jun 2018 13:35:58 +0800 Subject: [PATCH 01/16] initial scaffold for isosurface traces --- lib/index.js | 1 + lib/isosurface.js | 11 ++ package.json | 1 + src/traces/isosurface/attributes.js | 182 ++++++++++++++++++++++++++++ src/traces/isosurface/calc.js | 34 ++++++ src/traces/isosurface/convert.js | 147 ++++++++++++++++++++++ src/traces/isosurface/defaults.js | 58 +++++++++ src/traces/isosurface/index.js | 37 ++++++ 8 files changed, 471 insertions(+) create mode 100644 lib/isosurface.js create mode 100644 src/traces/isosurface/attributes.js create mode 100644 src/traces/isosurface/calc.js create mode 100644 src/traces/isosurface/convert.js create mode 100644 src/traces/isosurface/defaults.js create mode 100644 src/traces/isosurface/index.js diff --git a/lib/index.js b/lib/index.js index 4d014421b61..e3de210d800 100644 --- a/lib/index.js +++ b/lib/index.js @@ -27,6 +27,7 @@ Plotly.register([ require('./surface'), require('./mesh3d'), require('./cone'), + require('./isosurface'), require('./scattergeo'), require('./choropleth'), diff --git a/lib/isosurface.js b/lib/isosurface.js new file mode 100644 index 00000000000..7bc97ae239e --- /dev/null +++ b/lib/isosurface.js @@ -0,0 +1,11 @@ +/** +* Copyright 2012-2018, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = require('../src/traces/isosurface'); diff --git a/package.json b/package.json index 7ff361e57c1..af117299313 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", "font-atlas-sdf": "^1.3.3", + "gl-isosurface3d": "https://github.com/gl-vis/gl-isosurface3d.git", "gl-cone3d": "^1.1.0", "gl-contour2d": "^1.1.4", "gl-error3d": "^1.0.7", diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js new file mode 100644 index 00000000000..5aa25409e6a --- /dev/null +++ b/src/traces/isosurface/attributes.js @@ -0,0 +1,182 @@ +/** +* Copyright 2012-2018, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var colorAttrs = require('../../components/colorscale/color_attributes'); +var colorscaleAttrs = require('../../components/colorscale/attributes'); +var colorbarAttrs = require('../../components/colorbar/attributes'); +var mesh3dAttrs = require('../mesh3d/attributes'); +var baseAttrs = require('../../plots/attributes'); + +var extendFlat = require('../../lib/extend').extendFlat; + +var attrs = { + x: { + valType: 'data_array', + role: 'info', + editType: 'calc+clearAxisTypes', + description: [ + 'Sets the x coordinates of the vector field', + 'and of the displayed cones.' + ].join(' ') + }, + y: { + valType: 'data_array', + role: 'info', + editType: 'calc+clearAxisTypes', + description: [ + 'Sets the y coordinates of the vector field', + 'and of the displayed cones.' + ].join(' ') + }, + z: { + valType: 'data_array', + role: 'info', + editType: 'calc+clearAxisTypes', + description: [ + 'Sets the z coordinates of the vector field', + 'and of the displayed cones.' + ].join(' ') + }, + + u: { + valType: 'data_array', + editType: 'calc', + description: 'Sets the x components of the vector field.' + }, + v: { + valType: 'data_array', + editType: 'calc', + description: 'Sets the y components of the vector field.' + }, + w: { + valType: 'data_array', + editType: 'calc', + description: 'Sets the z components of the vector field.' + }, + + // TODO add way to specify cone positions independently of the vector field + // provided, similar to MATLAB's coneplot Cx/Cy/Cz meshgrids, + // see https://www.mathworks.com/help/matlab/ref/coneplot.html + // + // Alternatively, if our goal is only to 'fill in gaps' in the vector data, + // we could try to extend the heatmap 'connectgaps' algorithm to 3D. + // From AJ: this particular algorithm which amounts to a Poisson equation, + // both for interpolation and extrapolation - is the right one to use for + // cones too. It makes a field with zero divergence, which is a good + // baseline assumption for vector fields. + // + // cones: { + // // potential attributes to add: + // // + // // - meshmode: 'cartesian-product', 'pts', 'grid' + // // + // // under `meshmode: 'grid'` + // // - (x|y|z)grid.start + // // - (x|y|z)grid.end + // // - (x|y|z)grid.size + // + // x: { + // valType: 'data_array', + // editType: 'calc', + // description: 'Sets the x coordinates of the cones to be displayed.' + // }, + // y: { + // valType: 'data_array', + // editType: 'calc', + // description: 'Sets the y coordinates of the cones to be displayed.' + // }, + // z: { + // valType: 'data_array', + // editType: 'calc', + // description: 'Sets the z coordinates of the cones to be displayed.' + // }, + // + // editType: 'calc', + // description: [ + // 'By setting `cones.x`, `cones.y` and `cones.z` to 1D arrays,', + // 'plotly creates a mesh using the cartesian product of those 3 arrays.' + // ].join(' ') + // }, + + sizemode: { + valType: 'enumerated', + values: ['scaled', 'absolute'], + role: 'info', + editType: 'calc', + dflt: 'scaled', + description: [ + 'Determines whether `sizeref` is set as a *scaled* (i.e unitless) scalar', + '(normalized by the max u/v/w norm in the vector field) or as', + '*absolute* value (in the same units as the vector field).' + ].join(' ') + }, + sizeref: { + valType: 'number', + role: 'info', + editType: 'calc', + min: 0, + description: [ + 'Adjusts the cone size scaling.', + 'The size of the cones is determined by their u/v/w norm multiplied a factor and `sizeref`.', + 'This factor (computed internally) corresponds to the minimum "time" to travel across', + 'two successive x/y/z positions at the average velocity of those two successive positions.', + 'All cones in a given trace use the same factor.', + 'With `sizemode` set to *scaled*, `sizeref` is unitless, its default value is *0.5*', + 'With `sizemode` set to *absolute*, `sizeref` has the same units as the u/v/w vector field,', + 'its the default value is half the sample\'s maximum vector norm.' + ].join(' ') + }, + + anchor: { + valType: 'enumerated', + role: 'info', + editType: 'calc', + values: ['tip', 'tail', 'cm', 'center'], + dflt: 'cm', + description: [ + 'Sets the cones\' anchor with respect to their x/y/z positions.', + 'Note that *cm* denote the cone\'s center of mass which corresponds to', + '1/4 from the tail to tip.' + ].join(' ') + }, + + text: { + valType: 'string', + role: 'info', + dflt: '', + arrayOk: true, + editType: 'calc', + description: [ + 'Sets the text elements associated with the cones.', + 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', + 'these elements will be seen in the hover labels.' + ].join(' ') + } +}; + +extendFlat(attrs, colorAttrs('', 'calc', true), { + showscale: colorscaleAttrs.showscale, + colorbar: colorbarAttrs +}); +delete attrs.color; + +var fromMesh3d = ['opacity', 'lightposition', 'lighting']; + +fromMesh3d.forEach(function(k) { + attrs[k] = mesh3dAttrs[k]; +}); + +attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, { + editType: 'calc', + flags: ['x', 'y', 'z', 'u', 'v', 'w', 'norm', 'text', 'name'], + dflt: 'x+y+z+norm+text+name' +}); + +module.exports = attrs; diff --git a/src/traces/isosurface/calc.js b/src/traces/isosurface/calc.js new file mode 100644 index 00000000000..7a0f1e20982 --- /dev/null +++ b/src/traces/isosurface/calc.js @@ -0,0 +1,34 @@ +/** +* Copyright 2012-2018, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var colorscaleCalc = require('../../components/colorscale/calc'); + +module.exports = function calc(gd, trace) { + var u = trace.u; + var v = trace.v; + var w = trace.w; + var len = Math.min(u.length, v.length, w.length); + var normMax = -Infinity; + var normMin = Infinity; + + for(var i = 0; i < len; i++) { + var uu = u[i]; + var vv = v[i]; + var ww = w[i]; + var norm = Math.sqrt(uu * uu + vv * vv + ww * ww); + + normMax = Math.max(normMax, norm); + normMin = Math.min(normMin, norm); + } + + trace._normMax = normMax; + + colorscaleCalc(trace, [normMin, normMax], '', 'c'); +}; diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js new file mode 100644 index 00000000000..1694b45c1bf --- /dev/null +++ b/src/traces/isosurface/convert.js @@ -0,0 +1,147 @@ +/** +* Copyright 2012-2018, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +var isosurfacePlot = require('gl-isosurface3d'); + +var simpleMap = require('../../lib').simpleMap; +var parseColorScale = require('../../lib/gl_format_color').parseColorScale; + +function Isosurface(scene, uid) { + this.scene = scene; + this.uid = uid; + this.mesh = null; + this.data = null; +} + +var proto = Isosurface.prototype; + +proto.handlePick = function(selection) { + if(selection.object === this.mesh) { + var selectIndex = selection.index = selection.data.index; + var xx = this.data.x[selectIndex]; + var yy = this.data.y[selectIndex]; + var zz = this.data.z[selectIndex]; + var uu = this.data.u[selectIndex]; + var vv = this.data.v[selectIndex]; + var ww = this.data.w[selectIndex]; + + selection.traceCoordinate = [ + xx, yy, zz, + uu, vv, ww, + Math.sqrt(uu * uu + vv * vv + ww * ww) + ]; + + var text = this.data.text; + if(Array.isArray(text) && text[selectIndex] !== undefined) { + selection.textLabel = text[selectIndex]; + } else if(text) { + selection.textLabel = text; + } + + return true; + } +}; + +function zip3(x, y, z) { + var result = new Array(x.length); + for(var i = 0; i < x.length; i++) { + result[i] = [x[i], y[i], z[i]]; + } + return result; +} + +var axisName2scaleIndex = {xaxis: 0, yaxis: 1, zaxis: 2}; +var anchor2coneOffset = {tip: 1, tail: 0, cm: 0.25, center: 0.5}; +var anchor2coneSpan = {tip: 1, tail: 1, cm: 0.75, center: 0.5}; + +function convert(scene, trace) { + var sceneLayout = scene.fullSceneLayout; + var dataScale = scene.dataScale; + var isosurfaceOpts = {}; + + function toDataCoords(arr, axisName) { + var ax = sceneLayout[axisName]; + var scale = dataScale[axisName2scaleIndex[axisName]]; + return simpleMap(arr, function(v) { return ax.d2l(v) * scale; }); + } + + isosurfaceOpts.vectors = zip3( + toDataCoords(trace.u, 'xaxis'), + toDataCoords(trace.v, 'yaxis'), + toDataCoords(trace.w, 'zaxis') + ); + + isosurfaceOpts.positions = zip3( + toDataCoords(trace.x, 'xaxis'), + toDataCoords(trace.y, 'yaxis'), + toDataCoords(trace.z, 'zaxis') + ); + + isosurfaceOpts.colormap = parseColorScale(trace.colorscale); + isosurfaceOpts.vertexIntensityBounds = [trace.cmin / trace._normMax, trace.cmax / trace._normMax]; + isosurfaceOpts.coneOffset = anchor2coneOffset[trace.anchor]; + + if(trace.sizemode === 'scaled') { + // unitless sizeref + isosurfaceOpts.coneSize = trace.sizeref || 0.5; + } else { + // sizeref here has unit of velocity + isosurfaceOpts.coneSize = trace.sizeref && trace._normMax ? + trace.sizeref / trace._normMax : + 0.5; + } + + var meshData = isosurfacePlot(isosurfaceOpts); + + // pass gl-mesh3d lighting attributes + var lp = trace.lightposition; + meshData.lightPosition = [lp.x, lp.y, lp.z]; + meshData.ambient = trace.lighting.ambient; + meshData.diffuse = trace.lighting.diffuse; + meshData.specular = trace.lighting.specular; + meshData.roughness = trace.lighting.roughness; + meshData.fresnel = trace.lighting.fresnel; + meshData.opacity = trace.opacity; + + // stash autorange pad value + trace._pad = anchor2coneSpan[trace.anchor] * meshData.vectorScale * meshData.coneScale * trace._normMax; + + return meshData; +} + +proto.update = function(data) { + this.data = data; + + var meshData = convert(this.scene, data); + this.mesh.update(meshData); +}; + +proto.dispose = function() { + this.scene.glplot.remove(this.mesh); + this.mesh.dispose(); +}; + +function createIsosurfaceTrace(scene, data) { + var gl = scene.glplot.gl; + + var meshData = convert(scene, data); + var mesh = isosurfacePlot.createMesh(gl, meshData); + + var Isosurface = new Isosurface(scene, data.uid); + Isosurface.mesh = mesh; + Isosurface.data = data; + mesh._trace = Isosurface; + + scene.glplot.add(mesh); + + return Isosurface; +} + +module.exports = createIsosurfaceTrace; diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js new file mode 100644 index 00000000000..b76aedf6b23 --- /dev/null +++ b/src/traces/isosurface/defaults.js @@ -0,0 +1,58 @@ +/** +* Copyright 2012-2018, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var Lib = require('../../lib'); + +var colorscaleDefaults = require('../../components/colorscale/defaults'); +var attributes = require('./attributes'); + +module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { + function coerce(attr, dflt) { + return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); + } + + var u = coerce('u'); + var v = coerce('v'); + var w = coerce('w'); + + var x = coerce('x'); + var y = coerce('y'); + var z = coerce('z'); + + if( + !u || !u.length || !v || !v.length || !w || !w.length || + !x || !x.length || !y || !y.length || !z || !z.length + ) { + traceOut.visible = false; + return; + } + + coerce('sizeref'); + coerce('sizemode'); + + coerce('anchor'); + + coerce('lighting.ambient'); + coerce('lighting.diffuse'); + coerce('lighting.specular'); + coerce('lighting.roughness'); + coerce('lighting.fresnel'); + coerce('lightposition.x'); + coerce('lightposition.y'); + coerce('lightposition.z'); + + colorscaleDefaults(traceIn, traceOut, layout, coerce, {prefix: '', cLetter: 'c'}); + + coerce('text'); + + // disable 1D transforms (for now) + traceOut._length = null; +}; diff --git a/src/traces/isosurface/index.js b/src/traces/isosurface/index.js new file mode 100644 index 00000000000..fb15f5ac6e5 --- /dev/null +++ b/src/traces/isosurface/index.js @@ -0,0 +1,37 @@ +/** +* Copyright 2012-2018, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + +module.exports = { + moduleType: 'trace', + name: 'cone', + basePlotModule: require('../../plots/gl3d'), + categories: ['gl3d'], + + attributes: require('./attributes'), + supplyDefaults: require('./defaults'), + colorbar: { + min: 'cmin', + max: 'cmax' + }, + calc: require('./calc'), + plot: require('./convert'), + + meta: { + description: [ + 'Use cone traces to visualize vector fields.', + '', + 'Specify a vector field using 6 1D arrays,', + '3 position arrays `x`, `y` and `z`', + 'and 3 vector component arrays `u`, `v`, `w`.', + 'The cones are drawn exactly at the positions given', + 'by `x`, `y` and `z`.' + ].join(' ') + } +}; From f6aba7974011ade701ffe634197b6575e45304ee Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Sat, 23 Jun 2018 06:12:27 +0800 Subject: [PATCH 02/16] first working version of the isosurface plot --- src/traces/isosurface/attributes.js | 131 +++++++----------------- src/traces/isosurface/calc.js | 8 +- src/traces/isosurface/convert.js | 148 ++++++++++++++++++++-------- src/traces/isosurface/defaults.js | 13 ++- src/traces/isosurface/index.js | 10 +- 5 files changed, 157 insertions(+), 153 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index 5aa25409e6a..988483f3f8b 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -22,8 +22,7 @@ var attrs = { role: 'info', editType: 'calc+clearAxisTypes', description: [ - 'Sets the x coordinates of the vector field', - 'and of the displayed cones.' + 'Sets the x coordinates of the isosurface' ].join(' ') }, y: { @@ -31,8 +30,7 @@ var attrs = { role: 'info', editType: 'calc+clearAxisTypes', description: [ - 'Sets the y coordinates of the vector field', - 'and of the displayed cones.' + 'Sets the y coordinates of the isosurface' ].join(' ') }, z: { @@ -40,111 +38,56 @@ var attrs = { role: 'info', editType: 'calc+clearAxisTypes', description: [ - 'Sets the z coordinates of the vector field', - 'and of the displayed cones.' + 'Sets the z coordinates of the isosurface' ].join(' ') }, u: { valType: 'data_array', editType: 'calc', - description: 'Sets the x components of the vector field.' + description: 'Sets the intensity values of the isosurface.' }, - v: { - valType: 'data_array', + + imin: { + valType: 'number', editType: 'calc', - description: 'Sets the y components of the vector field.' + description: 'Sets the minimum iso bound of the isosurface.' }, - w: { - valType: 'data_array', + + imax: { + valType: 'number', editType: 'calc', - description: 'Sets the z components of the vector field.' + description: 'Sets the maximum iso bound of the isosurface.' }, - // TODO add way to specify cone positions independently of the vector field - // provided, similar to MATLAB's coneplot Cx/Cy/Cz meshgrids, - // see https://www.mathworks.com/help/matlab/ref/coneplot.html - // - // Alternatively, if our goal is only to 'fill in gaps' in the vector data, - // we could try to extend the heatmap 'connectgaps' algorithm to 3D. - // From AJ: this particular algorithm which amounts to a Poisson equation, - // both for interpolation and extrapolation - is the right one to use for - // cones too. It makes a field with zero divergence, which is a good - // baseline assumption for vector fields. - // - // cones: { - // // potential attributes to add: - // // - // // - meshmode: 'cartesian-product', 'pts', 'grid' - // // - // // under `meshmode: 'grid'` - // // - (x|y|z)grid.start - // // - (x|y|z)grid.end - // // - (x|y|z)grid.size - // - // x: { - // valType: 'data_array', - // editType: 'calc', - // description: 'Sets the x coordinates of the cones to be displayed.' - // }, - // y: { - // valType: 'data_array', - // editType: 'calc', - // description: 'Sets the y coordinates of the cones to be displayed.' - // }, - // z: { - // valType: 'data_array', - // editType: 'calc', - // description: 'Sets the z coordinates of the cones to be displayed.' - // }, - // - // editType: 'calc', - // description: [ - // 'By setting `cones.x`, `cones.y` and `cones.z` to 1D arrays,', - // 'plotly creates a mesh using the cartesian product of those 3 arrays.' - // ].join(' ') - // }, - - sizemode: { - valType: 'enumerated', - values: ['scaled', 'absolute'], - role: 'info', + smoothnormals: { + valType: 'boolean', editType: 'calc', - dflt: 'scaled', - description: [ - 'Determines whether `sizeref` is set as a *scaled* (i.e unitless) scalar', - '(normalized by the max u/v/w norm in the vector field) or as', - '*absolute* value (in the same units as the vector field).' - ].join(' ') + description: '' }, - sizeref: { - valType: 'number', - role: 'info', + + singlemesh: { + valType: 'boolean', editType: 'calc', - min: 0, - description: [ - 'Adjusts the cone size scaling.', - 'The size of the cones is determined by their u/v/w norm multiplied a factor and `sizeref`.', - 'This factor (computed internally) corresponds to the minimum "time" to travel across', - 'two successive x/y/z positions at the average velocity of those two successive positions.', - 'All cones in a given trace use the same factor.', - 'With `sizemode` set to *scaled*, `sizeref` is unitless, its default value is *0.5*', - 'With `sizemode` set to *absolute*, `sizeref` has the same units as the u/v/w vector field,', - 'its the default value is half the sample\'s maximum vector norm.' - ].join(' ') + description: '' }, - anchor: { - valType: 'enumerated', - role: 'info', + isocaps: { + valType: 'boolean', editType: 'calc', - values: ['tip', 'tail', 'cm', 'center'], - dflt: 'cm', - description: [ - 'Sets the cones\' anchor with respect to their x/y/z positions.', - 'Note that *cm* denote the cone\'s center of mass which corresponds to', - '1/4 from the tail to tip.' - ].join(' ') + description: '' + }, + + boundmin: { + valType: 'data_array', + editType: 'calc', + description: '' + }, + + boundmax: { + valType: 'data_array', + editType: 'calc', + description: '' }, text: { @@ -154,7 +97,7 @@ var attrs = { arrayOk: true, editType: 'calc', description: [ - 'Sets the text elements associated with the cones.', + 'Sets the text elements associated with the isosurface points.', 'If trace `hoverinfo` contains a *text* flag and *hovertext* is not set,', 'these elements will be seen in the hover labels.' ].join(' ') @@ -175,8 +118,8 @@ fromMesh3d.forEach(function(k) { attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, { editType: 'calc', - flags: ['x', 'y', 'z', 'u', 'v', 'w', 'norm', 'text', 'name'], - dflt: 'x+y+z+norm+text+name' + flags: ['x', 'y', 'z', 'intensity', 'text', 'name'], + dflt: 'x+y+z+intensity+text+name' }); module.exports = attrs; diff --git a/src/traces/isosurface/calc.js b/src/traces/isosurface/calc.js index 7a0f1e20982..4d90bbed482 100644 --- a/src/traces/isosurface/calc.js +++ b/src/traces/isosurface/calc.js @@ -12,17 +12,13 @@ var colorscaleCalc = require('../../components/colorscale/calc'); module.exports = function calc(gd, trace) { var u = trace.u; - var v = trace.v; - var w = trace.w; - var len = Math.min(u.length, v.length, w.length); + var len = u.length; var normMax = -Infinity; var normMin = Infinity; for(var i = 0; i < len; i++) { var uu = u[i]; - var vv = v[i]; - var ww = w[i]; - var norm = Math.sqrt(uu * uu + vv * vv + ww * ww); + var norm = uu; normMax = Math.max(normMax, norm); normMin = Math.min(normMin, norm); diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 1694b45c1bf..30f0013f69e 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -6,6 +6,62 @@ * LICENSE file in the root directory of this source tree. */ +/* + Usage example: + + var width = 64 + var height = 64 + var depth = 64 + + var xs = [] + var ys = [] + var zs = [] + + var data = new Uint16Array(width*height*depth) + for (var z=0; z Date: Sat, 23 Jun 2018 16:19:08 +0800 Subject: [PATCH 03/16] fix isosurface meshgrid construction --- src/traces/isosurface/convert.js | 40 +++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 30f0013f69e..dfd77413c40 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -110,6 +110,22 @@ function zip3(x, y, z) { var axisName2scaleIndex = {xaxis: 0, yaxis: 1, zaxis: 2}; +function getSequence(src) { + var xs = [src[0]]; + for(var i = 1, last = xs[0]; i < src.length; i++) { + var p = src[i]; + if(p >= last) { + if(p > last) { + xs.push(p); + } + last = p; + } else { + break; + } + } + return xs; +} + function convert(scene, trace) { var sceneLayout = scene.fullSceneLayout; var dataScale = scene.dataScale; @@ -121,27 +137,9 @@ function convert(scene, trace) { return simpleMap(arr, function(v) { return ax.d2l(v) * scale; }); } - var points = zip3( - toDataCoords(trace.x, 'xaxis'), - toDataCoords(trace.y, 'yaxis'), - toDataCoords(trace.z, 'zaxis') - ); - var xs = [points[0][0]]; - var ys = [points[0][1]]; - var zs = [points[0][2]]; - - for(var i = 1; i < points.length; i++) { - var p = points[i]; - if(xs[xs.length - 1] < p[0]) { - xs.push(p[0]); - } - if(ys[ys.length - 1] < p[1]) { - ys.push(p[1]); - } - if(zs[zs.length - 1] < p[2]) { - zs.push(p[2]); - } - } + var xs = getSequence(trace.x); + var ys = getSequence(trace.y); + var zs = getSequence(trace.z); isosurfaceOpts.dimensions = [xs.length, ys.length, zs.length]; isosurfaceOpts.meshgrid = [ From 6b2dbaca9c63985c2918063ca2a284e44cd75396 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Mon, 25 Jun 2018 10:39:48 +0800 Subject: [PATCH 04/16] fix lint errors --- src/traces/isosurface/convert.js | 8 -------- src/traces/isosurface/defaults.js | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index dfd77413c40..7bcca23f286 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -100,14 +100,6 @@ proto.handlePick = function(selection) { } }; -function zip3(x, y, z) { - var result = new Array(x.length); - for(var i = 0; i < x.length; i++) { - result[i] = [x[i], y[i], z[i]]; - } - return result; -} - var axisName2scaleIndex = {xaxis: 0, yaxis: 1, zaxis: 2}; function getSequence(src) { diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js index 309b8fb6558..8396a64c2f8 100644 --- a/src/traces/isosurface/defaults.js +++ b/src/traces/isosurface/defaults.js @@ -26,7 +26,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout var z = coerce('z'); if( - !u || !u.length || + !u || !u.length || !x || !x.length || !y || !y.length || !z || !z.length ) { traceOut.visible = false; From 6b87ed7f311ca23f4d05ec055618931874b968b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 10 Jul 2018 14:08:15 -0400 Subject: [PATCH 05/16] add gl-isosurface3d to package-lock --- package-lock.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/package-lock.json b/package-lock.json index ed8e620daca..cedbaf5daf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4963,6 +4963,25 @@ } } }, + "gl-isosurface3d": { + "version": "git+https://github.com/gl-vis/gl-isosurface3d.git#b4a79af9986263bd2bf1a70cc6096e711d2365ee", + "requires": { + "barycentric": "1.0.1", + "colormap": "2.3.0", + "gl-buffer": "2.1.2", + "gl-mat4": "1.2.0", + "gl-shader": "4.2.1", + "gl-texture2d": "2.1.0", + "gl-vao": "1.3.0", + "glsl-specular-cook-torrance": "2.0.1", + "glslify": "6.1.1", + "ndarray": "1.0.18", + "normals": "1.1.0", + "polytope-closest-point": "1.0.0", + "simplicial-complex-contour": "1.0.2", + "typedarray-pool": "1.1.0" + } + }, "gl-line3d": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/gl-line3d/-/gl-line3d-1.1.2.tgz", From 1c4ec62e9026b950be97c94ba82251a2cab4716b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 10 Jul 2018 14:58:00 -0400 Subject: [PATCH 06/16] fixup post merge-master --- src/traces/isosurface/attributes.js | 16 ++++++++-------- src/traces/isosurface/calc.js | 20 +++++++++----------- src/traces/isosurface/convert.js | 10 +++++----- src/traces/isosurface/defaults.js | 8 ++++---- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index 988483f3f8b..c8784dc3343 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -8,7 +8,6 @@ 'use strict'; -var colorAttrs = require('../../components/colorscale/color_attributes'); var colorscaleAttrs = require('../../components/colorscale/attributes'); var colorbarAttrs = require('../../components/colorbar/attributes'); var mesh3dAttrs = require('../mesh3d/attributes'); @@ -42,19 +41,19 @@ var attrs = { ].join(' ') }, - u: { + value: { valType: 'data_array', editType: 'calc', description: 'Sets the intensity values of the isosurface.' }, - imin: { + isomin: { valType: 'number', editType: 'calc', description: 'Sets the minimum iso bound of the isosurface.' }, - imax: { + isomax: { valType: 'number', editType: 'calc', description: 'Sets the maximum iso bound of the isosurface.' @@ -104,14 +103,15 @@ var attrs = { } }; -extendFlat(attrs, colorAttrs('', 'calc', true), { - showscale: colorscaleAttrs.showscale, +extendFlat(attrs, colorscaleAttrs('', { + colorAttr: 'value', + showScaleDflt: true, + editTypeOverride: 'calc' +}), { colorbar: colorbarAttrs }); -delete attrs.color; var fromMesh3d = ['opacity', 'lightposition', 'lighting']; - fromMesh3d.forEach(function(k) { attrs[k] = mesh3dAttrs[k]; }); diff --git a/src/traces/isosurface/calc.js b/src/traces/isosurface/calc.js index 4d90bbed482..3a238a5064a 100644 --- a/src/traces/isosurface/calc.js +++ b/src/traces/isosurface/calc.js @@ -11,20 +11,18 @@ var colorscaleCalc = require('../../components/colorscale/calc'); module.exports = function calc(gd, trace) { - var u = trace.u; - var len = u.length; - var normMax = -Infinity; - var normMin = Infinity; + var value = trace.value; + var len = value.length; + var vMax = -Infinity; + var vMin = Infinity; for(var i = 0; i < len; i++) { - var uu = u[i]; - var norm = uu; - - normMax = Math.max(normMax, norm); - normMin = Math.min(normMin, norm); + var v = value[i]; + vMax = Math.max(vMax, v); + vMin = Math.min(vMin, v); } - trace._normMax = normMax; + trace._vMax = vMax; - colorscaleCalc(trace, [normMin, normMax], '', 'c'); + colorscaleCalc(trace, [vMin, vMax], '', 'c'); }; diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 7bcca23f286..af7904fa1c0 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -39,10 +39,10 @@ y: ys, z: zs, - u: data, + value: data, - imin: 1600, - imax: 2000, + isomin: 1600, + isomax: 2000, cmin: 1500, cmax: 2000, @@ -146,12 +146,12 @@ function convert(scene, trace) { // ]; - isosurfaceOpts.values = trace.u; + isosurfaceOpts.values = trace.value; isosurfaceOpts.colormap = parseColorScale(trace.colorscale); // isosurfaceOpts.capsColormap = parseColorScale(trace.capscolorscale); isosurfaceOpts.vertexIntensityBounds = [trace.cmin, trace.cmax]; - isosurfaceOpts.isoBounds = [trace.imin, trace.imax]; + isosurfaceOpts.isoBounds = [trace.isomin, trace.isomax]; isosurfaceOpts.isoCaps = trace.isocaps; isosurfaceOpts.singleMesh = trace.singlemesh === undefined ? true : trace.singlemesh; diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js index 8396a64c2f8..46b9413a81b 100644 --- a/src/traces/isosurface/defaults.js +++ b/src/traces/isosurface/defaults.js @@ -19,22 +19,22 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); } - var u = coerce('u'); + var value = coerce('value'); var x = coerce('x'); var y = coerce('y'); var z = coerce('z'); if( - !u || !u.length || + !value || !value.length || !x || !x.length || !y || !y.length || !z || !z.length ) { traceOut.visible = false; return; } - coerce('imin'); - coerce('imax'); + coerce('isomin'); + coerce('isomax'); coerce('smoothnormals'); coerce('isocaps'); // coerce('singlemesh'); From d417e6e43113b506794b4e5c6acd28f2061b3180 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Sun, 12 Aug 2018 15:26:24 +0800 Subject: [PATCH 07/16] isosurface trace [xyz](min|max) bounds --- src/traces/isosurface/attributes.js | 46 +++++++++++++++++++------ src/traces/isosurface/convert.js | 52 +++++++++++++++++++++++++---- src/traces/isosurface/defaults.js | 8 +++++ 3 files changed, 89 insertions(+), 17 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index c8784dc3343..84deba5e08d 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -59,32 +59,56 @@ var attrs = { description: 'Sets the maximum iso bound of the isosurface.' }, - smoothnormals: { - valType: 'boolean', + xmin: { + valType: 'number', editType: 'calc', - description: '' + description: 'Sets the minimum x bound of the isosurface.' }, - singlemesh: { - valType: 'boolean', + xmax: { + valType: 'number', editType: 'calc', - description: '' + description: 'Sets the maximum x bound of the isosurface.' }, - isocaps: { + ymin: { + valType: 'number', + editType: 'calc', + description: 'Sets the minimum y bound of the isosurface.' + }, + + ymax: { + valType: 'number', + editType: 'calc', + description: 'Sets the maximum y bound of the isosurface.' + }, + + zmin: { + valType: 'number', + editType: 'calc', + description: 'Sets the minimum z bound of the isosurface.' + }, + + zmax: { + valType: 'number', + editType: 'calc', + description: 'Sets the maximum z bound of the isosurface.' + }, + + smoothnormals: { valType: 'boolean', editType: 'calc', description: '' }, - boundmin: { - valType: 'data_array', + singlemesh: { + valType: 'boolean', editType: 'calc', description: '' }, - boundmax: { - valType: 'data_array', + isocaps: { + valType: 'boolean', editType: 'calc', description: '' }, diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index af7904fa1c0..9d6a39827d4 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -118,6 +118,32 @@ function getSequence(src) { return xs; } +// This should find the bounding box min +// edge index so that `value` lies at the edge or outside +// the range starting from xs[edge index]. +// That is, xs[edge index] >= value. +function findMinIndex(xs, value) { + for(var i = 0; i < xs.length; i++) { + if(xs[i] >= value) { + return i; + } + } + return xs.length; +} + +// This should find the bounding box max +// edge index so that `value` lies at the edge or outside +// the range ending at xs[edge index]. +// That is, xs[edge index] <= value. +function findMaxIndex(xs, value) { + for(var i = xs.length-1; i >= 0; i--) { + if(xs[i] <= value) { + return i; + } + } + return -1; +} + function convert(scene, trace) { var sceneLayout = scene.fullSceneLayout; var dataScale = scene.dataScale; @@ -140,11 +166,6 @@ function convert(scene, trace) { toDataCoords(zs, 'zaxis') ]; - // var bounds = [ - // isosurfaceOpts.boundmin || [xs[0], ys[0], zs[0]], - // isosurfaceOpts.boundmax || [xs[xs.length - 1], ys[ys.length - 1], zs[zs.length - 1]] - // ]; - isosurfaceOpts.values = trace.value; @@ -156,7 +177,26 @@ function convert(scene, trace) { isosurfaceOpts.isoCaps = trace.isocaps; isosurfaceOpts.singleMesh = trace.singlemesh === undefined ? true : trace.singlemesh; - var bounds = [[0, 0, 0], isosurfaceOpts.dimensions]; + var bounds = [[0, 0, 0], isosurfaceOpts.dimensions.slice()]; + + if(trace.xmin !== undefined) { + bounds[0][0] = findMinIndex(xs, trace.xmin); + } + if(trace.ymin !== undefined) { + bounds[0][1] = findMinIndex(ys, trace.ymin); + } + if(trace.zmin !== undefined) { + bounds[0][2] = findMinIndex(zs, trace.zmin); + } + if(trace.xmax !== undefined) { + bounds[1][0] = findMaxIndex(xs, trace.xmax); + } + if(trace.ymax !== undefined) { + bounds[1][1] = findMaxIndex(ys, trace.ymax); + } + if(trace.zmax !== undefined) { + bounds[1][2] = findMaxIndex(zs, trace.zmax); + } var meshData = isosurfacePlot(isosurfaceOpts, bounds); diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js index 46b9413a81b..8bf6636a281 100644 --- a/src/traces/isosurface/defaults.js +++ b/src/traces/isosurface/defaults.js @@ -39,6 +39,14 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('isocaps'); // coerce('singlemesh'); + coerce('xmin'); + coerce('ymin'); + coerce('zmin'); + + coerce('xmax'); + coerce('ymax'); + coerce('zmax'); + coerce('lighting.ambient'); coerce('lighting.diffuse'); coerce('lighting.specular'); From 88cad8352b9f8f06301ceb565068b407455cb7da Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Sun, 12 Aug 2018 15:34:25 +0800 Subject: [PATCH 08/16] add npm gl-isosurface to package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f5c295cc6a9..a7c3137e614 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", "font-atlas-sdf": "^1.3.3", - "gl-isosurface3d": "https://github.com/gl-vis/gl-isosurface3d.git", + "gl-isosurface3d": "^0.5.0", "gl-cone3d": "^1.1.0", "gl-contour2d": "^1.1.4", "gl-error3d": "^1.0.7", From c3df068d5f42c30e75d67a554bc70942463156bf Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Fri, 24 Aug 2018 19:17:22 +0800 Subject: [PATCH 09/16] isosurface hovertext hack in spirit of src/plots/gl3d/scene.js:91 --- src/traces/isosurface/attributes.js | 5 +++-- src/traces/isosurface/convert.js | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index 84deba5e08d..206bec46823 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -43,6 +43,7 @@ var attrs = { value: { valType: 'data_array', + role: 'info', editType: 'calc', description: 'Sets the intensity values of the isosurface.' }, @@ -142,8 +143,8 @@ fromMesh3d.forEach(function(k) { attrs.hoverinfo = extendFlat({}, baseAttrs.hoverinfo, { editType: 'calc', - flags: ['x', 'y', 'z', 'intensity', 'text', 'name'], - dflt: 'x+y+z+intensity+text+name' + flags: ['x', 'y', 'z', 'value', 'text', 'name'], + dflt: 'x+y+z+value+text+name' }); module.exports = attrs; diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 9d6a39827d4..7f2fff4b6c7 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -90,10 +90,12 @@ proto.handlePick = function(selection) { ]; var text = this.data.text; + selection.textLabel = "value: " + selection.data.intensity.toPrecision(3); + if(Array.isArray(text) && text[selectIndex] !== undefined) { - selection.textLabel = text[selectIndex]; + selection.textLabel = "
" + text[selectIndex]; } else if(text) { - selection.textLabel = text; + selection.textLabel = "
" + text; } return true; From f7eb9514ff49fa89b619757631aa9fcf60711183 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Fri, 24 Aug 2018 21:22:34 +0800 Subject: [PATCH 10/16] Compute bounds for isosurface --- src/traces/isosurface/calc.js | 31 +++++++++++++++++++++++++++++++ src/traces/isosurface/convert.js | 28 +++++++++++++++++++--------- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/traces/isosurface/calc.js b/src/traces/isosurface/calc.js index 3a238a5064a..3f720489952 100644 --- a/src/traces/isosurface/calc.js +++ b/src/traces/isosurface/calc.js @@ -25,4 +25,35 @@ module.exports = function calc(gd, trace) { trace._vMax = vMax; colorscaleCalc(trace, [vMin, vMax], '', 'c'); + + var x = trace.x; + var y = trace.y; + var z = trace.z; + + var xMax = -Infinity; + var xMin = Infinity; + var yMax = -Infinity; + var yMin = Infinity; + var zMax = -Infinity; + var zMin = Infinity; + + for(i = 0; i < len; i++) { + var xx = x[i]; + xMax = Math.max(xMax, xx); + xMin = Math.min(xMin, xx); + + var yy = y[i]; + yMax = Math.max(yMax, yy); + yMin = Math.min(yMin, yy); + + var zz = z[i]; + zMax = Math.max(zMax, zz); + zMin = Math.min(zMin, zz); + } + + trace._xbnds = [xMin, xMax]; + trace._ybnds = [yMin, yMax]; + trace._zbnds = [zMin, zMax]; + + console.log(trace); }; diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 7f2fff4b6c7..91010efb0e8 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -146,26 +146,28 @@ function findMaxIndex(xs, value) { return -1; } +function toDataCoords(scene, arr, axisName) { + var sceneLayout = scene.fullSceneLayout; + var dataScale = scene.dataScale; + var ax = sceneLayout[axisName]; + var scale = dataScale[axisName2scaleIndex[axisName]]; + return simpleMap(arr, function(v) { return ax.d2l(v) * scale; }); +} + function convert(scene, trace) { var sceneLayout = scene.fullSceneLayout; var dataScale = scene.dataScale; var isosurfaceOpts = {}; - function toDataCoords(arr, axisName) { - var ax = sceneLayout[axisName]; - var scale = dataScale[axisName2scaleIndex[axisName]]; - return simpleMap(arr, function(v) { return ax.d2l(v) * scale; }); - } - var xs = getSequence(trace.x); var ys = getSequence(trace.y); var zs = getSequence(trace.z); isosurfaceOpts.dimensions = [xs.length, ys.length, zs.length]; isosurfaceOpts.meshgrid = [ - toDataCoords(xs, 'xaxis'), - toDataCoords(ys, 'yaxis'), - toDataCoords(zs, 'zaxis') + toDataCoords(scene, xs, 'xaxis'), + toDataCoords(scene, ys, 'yaxis'), + toDataCoords(scene, zs, 'zaxis') ]; @@ -232,6 +234,14 @@ function createIsosurfaceTrace(scene, data) { var meshData = convert(scene, data); var mesh = isosurfacePlot.createTriMesh(gl, meshData); + var trace = data; + var xbnds = toDataCoords(scene, trace._xbnds, 'xaxis'); + var ybnds = toDataCoords(scene, trace._ybnds, 'yaxis'); + var zbnds = toDataCoords(scene, trace._zbnds, 'zaxis'); + mesh.bounds = [ + [xbnds[0], ybnds[0], zbnds[0]], + [xbnds[1], ybnds[1], zbnds[1]], + ]; var isosurface = new Isosurface(scene, data.uid); isosurface.mesh = mesh; From 604a2d90ee0ebc23350dd466729ccab3b918b773 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Mon, 27 Aug 2018 16:00:01 +0800 Subject: [PATCH 11/16] update example to implicit bounds, 2x size --- src/traces/isosurface/convert.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 91010efb0e8..d463a518c03 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -21,9 +21,9 @@ for (var z=0; z Date: Mon, 10 Sep 2018 12:19:39 +0800 Subject: [PATCH 12/16] Isosurface attributes add roles, tweak descriptions --- src/traces/isosurface/attributes.js | 32 ++++++++++++++++------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index 206bec46823..073cc91822c 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -21,7 +21,7 @@ var attrs = { role: 'info', editType: 'calc+clearAxisTypes', description: [ - 'Sets the x coordinates of the isosurface' + 'Sets the x coordinates of the volume data' ].join(' ') }, y: { @@ -29,7 +29,7 @@ var attrs = { role: 'info', editType: 'calc+clearAxisTypes', description: [ - 'Sets the y coordinates of the isosurface' + 'Sets the y coordinates of the volume data' ].join(' ') }, z: { @@ -37,7 +37,7 @@ var attrs = { role: 'info', editType: 'calc+clearAxisTypes', description: [ - 'Sets the z coordinates of the isosurface' + 'Sets the z coordinates of the volume data' ].join(' ') }, @@ -45,73 +45,77 @@ var attrs = { valType: 'data_array', role: 'info', editType: 'calc', - description: 'Sets the intensity values of the isosurface.' + description: 'Sets the intensity values of the volume data.' }, isomin: { valType: 'number', + role: 'info', editType: 'calc', - description: 'Sets the minimum iso bound of the isosurface.' + description: 'Sets the minimum intensity bound of the isosurface.' }, isomax: { valType: 'number', + role: 'info', editType: 'calc', - description: 'Sets the maximum iso bound of the isosurface.' + description: 'Sets the maximum intensity bound of the isosurface.' }, xmin: { valType: 'number', + role: 'info', editType: 'calc', description: 'Sets the minimum x bound of the isosurface.' }, xmax: { valType: 'number', + role: 'info', editType: 'calc', description: 'Sets the maximum x bound of the isosurface.' }, ymin: { valType: 'number', + role: 'info', editType: 'calc', description: 'Sets the minimum y bound of the isosurface.' }, ymax: { valType: 'number', + role: 'info', editType: 'calc', description: 'Sets the maximum y bound of the isosurface.' }, zmin: { valType: 'number', + role: 'info', editType: 'calc', description: 'Sets the minimum z bound of the isosurface.' }, zmax: { valType: 'number', + role: 'info', editType: 'calc', description: 'Sets the maximum z bound of the isosurface.' }, smoothnormals: { valType: 'boolean', + role: 'info', editType: 'calc', - description: '' - }, - - singlemesh: { - valType: 'boolean', - editType: 'calc', - description: '' + description: 'Smooth normals of the isosurface (default: true)' }, isocaps: { valType: 'boolean', + role: 'info', editType: 'calc', - description: '' + description: 'Whether to generate isocaps for the isosurface (default: true)' }, text: { From eb5221df102a7aeeeded648b9af15f1b20ec0a16 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Mon, 10 Sep 2018 12:29:33 +0800 Subject: [PATCH 13/16] isosurface eslint fixes --- src/traces/isosurface/calc.js | 3 +-- src/traces/isosurface/convert.js | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/traces/isosurface/calc.js b/src/traces/isosurface/calc.js index 3f720489952..73c2c86afc9 100644 --- a/src/traces/isosurface/calc.js +++ b/src/traces/isosurface/calc.js @@ -37,7 +37,7 @@ module.exports = function calc(gd, trace) { var zMax = -Infinity; var zMin = Infinity; - for(i = 0; i < len; i++) { + for(var i = 0; i < len; i++) { var xx = x[i]; xMax = Math.max(xMax, xx); xMin = Math.min(xMin, xx); @@ -55,5 +55,4 @@ module.exports = function calc(gd, trace) { trace._ybnds = [yMin, yMax]; trace._zbnds = [zMin, zMax]; - console.log(trace); }; diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index d463a518c03..2b60305031e 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -83,12 +83,12 @@ proto.handlePick = function(selection) { ]; var text = this.data.text; - selection.textLabel = "value: " + selection.data.intensity.toPrecision(3); + selection.textLabel = 'value: ' + selection.data.intensity.toPrecision(3); if(Array.isArray(text) && text[selectIndex] !== undefined) { - selection.textLabel = "
" + text[selectIndex]; + selection.textLabel = '
' + text[selectIndex]; } else if(text) { - selection.textLabel = "
" + text; + selection.textLabel = '
' + text; } return true; @@ -131,7 +131,7 @@ function findMinIndex(xs, value) { // the range ending at xs[edge index]. // That is, xs[edge index] <= value. function findMaxIndex(xs, value) { - for(var i = xs.length-1; i >= 0; i--) { + for(var i = xs.length - 1; i >= 0; i--) { if(xs[i] <= value) { return i; } @@ -148,8 +148,6 @@ function toDataCoords(scene, arr, axisName) { } function convert(scene, trace) { - var sceneLayout = scene.fullSceneLayout; - var dataScale = scene.dataScale; var isosurfaceOpts = {}; var xs = getSequence(trace.x); From e75e9d77e8b8631e486469c186b17cf8b76f0aed Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Mon, 10 Sep 2018 13:16:37 +0800 Subject: [PATCH 14/16] isosurface single-color surface --- src/traces/isosurface/attributes.js | 15 ++++++++++++-- src/traces/isosurface/convert.js | 32 +++++++++++++++++++++++------ src/traces/isosurface/defaults.js | 3 ++- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index 073cc91822c..f9faca39c3e 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -108,14 +108,25 @@ var attrs = { valType: 'boolean', role: 'info', editType: 'calc', - description: 'Smooth normals of the isosurface (default: true)' + description: 'Smooth normals of the isosurface. By default this is set to true.' }, isocaps: { valType: 'boolean', role: 'info', editType: 'calc', - description: 'Whether to generate isocaps for the isosurface (default: true)' + description: 'Whether to generate isocaps for the isosurface. By default this is set to true.' + }, + + color: { + valType: 'color', + role: 'style', + editType: 'calc', + description: [ + 'Sets the color of the isosurface.', + 'By default the isosurface color is computed from the colorscale.', + 'Isocaps still use the colorscale colors even with this set.' + ].join(" ") }, text: { diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 2b60305031e..39acd23dee2 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -46,11 +46,9 @@ cmin: 1500, cmax: 2000, - smoothnormals: true, + smoothnormals: true, isocaps: true, - singlemesh: true, - colorscale: 'Portland' }]) @@ -61,6 +59,7 @@ var isosurfacePlot = require('gl-isosurface3d'); var simpleMap = require('../../lib').simpleMap; var parseColorScale = require('../../lib/gl_format_color').parseColorScale; +var str2RgbaArray = require('../../lib/str2rgbarray'); function Isosurface(scene, uid) { this.scene = scene; @@ -164,13 +163,24 @@ function convert(scene, trace) { isosurfaceOpts.values = trace.value; - isosurfaceOpts.colormap = parseColorScale(trace.colorscale); - // isosurfaceOpts.capsColormap = parseColorScale(trace.capscolorscale); + if (trace.colorscale) { + isosurfaceOpts.colormap = parseColorScale(trace.colorscale); + } + if (trace.color) { + isosurfaceOpts.capsColormap = isosurfaceOpts.colormap; + var color = str2RgbaArray(trace.color).map(function(c) { return c * 255; }); + isosurfaceOpts.colormap = [{index: 0, rgb: color}, {index: 1, rgb: color}]; + if (!isosurfaceOpts.capsColormap) { + isosurfaceOpts.capsColormap = isosurfaceOpts.colormap; + } + } isosurfaceOpts.vertexIntensityBounds = [trace.cmin, trace.cmax]; isosurfaceOpts.isoBounds = [trace.isomin, trace.isomax]; isosurfaceOpts.isoCaps = trace.isocaps; - isosurfaceOpts.singleMesh = trace.singlemesh === undefined ? true : trace.singlemesh; + isosurfaceOpts.singleMesh = false; //trace.singlemesh === undefined ? true : trace.singlemesh; + + isosurfaceOpts.smoothNormals = trace.smoothnormals === undefined ? true : trace.smoothnormals; var bounds = [[0, 0, 0], isosurfaceOpts.dimensions.slice()]; @@ -225,6 +235,7 @@ function createIsosurfaceTrace(scene, data) { var meshData = convert(scene, data); var mesh = isosurfacePlot.createTriMesh(gl, meshData); + var capMesh = isosurfacePlot.createTriMesh(gl, meshData.caps); var trace = data; var xbnds = toDataCoords(scene, trace._xbnds, 'xaxis'); var ybnds = toDataCoords(scene, trace._ybnds, 'yaxis'); @@ -240,7 +251,16 @@ function createIsosurfaceTrace(scene, data) { isosurface.meshData = meshData; mesh._trace = isosurface; + var caps = new Isosurface(scene, data.uid); + caps.mesh = capMesh; + caps.data = data; + caps.meshData = meshData; + capMesh._trace = caps; + + isosurface.caps = caps; + scene.glplot.add(mesh); + scene.glplot.add(capMesh); return isosurface; } diff --git a/src/traces/isosurface/defaults.js b/src/traces/isosurface/defaults.js index 8bf6636a281..7c0112f78b0 100644 --- a/src/traces/isosurface/defaults.js +++ b/src/traces/isosurface/defaults.js @@ -33,11 +33,12 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout return; } + coerce('color'); + coerce('isomin'); coerce('isomax'); coerce('smoothnormals'); coerce('isocaps'); - // coerce('singlemesh'); coerce('xmin'); coerce('ymin'); From 2ee5f602d668da046dca5ad48789866a1986e961 Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Thu, 13 Sep 2018 16:53:02 +0800 Subject: [PATCH 15/16] isosurface lint fixes --- src/traces/isosurface/attributes.js | 2 +- src/traces/isosurface/calc.js | 5 +++-- src/traces/isosurface/convert.js | 11 ++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/traces/isosurface/attributes.js b/src/traces/isosurface/attributes.js index f9faca39c3e..b8460bd4dc2 100644 --- a/src/traces/isosurface/attributes.js +++ b/src/traces/isosurface/attributes.js @@ -126,7 +126,7 @@ var attrs = { 'Sets the color of the isosurface.', 'By default the isosurface color is computed from the colorscale.', 'Isocaps still use the colorscale colors even with this set.' - ].join(" ") + ].join(' ') }, text: { diff --git a/src/traces/isosurface/calc.js b/src/traces/isosurface/calc.js index 73c2c86afc9..4ad31d4866a 100644 --- a/src/traces/isosurface/calc.js +++ b/src/traces/isosurface/calc.js @@ -15,8 +15,9 @@ module.exports = function calc(gd, trace) { var len = value.length; var vMax = -Infinity; var vMin = Infinity; + var i = 0; - for(var i = 0; i < len; i++) { + for(i = 0; i < len; i++) { var v = value[i]; vMax = Math.max(vMax, v); vMin = Math.min(vMin, v); @@ -37,7 +38,7 @@ module.exports = function calc(gd, trace) { var zMax = -Infinity; var zMin = Infinity; - for(var i = 0; i < len; i++) { + for(i = 0; i < len; i++) { var xx = x[i]; xMax = Math.max(xMax, xx); xMin = Math.min(xMin, xx); diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index 39acd23dee2..cfd26cafbbe 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -49,7 +49,8 @@ smoothnormals: true, isocaps: true, - colorscale: 'Portland' + colorscale: 'Portland', + color: 'grey' }]) */ @@ -163,14 +164,14 @@ function convert(scene, trace) { isosurfaceOpts.values = trace.value; - if (trace.colorscale) { + if (trace.colorscale){ isosurfaceOpts.colormap = parseColorScale(trace.colorscale); } - if (trace.color) { + if (trace.color){ isosurfaceOpts.capsColormap = isosurfaceOpts.colormap; var color = str2RgbaArray(trace.color).map(function(c) { return c * 255; }); isosurfaceOpts.colormap = [{index: 0, rgb: color}, {index: 1, rgb: color}]; - if (!isosurfaceOpts.capsColormap) { + if (!isosurfaceOpts.capsColormap){ isosurfaceOpts.capsColormap = isosurfaceOpts.colormap; } } @@ -178,7 +179,7 @@ function convert(scene, trace) { isosurfaceOpts.isoBounds = [trace.isomin, trace.isomax]; isosurfaceOpts.isoCaps = trace.isocaps; - isosurfaceOpts.singleMesh = false; //trace.singlemesh === undefined ? true : trace.singlemesh; + isosurfaceOpts.singleMesh = false; isosurfaceOpts.smoothNormals = trace.smoothnormals === undefined ? true : trace.smoothnormals; From c884c89e1d69b6def34a74014c7c78736817c54d Mon Sep 17 00:00:00 2001 From: Ilmari Heikkinen Date: Thu, 13 Sep 2018 16:59:53 +0800 Subject: [PATCH 16/16] isosurface lint fixes 2/2 --- src/traces/isosurface/convert.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/traces/isosurface/convert.js b/src/traces/isosurface/convert.js index cfd26cafbbe..50b34d4e454 100644 --- a/src/traces/isosurface/convert.js +++ b/src/traces/isosurface/convert.js @@ -164,14 +164,14 @@ function convert(scene, trace) { isosurfaceOpts.values = trace.value; - if (trace.colorscale){ + if(trace.colorscale) { isosurfaceOpts.colormap = parseColorScale(trace.colorscale); } - if (trace.color){ + if(trace.color) { isosurfaceOpts.capsColormap = isosurfaceOpts.colormap; var color = str2RgbaArray(trace.color).map(function(c) { return c * 255; }); isosurfaceOpts.colormap = [{index: 0, rgb: color}, {index: 1, rgb: color}]; - if (!isosurfaceOpts.capsColormap){ + if(!isosurfaceOpts.capsColormap) { isosurfaceOpts.capsColormap = isosurfaceOpts.colormap; } }