function update(width, height, dt) { //do some mouse motion particles.forEach(function(p) { var s = 0.05 //get direction of mouse to this particle vec.subtract(dir, mouse, p.position) vec.normalize(dir, dir) //perform some mouse motion on the vertices var dist = smoothstep(100, 50, vec.distance(p.position, mouse)) vec.scale(dir, dir, dist*0.5) p.addForce(dir) }) //constrain world system.max = [width, height] system.min = [0, 0] //step the physics system.integrate(particles, dt/1000) //perform triangulation on all points positions = particles.map(function(p) { return p.position }) cells = delaunay(positions) }
function constructDelaunay(points, color, axis) { var u = (axis + 1) % 3; var v = (axis + 2) % 3; var filteredPoints = []; var filteredIds = []; var i; for(i = 0; i < points.length; ++i) { var p = points[i]; if(isNaN(p[u]) || !isFinite(p[u]) || isNaN(p[v]) || !isFinite(p[v])) { continue; } filteredPoints.push([p[u], p[v]]); filteredIds.push(i); } var cells = triangulate(filteredPoints); for(i = 0; i < cells.length; ++i) { var c = cells[i]; for(var j = 0; j < c.length; ++j) { c[j] = filteredIds[c[j]]; } } return { positions: points, cells: cells, meshColor: color }; }
function render(dt) { let t = dt / (1000/24) let { width, height } = canvas ctx.clearRect(0, 0, width, height) //triangualte and draw lines let positions = points.map(p => p.position) let cells = triangulate(positions) ctx.beginPath() ctx.lineWidth = 1 ctx.lineJoin = 'round' ctx.strokeStyle = 'hsl(0, 0%, 65%)' drawTriangles(ctx, positions, cells) ctx.stroke() //render and integrate points ctx.beginPath() points.forEach(point => { let [ x, y ] = point.position let [ vx, vy ] = point.velocity let radius = point.radius ctx.moveTo(x, y) ctx.arc(x, y, radius, 0, Math.PI*2, false) point.position[0] += vx * t point.position[1] += vy * t point.velocity[0] *= friction point.velocity[1] *= friction }) ctx.fillStyle = '#000' ctx.fill() }
shell.on("tick", function() { if(shell.wasDown("mouse-1")) { var w = canvas.width var h = canvas.height points.push([shell.mouseX/w, shell.mouseY/h]) robustTriangulation = robustDelaunay(points) nonrobustTriangulation = [] nonrobustTriangulation = nonRobustDelaunay(points) } })
function verifyDT(tape, points) { var expectedCells = delaunay(points) var actualCells = cdt(points) //Canonicalize cells actualCells = actualCells.map(normalizeCell).sort(compareLex) expectedCells = expectedCells.map(flipCell).map(normalizeCell).sort(compareLex) if(actualCells.length !== expectedCells.length) { tape.error('dt returned incorrect number of cells') return } for(var i=0; i<actualCells.length; ++i) { tape.equals(actualCells[i].join(), expectedCells[i].join(), 'cells match') } }
$('canvas').click(function(e) { var x = e.pageX * devicePixelRatio var y = e.pageY * devicePixelRatio var point = [x,y] current.points.push(point) current.triangleIndices = CreateTriangles( current.points ) current.triangles = current.triangleIndices.map(function( indices ) { var pt1 = current.points[indices[0]] var pt2 = current.points[indices[1]] var pt3 = current.points[indices[2]] return [pt1, pt2, pt3] }) current.circumcenters = current.triangles.map( Circumcenter ) draw() })
World.prototype.setupEnvironment = function () { this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false }); this.width = window.innerWidth; this.height = window.innerHeight; this.renderer.setSize(this.width, this.height); this.renderer.setClearColor(0xffffff, 0); this.renderer.domElement.id = "canvas"; this.renderer.context.getProgramInfoLog = function () { return '' }; // muzzle this.effect1 = new THREE.ParallaxBarrierEffect(this.renderer); this.effect2 = new THREE.AnaglyphEffect(this.renderer); this.effect1.setSize(this.width, this.height); this.effect2.setSize(this.width, this.height); this.useEffect = 0; this.clock = new THREE.Clock(); document.body.appendChild(this.renderer.domElement); this.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 3000); this.camera.position.set(0, 0, 700); this.scene = new THREE.Scene(); this.container = new THREE.Object3D(); this.scene.add(this.container); var scene = this.scene; var particleCount = users.length; var uniforms = { texture: { type: 't', value: THREE.ImageUtils.loadTexture('images/unicorns2.jpg') } }; var attributes = { texIndex: { type: 'f', value: [] } }; this.attributes = attributes; var material = new THREE.ShaderMaterial({ uniforms: uniforms, attributes: attributes, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent, transparent: true }); var pointMaterial = new THREE.PointCloudMaterial({ color: 0x09A7F7, size: 20, map: THREE.ImageUtils.loadTexture('images/disc.png'), transparent: true }) var geometry = new THREE.Geometry(); var zPos = -1000; var inc = 1500 / particleCount; var points = []; var x, y, z, r = 750; for (var i = 0; i < particleCount; i++) { do { x = (Math.random() - 0.5) * r*2; y = (Math.random() - 0.5) * r*2; z = (Math.random() - 0.5) * r*2; } while (((x*x) + (y*y) + (z*z)) > r*r) var pt = [x, y, z]; var vt = new THREE.Vector3(x, y, z); points.push(pt); geometry.vertices.push(vt); attributes.texIndex.value.push(i); zPos += inc; } var tris = dt(points); var a, b, c, f; for (var i = 0; i < tris.length; i+= 5) { f = new THREE.Face3(tris[i][0], tris[i][1] , tris[i][2]); geometry.faces.push(f); } geometry.computeBoundingSphere(); var meshMaterial = new THREE.MeshBasicMaterial({ wireframe: true, color: 0xFF0044, transparent: true, opacity: 0.2 }); this.meshGeom = geometry.clone(); var mesh = new THREE.Mesh(this.meshGeom, meshMaterial); this.container.add(mesh); // make a grid // for (var i = 0; i < particleCount; i++) { // var row = Math.floor(i/32); // var col = i % 32; // var pos = new THREE.Vector3( // -(500) + col * 32, // -(500) + row * 32, // -800 // ); // geometry.vertices.push(pos) // attributes.texIndex.value.push(i); // } var particles = new THREE.PointCloud(geometry, pointMaterial); // var particles = new THREE.PointCloud(geometry, material); particles.sortParticles = true; this.particlesGeom = geometry; this.container.add(particles); };
exports.triangulate = function(mat2d) { return triangulate(mat2d); }
function SphereGeometry(radius, total, elongatedTarget){ radius = radius !== undefined ? radius : 20; total = total !== undefined ? total : 20; var verticeArrays = []; var geometry = new THREE.Geometry(); var vertices = geometry.vertices; var i, hash, uniqueIndex; for (i = 0; i < total; i++) { var longLat = pointOnSphere(i, total); var long = longLat[0]; var lat = longLat[1]; var vertArr = [ Math.cos(lat) * Math.cos(long) * radius, Math.sin(lat) * radius, Math.cos(lat) * Math.sin(long) * radius ]; verticeArrays.push(vertArr); vertices.push((new THREE.Vector3().fromArray(vertArr))); } var tetras = triangulate(verticeArrays); var triangles = []; for (i = 0; i < tetras.length; i++) { var tetra = tetras[i]; triangles.push(tetra[0], tetra[1], tetra[3]); triangles.push(tetra[0], tetra[2], tetra[1]); triangles.push(tetra[0], tetra[3], tetra[2]); triangles.push(tetra[3], tetra[1], tetra[2]); } var temp; var uniques = []; var counts = []; var tempTri = []; function uniqueTriOrderSort(a, b) { return a - b; } for (i = 0; i < triangles.length; i+=3) { tempTri[0] = triangles[i]; tempTri[1] = triangles[i+1]; tempTri[2] = triangles[i+2]; tempTri = tempTri.sort(uniqueTriOrderSort); hash = tempTri[0]+','+tempTri[1]+','+tempTri[2]; uniqueIndex = uniques.indexOf(hash); if(uniqueIndex === -1) { uniqueIndex = uniques.length; uniques.push(hash); counts.push(0); } counts[uniqueIndex]++; } for (i = 0; i < triangles.length; i+=3) { tempTri[0] = triangles[i]; tempTri[1] = triangles[i+1]; tempTri[2] = triangles[i+2]; tempTri = tempTri.sort(uniqueTriOrderSort); hash = tempTri[0]+','+tempTri[1]+','+tempTri[2]; uniqueIndex = uniques.indexOf(hash); if(counts[uniqueIndex] === 1) { var face = new THREE.Face3(triangles[i], triangles[i+1], triangles[i+2]); geometry.faces.push(face); } } geometry.computeFaceNormals(); geometry.computeVertexNormals(); // geometry.computeTangents(); if(elongatedTarget) { var vertices2 = []; geometry.vertices.forEach(function(v){ if(v.y>0) { v.multiplyScalar(0.8); v.y += 1; } var v2 = v.clone(); if(v2.y<0) { v2.y = 0; }else{ v2.y = 1; } vertices2.push(v2); }); geometry.morphTargets.push( { name: "target", vertices: vertices2 } ); } return geometry; }
proto.update = function(data) { var scene = this.scene, layout = scene.fullSceneLayout; this.data = data; //Unpack position data function toDataCoords(axis, coord, scale) { return coord.map(function(x) { return axis.d2l(x) * scale; }); } var positions = zip3( toDataCoords(layout.xaxis, data.x, scene.dataScale[0]), toDataCoords(layout.yaxis, data.y, scene.dataScale[1]), toDataCoords(layout.zaxis, data.z, scene.dataScale[2])); var cells; if(data.i && data.j && data.k) { cells = zip3(data.i, data.j, data.k); } else if(data.alphahull === 0) { cells = convexHull(positions); } else if(data.alphahull > 0) { cells = alphaShape(data.alphahull, positions); } else { var d = ['x', 'y', 'z'].indexOf(data.delaunayaxis); cells = triangulate(positions.map(function(c) { return [c[(d+1)%3], c[(d+2)%3]]; })); } var config = { positions: positions, cells: cells, ambient: data.lighting.ambient, diffuse: data.lighting.diffuse, specular: data.lighting.specular, roughness: data.lighting.roughness, fresnel: data.lighting.fresnel, opacity: data.opacity, contourEnable: data.contour.show, contourColor: str2RgbaArray(data.contour.color).slice(0,3), contourWidth: data.contour.width, useFacetNormals: data.flatshading }; if(data.intensity) { this.color = '#fff'; config.vertexIntensity = data.intensity; config.colormap = parseColorScale(data.colorscale); } else if(data.vertexcolor) { this.color = data.vertexcolors[0]; config.vertexColors = parseColorArray(data.vertexcolor); } else if(data.facecolor) { this.color = data.facecolor[0]; config.cellColors = parseColorArray(data.facecolor); } else { this.color = data.color; config.meshColor = str2RgbaArray(data.color); } //Update mesh this.mesh.update(config); };
function _prepCanvasAndGetCtx(){function i(){e.width=window.innerWidth*devicePixelRatio,e.height=window.innerHeight*devicePixelRatio}var e=$("canvas")[0];return $(window).on("resize",i),i(),e.getContext("2d")}function _clickToCreatePoints(i,e){$("canvas").click(function(n){var t=n.pageX*devicePixelRatio,r=n.pageY*devicePixelRatio,o=[t,r];i.points.push(o),i.triangleIndices=CreateTriangles(i.points),i.triangles=i.triangleIndices.map(function(e){var n=i.points[e[0]],t=i.points[e[1]],r=i.points[e[2]];return[n,t,r]}),i.circumcenters=i.triangles.map(Circumcenter),e()})}function _drawTriangles(i,e,n,t){i.lineWidth=e.lineWidth*devicePixelRatio,i.strokeStyle=e.lineColor,i.beginPath(),n.forEach(function(e){i.moveTo(e[0][0],e[0][1]),i.lineTo(e[1][0],e[1][1]),i.moveTo(e[1][0],e[1][1]),i.lineTo(e[2][0],e[2][1]),i.moveTo(e[2][0],e[2][1]),i.lineTo(e[0][0],e[0][1])}),i.stroke(),i.closePath()}function _drawPoints(i,e,n){e.pointSize*devicePixelRatio,e.pointSize/2*devicePixelRatio;i.fillStyle=e.pointColor,n.forEach(function(n){i.beginPath(),i.arc(n[0],n[1],e.pointSize,0,TAU),i.fill()})}function _drawCircumcenters(i,e,n,t){i.strokeStyle=e.circumcenterColor,i.lineWidth=e.circumcenterLineWidth,n.forEach(function(e,n){var r=t[n][0],o=Math.sqrt(Math.pow(e[0]-r[0],2)+Math.pow(e[1]-r[1],2));i.beginPath(),i.arc(e[0],e[1],o,0,TAU),i.stroke()})}function _drawFn(i,e,n){return function(){i.clearRect(0,0,window.innerWidth*devicePixelRatio,window.innerHeight*devicePixelRatio),_drawTriangles(i,e,n.triangles,n.points),_drawPoints(i,e,n.points),_drawCircumcenters(i,e,n.circumcenters,n.triangles)}}function init(){var i=_prepCanvasAndGetCtx(),e={points:[],triangles:[]},n={pointSize:4,pointColor:"#fff",lineWidth:2,lineColor:"#208FF3",circumcenterColor:"rgba(30,255,30,0.15)",circumcenterLineWidth:2},t=_drawFn(i,n,e);$(window).on("resize",t),_clickToCreatePoints(e,t)}var CreateTriangles=require("delaunay-triangulate"),Circumcenter=require("circumcenter"),TAU=2*Math.PI;jQuery(init);