Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 26 additions & 23 deletions cone.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,33 +169,39 @@ module.exports = function(vectorfield, bounds) {
var minX = 1/0, maxX = -1/0;
var minY = 1/0, maxY = -1/0;
var minZ = 1/0, maxZ = -1/0;
var v2 = null;
var p2 = null;
var u2 = null;
var positionVectors = [];
var minSeparation = 1/0;
var vectorScale = 1/0;
for (var i = 0; i < positions.length; i++) {
var v1 = positions[i];
minX = Math.min(v1[0], minX);
maxX = Math.max(v1[0], maxX);
minY = Math.min(v1[1], minY);
maxY = Math.max(v1[1], maxY);
minZ = Math.min(v1[2], minZ);
maxZ = Math.max(v1[2], maxZ);
var p = positions[i];
minX = Math.min(p[0], minX);
maxX = Math.max(p[0], maxX);
minY = Math.min(p[1], minY);
maxY = Math.max(p[1], maxY);
minZ = Math.min(p[2], minZ);
maxZ = Math.max(p[2], maxZ);
var u;
if (meshgrid) {
u = sampleMeshgrid(v1, vectors, meshgrid, true);
u = sampleMeshgrid(p, vectors, meshgrid, true);
} else {
u = vectors[i];
}
if (V.length(u) > maxNorm) {
maxNorm = V.length(u);
}
if (v2) {
var separation = V.distance(v1, v2);
if (separation < minSeparation) {
minSeparation = separation;
}
if (i) {
// Find vector scale [w/ units of time] using "successive" positions
// (not "adjacent" with would be O(n^2)),
//
// The vector scale corresponds to the minimum "time" to travel across two
// two adjacent positions at the average velocity of those two adjacent positions
vectorScale = Math.min(vectorScale,
2 * V.distance(p2, p) / (V.length(u2) + V.length(u))
);
}
v2 = v1;
p2 = p;
u2 = u;
positionVectors.push(u);
}
var minV = [minX, minY, minZ];
Expand All @@ -207,17 +213,14 @@ module.exports = function(vectorfield, bounds) {
if (maxNorm === 0) {
maxNorm = 1;
}

// Inverted max norm would map vector with norm maxNorm to 1 coord space units in length
var invertedMaxNorm = 1 / maxNorm;

if (!isFinite(minSeparation) || isNaN(minSeparation)) {
minSeparation = 1.0;
if (!isFinite(vectorScale) || isNaN(vectorScale)) {
vectorScale = 1.0;
}

// Inverted max norm multiplied scaled by smallest found vector position distance:
// Maps a vector with norm maxNorm to minSeparation coord space units in length.
// In practice, scales maxNorm vectors so that they are just long enough to reach the adjacent vector position.
geo.vectorScale = invertedMaxNorm * minSeparation;
geo.vectorScale = vectorScale;

var nml = vec3(0,1,0);

Expand Down
101 changes: 101 additions & 0 deletions example/cone_rossler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
var createCamera = require('3d-view-controls')
var getBounds = require('bound-points')
var perspective = require('gl-mat4/perspective')
var createAxes = require('gl-axes3d')
var createSpikes = require('gl-spikes3d')
var createSelect = require('gl-select-static')
var getBounds = require('bound-points')
var mouseChange = require('mouse-change')
var createConePlot = require('../cone')
var createMesh = createConePlot.createConeMesh;
var data = require('./dataset-rossler.json');

var bounds = []

var conePlot = createConePlot({
positions: data.positions,
vectors: data.vectors,
// uncomment to see visible cones
//coneSize: 40,
colormap: 'portland'
}, bounds)

var canvas = document.createElement('canvas')
document.body.appendChild(canvas)
window.addEventListener('resize', require('canvas-fit')(canvas))
var gl = canvas.getContext('webgl')

var camera = createCamera(canvas, {
eye: [3,3,3],
center: [0,0,0],
zoomMax: 500,
mode: 'turntable'
})


var mesh = createMesh(gl, conePlot)

var select = createSelect(gl, [canvas.width, canvas.height])
var tickSpacing = 1;
var ticks = bounds[0].map(function(v,i) {
var arr = [];
var firstTick = 0; //Math.ceil(bounds[0][i] / tickSpacing) * tickSpacing;
var lastTick = 3; //Math.floor(bounds[1][i] / tickSpacing) * tickSpacing;
for (var tick = firstTick; tick <= lastTick; tick += tickSpacing) {
if (tick === -0) tick = 0;
arr.push({x: tick, text: tick.toString()});
}
return arr;
});
var axes = createAxes(gl, { bounds: bounds, ticks: ticks })
var spikes = createSpikes(gl, {
bounds: bounds
})
var spikeChanged = false

mouseChange(canvas, function(buttons, x, y) {
var pickData = select.query(x, canvas.height - y, 10)
var pickResult = mesh.pick(pickData)
if(pickResult) {
spikes.update({
position: pickResult.position,
enabled: [true, true, true]
})
spikeChanged = true
} else {
spikeChanged = spikes.enabled[0]
spikes.update({
enabled: [false, false, false]
})
}
})

function render() {
requestAnimationFrame(render)

gl.enable(gl.DEPTH_TEST)

var needsUpdate = camera.tick()
var cameraParams = {
projection: perspective([], Math.PI/4, canvas.width/canvas.height, 0.1, 300),
view: camera.matrix
}

if(needsUpdate || spikeChanged) {
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
gl.viewport(0, 0, canvas.width, canvas.height)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
axes.draw(cameraParams)
spikes.draw(cameraParams)
mesh.draw(cameraParams)
spikeChanged = false
}

if(needsUpdate) {
select.shape = [canvas.width, canvas.height]
select.begin()
mesh.drawPick(cameraParams)
select.end()
}
}
render()
Loading