Skip to content

Commit e99ffc9

Browse files
committed
expect x/y/z and u/v/w to have matching length + add tube bounds pad
- which makes x/y/z and u/v/w streamtube data interchangeable with cone traces - convert x/y/z columns to gl-streamtube "meshgrid" using Lib.distinctVals - add pad around tube x/y/z bounds to allow them to go a little bit beyond the mesh w/o getting clipped.
1 parent b0cd99d commit e99ffc9

11 files changed

+135672
-59
lines changed

Diff for: src/traces/streamtube/calc.js

+15-17
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@ module.exports = function calc(gd, trace) {
1616
var u = trace.u;
1717
var v = trace.v;
1818
var w = trace.w;
19-
var vlen = Math.min(u.length, v.length, w.length);
20-
var normMax = -Infinity;
19+
var x = trace.x;
20+
var y = trace.y;
21+
var z = trace.z;
22+
var len = Math.min(x.length, y.length, z.length, u.length, v.length, w.length);
23+
24+
var startx = trace.startx;
25+
var starty = trace.starty;
26+
var startz = trace.startz;
27+
var slen = Math.min(startx.length, starty.length, startz.length);
28+
29+
var normMax = 0;
2130
var normMin = Infinity;
2231

23-
for(i = 0; i < vlen; i++) {
32+
for(i = 0; i < len; i++) {
2433
var uu = u[i];
2534
var vv = v[i];
2635
var ww = w[i];
@@ -30,8 +39,6 @@ module.exports = function calc(gd, trace) {
3039
normMin = Math.min(normMin, norm);
3140
}
3241

33-
trace._normMax = normMax;
34-
3542
colorscaleCalc(trace, [normMin, normMax], '', 'c');
3643

3744
var xMax = -Infinity;
@@ -41,12 +48,7 @@ module.exports = function calc(gd, trace) {
4148
var zMax = -Infinity;
4249
var zMin = Infinity;
4350

44-
var x = trace.x;
45-
var y = trace.y;
46-
var z = trace.z;
47-
var plen = Math.min(x.length, y.length, z.length);
48-
49-
for(i = 0; i < plen; i++) {
51+
for(i = 0; i < len; i++) {
5052
var xx = x[i];
5153
xMax = Math.max(xMax, xx);
5254
xMin = Math.min(xMin, xx);
@@ -59,12 +61,6 @@ module.exports = function calc(gd, trace) {
5961
zMax = Math.max(zMax, zz);
6062
zMin = Math.min(zMin, zz);
6163
}
62-
63-
var startx = trace.startx;
64-
var starty = trace.starty;
65-
var startz = trace.startz;
66-
var slen = Math.min(startx.length, starty.length, startz.length);
67-
6864
for(i = 0; i < slen; i++) {
6965
var sx = startx[i];
7066
xMax = Math.max(xMax, sx);
@@ -79,6 +75,8 @@ module.exports = function calc(gd, trace) {
7975
zMin = Math.min(zMin, sz);
8076
}
8177

78+
trace._len = len;
79+
trace._normMax = normMax;
8280
trace._xbnds = [xMin, xMax];
8381
trace._ybnds = [yMin, yMax];
8482
trace._zbnds = [zMin, zMax];

Diff for: src/traces/streamtube/convert.js

+54-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
var tube2mesh = require('gl-streamtube3d');
1212
var createTubeMesh = tube2mesh.createTubeMesh;
1313

14-
var simpleMap = require('../../lib').simpleMap;
14+
var Lib = require('../../lib');
1515
var parseColorScale = require('../../lib/gl_format_color').parseColorScale;
1616
var zip3 = require('../../lib/zip3');
1717

@@ -47,33 +47,54 @@ proto.handlePick = function(selection) {
4747

4848
var axisName2scaleIndex = {xaxis: 0, yaxis: 1, zaxis: 2};
4949

50+
function distinctVals(col) {
51+
return Lib.distinctVals(col).vals;
52+
}
53+
54+
function getBoundPads(vec) {
55+
var len = vec.length;
56+
if(len === 1) {
57+
return [0.5, 0.5];
58+
} else {
59+
return [vec[1] - vec[0], vec[len - 1] - vec[len - 2]];
60+
}
61+
}
62+
5063
function convert(scene, trace) {
5164
var sceneLayout = scene.fullSceneLayout;
5265
var dataScale = scene.dataScale;
66+
var len = trace._len;
5367
var tubeOpts = {};
5468

5569
function toDataCoords(arr, axisName) {
5670
var ax = sceneLayout[axisName];
5771
var scale = dataScale[axisName2scaleIndex[axisName]];
58-
return simpleMap(arr, function(v) { return ax.d2l(v) * scale; });
72+
return Lib.simpleMap(arr, function(v) { return ax.d2l(v) * scale; });
5973
}
6074

61-
tubeOpts.vectors = zip3(
62-
toDataCoords(trace.u, 'xaxis'),
63-
toDataCoords(trace.v, 'yaxis'),
64-
toDataCoords(trace.w, 'zaxis')
65-
);
75+
var u = toDataCoords(trace.u.slice(0, len), 'xaxis');
76+
var v = toDataCoords(trace.v.slice(0, len), 'yaxis');
77+
var w = toDataCoords(trace.w.slice(0, len), 'zaxis');
6678

67-
// TODO make this optional?
68-
// N.B. this is a "meshgrid" but shouldn't this be the position
69-
// of the vector field ???
70-
tubeOpts.meshgrid = [
71-
toDataCoords(trace.x, 'xaxis'),
72-
toDataCoords(trace.y, 'yaxis'),
73-
toDataCoords(trace.z, 'zaxis')
74-
];
79+
tubeOpts.vectors = zip3(u, v, w);
80+
81+
var valsx = distinctVals(trace.x.slice(0, len));
82+
var valsy = distinctVals(trace.y.slice(0, len));
83+
var valsz = distinctVals(trace.z.slice(0, len));
84+
85+
// Over-specified mesh case, this would error in tube2mesh
86+
if(valsx.length * valsy.length * valsz.length > len) {
87+
return {positions: [], cells: []};
88+
}
89+
90+
var meshx = toDataCoords(valsx, 'xaxis');
91+
var meshy = toDataCoords(valsy, 'yaxis');
92+
var meshz = toDataCoords(valsz, 'zaxis');
93+
94+
tubeOpts.meshgrid = [meshx, meshy, meshz];
7595

7696
// TODO make this optional?
97+
// Default to in-between x/y/z mesh
7798
tubeOpts.startingPositions = zip3(
7899
toDataCoords(trace.startx, 'xaxis'),
79100
toDataCoords(trace.starty, 'yaxis'),
@@ -87,12 +108,19 @@ function convert(scene, trace) {
87108

88109
tubeOpts.tubeSize = trace.sizeref;
89110

111+
// add some padding around the bounds
112+
// to e.g. allow tubes starting from a slice of the x/y/z mesh
113+
// to go beyond bounds a little bit w/o getting clipped
90114
var xbnds = toDataCoords(trace._xbnds, 'xaxis');
91115
var ybnds = toDataCoords(trace._ybnds, 'yaxis');
92116
var zbnds = toDataCoords(trace._zbnds, 'zaxis');
117+
var xpads = getBoundPads(meshx);
118+
var ypads = getBoundPads(meshy);
119+
var zpads = getBoundPads(meshz);
120+
93121
var bounds = [
94-
[xbnds[0], ybnds[0], zbnds[0]],
95-
[xbnds[1], ybnds[1], zbnds[1]]
122+
[xbnds[0] - xpads[0], ybnds[0] - ypads[0], zbnds[0] - zpads[0]],
123+
[xbnds[1] + xpads[1], ybnds[1] + ypads[1], zbnds[1] + zpads[1]]
96124
];
97125

98126
var meshData = tube2mesh(tubeOpts, bounds);
@@ -103,14 +131,22 @@ function convert(scene, trace) {
103131
meshData.vertexIntensityBounds = [trace.cmin / trace._normMax, trace.cmax / trace._normMax];
104132

105133
// pass gl-mesh3d lighting attributes
106-
meshData.lightPosition = [trace.lightposition.x, trace.lightposition.y, trace.lightposition.z];
134+
var lp = trace.lightposition;
135+
meshData.lightPosition = [lp.x, lp.y, lp.z];
107136
meshData.ambient = trace.lighting.ambient;
108137
meshData.diffuse = trace.lighting.diffuse;
109138
meshData.specular = trace.lighting.specular;
110139
meshData.roughness = trace.lighting.roughness;
111140
meshData.fresnel = trace.lighting.fresnel;
112141
meshData.opacity = trace.opacity;
113142

143+
// TODO
144+
// stash autorange pad value
145+
// - include pad!
146+
// - include tubeScale
147+
// trace._pad = meshData.tubeScale * trace.sizeref;
148+
// if(trace.sizemode === 'scaled') trace._pad *= trace._normMax;
149+
114150
return meshData;
115151
}
116152

Diff for: src/traces/streamtube/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
6060
coerce('text');
6161

6262
// disable 1D transforms (for now)
63+
// x/y/z and u/v/w have matching lengths,
64+
// but they don't have to match with start(x|y|z)
6365
traceOut._length = null;
6466
};

Diff for: test/image/baselines/gl3d_streamtube-first.png

10.6 KB
Loading

Diff for: test/image/baselines/gl3d_streamtube-simple.png

35 KB
Loading

Diff for: test/image/baselines/gl3d_streamtube-thin.png

-308 Bytes
Loading

Diff for: test/image/baselines/gl3d_streamtube-wind.png

45.6 KB
Loading

0 commit comments

Comments
 (0)