Skip to content

Instantly share code, notes, and snippets.

@mathdoodle
Last active July 7, 2020 20:18
Show Gist options
  • Save mathdoodle/920edc41585eebe3a230ee5843477ef5 to your computer and use it in GitHub Desktop.
Save mathdoodle/920edc41585eebe3a230ee5843477ef5 to your computer and use it in GitHub Desktop.
Paul trap

Paul trap

Overview

A simulation of a Paul trap.

<!doctype html>
<html>
<head>
<!-- STYLES-MARKER -->
<style>
/* STYLE-MARKER */
</style>
<script src="https://jspm.io/system.js"></script>
<!-- SHADERS-MARKER -->
<!-- SCRIPTS-MARKER -->
</head>
<body>
<canvas id='canvas'></canvas>
<script>
// CODE-MARKER
</script>
<script>
System.defaultJSExtensions = true
System.import('./index')
</script>
</body>
</html>
import { Geometric3 } from 'davinci-eight'
import { VectorE3, BivectorE3 } from 'davinci-eight'
import { Engine, Capability, Scene, Facet, PerspectiveCamera } from 'davinci-eight'
import { DirectionalLight, TrackballControls } from 'davinci-eight'
import { Arrow, Sphere, Color, Grid } from 'davinci-eight'
const e1 = Geometric3.e1()
const e2 = Geometric3.e2()
const e3 = Geometric3.e3()
const I = e1 ^ e2 ^ e3
const g = -e3
/**
* The position of the particle on the surface.
* We will have to move the ball to make it look like it is resting on the surface.
*/
const tangent = function(X: VectorE3): BivectorE3 {
const x = X.x
const y = X.y
const v1 = e1 + 2 * x * e3
const v2 = e2 - 2 * y * e3
return (v1 ^ v2).normalize()
}
const aPosition = (x: number, y: number) => x * e1 + y * e2 + (x * x - y * y) * e3
const aNormal = function(x: number, y: number): Geometric3 {
return (I * Geometric3.fromBivector(tangent({ x, y, z: 0 }))).scale(-1).normalize()
}
const ballCenter = function(X: VectorE3, radius: number): Geometric3 {
const P = aPosition(X.x, X.y)
const N = aNormal(X.x, X.y)
return Geometric3.fromVector(P).add(N, radius)
}
const ballNormal = function(X: VectorE3) {
return aNormal(X.x, X.y)
}
const acceleration = function(X: VectorE3): VectorE3 {
const B = Geometric3.fromBivector(tangent(X))
const c = g << B
return B * c
}
/**
* Wrapper around the WebGLRenderingContext providing the ContextManager interface.
*/
const engine = new Engine('canvas')
.size(500, 500)
.clearColor(0.1, 0.1, 0.1, 1.0)
.enable(Capability.DEPTH_TEST)
/**
* A collection of objects that can be rendered with a single draw method call.
*/
const scene = new Scene(engine)
/**
* Rendering information that applies to all objects.
*/
const ambients: Facet[] = []
/**
* Provides the viewing point and perspective transformation.
*/
const camera = new PerspectiveCamera()
camera.eye.copy(e3 + e2 + e1).scale(3)
camera.up.copy(e3)
ambients.push(camera)
/**
* Provides a light color and direction for Lambert shading.
*/
const dirLight = new DirectionalLight()
ambients.push(dirLight)
/**
* Controls the camera by accumulating mouse movements then moving and rotating the camera.
*/
const trackball = new TrackballControls(camera, window)
trackball.subscribe(engine.canvas)
trackball.noPan = true
const ball = new Sphere(engine)
ball.color = Color.yellow
ball.radius = 0.1
scene.add(ball)
const grid = new Grid(engine, {
mode: 1,
aPosition,
aNormal
})
grid.color = Color.gray
scene.add(grid)
const arrow = new Arrow(engine)
const stats = new Stats()
stats.domElement.style.position = 'absolute'
stats.domElement.style.top = '10px'
stats.domElement.style.left = '10px'
stats.domElement.style.zIndex = '100'
document.body.appendChild(stats.domElement)
const X = ballCenter(0.5 * e2, ball.radius)
const T = 5
const ω = 2 * Math.PI / T
const B = e1 ^ e2
const R = Geometric3.one()
/**
* Animates the scene.
*/
const animate = function(timestamp: number) {
stats.begin()
engine.clear()
trackball.update()
dirLight.direction.copy(camera.look).sub(camera.eye)
const t = timestamp * 0.00001
const θ = ω * t
R.copy(B).scale(-θ / 2).exp()
// grid.R.copy(R)
R.copy(B).scale(0.01).exp()
X.rotate(R)
ball.X.copyVector(ballCenter(X, ball.radius))
arrow.X.copyVector(ballCenter(X, ball.radius))
arrow.vector = ballNormal(X)
arrow.color.copy(Color.blue)
arrow.render(ambients)
arrow.X.copyVector(ballCenter(X, ball.radius))
arrow.vector = acceleration(X)
arrow.color.copy(Color.red)
arrow.render(ambients)
scene.render(ambients)
stats.end()
requestAnimationFrame(animate)
}
requestAnimationFrame(animate)
{
"description": "Paul trap",
"dependencies": {
"stats.js": "0.16.0",
"davinci-eight": "7.4.4"
},
"operatorOverloading": true,
"name": "copy-of-eight-starter-template",
"version": "0.1.0",
"author": "David Geo Holmes",
"linting": true
}
body { margin: 0; }
canvas { width: 500px; height: 500px }
#stats { position: absolute; top: 0; left: 0; }
{
"allowJs": true,
"checkJs": true,
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "system",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true,
"removeComments": false,
"skipLibCheck": true,
"sourceMap": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5",
"traceResolution": true
}
{
"rules": {
"array-type": [
true,
"array"
],
"curly": false,
"comment-format": [
true,
"check-space"
],
"eofline": true,
"forin": true,
"jsdoc-format": true,
"new-parens": true,
"no-conditional-assignment": false,
"no-consecutive-blank-lines": true,
"no-construct": true,
"no-for-in-array": true,
"no-inferrable-types": [
true
],
"no-magic-numbers": false,
"no-shadowed-variable": true,
"no-string-throw": true,
"no-trailing-whitespace": [
true,
"ignore-jsdoc"
],
"no-var-keyword": true,
"one-variable-per-declaration": [
true,
"ignore-for-loop"
],
"prefer-const": true,
"prefer-for-of": true,
"prefer-function-over-method": false,
"prefer-method-signature": true,
"radix": true,
"semicolon": [
true,
"never"
],
"trailing-comma": [
true,
{
"multiline": "never",
"singleline": "never"
}
],
"triple-equals": true,
"use-isnan": true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment