block by monfera 6039e02f8731d6205f4ad9d55b62be49

Elastic collision test with Toph Tucker's elastic force

Full Screen

Testing Toph Tucker’s elastic collision implementation, in a setup identical to my baseline inelastic example that uses the built-in D3 forceCollide by Mike Bostock.

Built with blockbuilder.org

forked from monfera‘s block: Brownian motion with D3 4.0 velocity Verlet physics

forked from monfera‘s block: Collision test with D3 4.0

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://rawgit.com/tophtucker/16fbd7e7c6274ed329111cbe139a6bb6/raw/d6daaf1e9e3914268e2df1837bacf26622802e21/forceCollideElastic.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
  </style>
</head>

<body style="margin: 0; overflow: hidden">
<canvas id="realtime" width="1920" height="1000"
		    style="position: absolute; left: 0; top: 0; width: 960px; height: 500px" >
</canvas>

<script>

  var width = 1920
  var height = 1000

  var gasMoleculeCount = 1
  var dustCount = 4
  var gasMoleculeRadius = 12
  var dustRadius = 36

  var realtimeContext = document.querySelector('#realtime')
      .getContext('2d', {alpha: true})

  realtimeContext.transform(1, 0, 0, 1, width / 2, height / 2)

  var radius = function(node) { return node.radius }

  var gasMolecules = d3.range(gasMoleculeCount).map(function() {
    return {
      radius: gasMoleculeRadius,
      x: -width / 3 + dustRadius - gasMoleculeRadius, // collide at same time
      y: height / 6,
      vx: 2,
      vy: 0
    }
  })

  var dustParticles = d3.range(dustCount).map(function(d, i) {
    return {
      radius: dustRadius,
      x: width / 3 * [-1, 0, 0, -1][i],
      y: height / 6 * [-1, 0, 1, 0][i],
      vx: [2, 0, 0, 2][i],
      vy: 0
    }})

  var nodes = dustParticles.concat(gasMolecules)

  d3.forceSimulation(nodes)
      .alphaDecay(0)
      .velocityDecay(0)
      .force("collide", forceCollideElastic()
          .radius(radius).strength(1).iterations(10))
      .on("tick", render)

  realtimeContext.lineWidth = 1
  realtimeContext.fillStyle = "red"

  function render() {

    var i
    var r
    var particle

    realtimeContext.clearRect(-width / 2, -height / 2, width, height)

    realtimeContext.beginPath()
    realtimeContext.moveTo(-dustRadius, -height / 3)
    realtimeContext.lineTo(-dustRadius, height / 3)
    realtimeContext.stroke()

    realtimeContext.beginPath()
    for(i = 0; i < gasMoleculeCount; i++) {
      particle = gasMolecules[i]
      r = particle.radius
      realtimeContext.moveTo(particle.x + r, particle.y)
      realtimeContext.arc(particle.x, particle.y, r, 0, 2 * Math.PI)
    }
    realtimeContext.stroke()

    realtimeContext.beginPath()
    for(i = 0; i < dustCount; i++) {
      particle = dustParticles[i]
      r = particle.radius
      realtimeContext.moveTo(particle.x + r, particle.y)
      realtimeContext.arc(particle.x, particle.y, r, 0, 2 * Math.PI)
    }
    realtimeContext.fill()
    realtimeContext.stroke()
  }

</script>

</body>