Skip to content

Instantly share code, notes, and snippets.

@stemcstudio
Last active August 8, 2016 14:53
Show Gist options
  • Save stemcstudio/3ab0319a9d6eaaf7695bab9fc0f5e910 to your computer and use it in GitHub Desktop.
Save stemcstudio/3ab0319a9d6eaaf7695bab9fc0f5e910 to your computer and use it in GitHub Desktop.
Vector Modeling Problem Framework

Vector Modeling Problem Framework

Overview

This is a starter project for creating Computational Projects for learning geometry, kinematics and dynamics.

A student develops their own Vector3 class for describing the position and velocity of objects in 3D. This class then becomes the basis for future projects. Vector3 is a springboard to Geometric3, a geometric object for Euclidean space using Geometric Algebra.

The Vector3 class in the file Vector3.ts is initially nothing more than a triple of Cartesian coordinates. The goal is to develop the Vector3 class into a mathematical object supporting coordinate-free geometry. The student develops an appreciation of the power of geometric objects for representing physical laws.

Principles

  1. Productivity. The project has been designed so that the student need only work in the index.ts and Vector3.ts files without becoming bogged down in the details of Computer Graphics.
  2. Transparency. The project does not hide details, so that the details may be explored. Explicit is better than implicit.
  3. Constructive Modeling. The important Physical, Mathematical, and Computation models are constructed by the student. We understand that which we construct.
  4. Ownership. The student takes ownership of that which they construct. Errors become challenges to mastery.
  5. Separation. Models should be distinct from graphical representations. Constructing algorithms and data structures is a part of developing Computational Thinking skills.

Learning Terminology

  1. basis as reference vectors e1 and e2.
  2. decompose $\vec{v} = a \mathbf{e}_1 + b \mathbf{e}_2$.
  3. components of $\vec{v}$ $a \mathbf{e}_1$ and $b \mathbf{e}_2$.
  4. coordinates of $\vec{v}$: $a$ and $b$

Instructions

Some ideas:

  1. Use the Vector3 to model position and velocity kinematic variables. Position and move an object in various ways.
  2. Develop methods for implementing scalar multiplication, addition and subtraction.
  3. Replace explicit method calls with operator overloading for a more natural representation of geometric ideas.
  4. Develop methods that provide magnitude and direction.
  5. Define basis vector constants.
  6. Develop methods that implement magnitude and direction.
  7. Develop methods for projection and a scalar product.
  8. Develop methods for reflection and rejection.
  9. Develop method for vector cross-product.
  10. Use the EIGHT.Arrow class for visualizing vectors.
  11. Use the EIGHT.Basis class for visualizing a coordinate basis.
  12. Use EIGHT.Trail for showing a graphical trail.
  13. Use EIGHT.Vector3 and EIGHT.Geometric3 as advanced examples of geometric quantities in 3D
  14. Use the UNITS library for investigating Units of Measure.
  15. Use JSXGraph library for graphing.
  16. Introduce mass, momentum, force, and dynamics.
  17. Model single and multi-particle problems.
  18. Model two-particle problems with internal interactions.
  19. Model rigid-body problems.
  20. Write unit tests to verify Vector3 class.
<!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='my-canvas'></canvas>
<script>
// CODE-MARKER
</script>
<script>
System.import('./index.js')
</script>
</body>
</html>
import Vector3 from './Vector3'
import World from './World'
/**
* A brave new World.
*/
const world = new World()
const sphere = world.createSphere()
sphere.color = new EIGHT.Color(0.8984, 0.1133, 0.3711)
sphere.radius = 0.3
const gridXY = world.createGridXY({segments: 20, min: -10, max: +10})
gridXY.color = new EIGHT.Color(0.4, 0.4, 0.4)
world.reset()
let r = new Vector3(-10, 0, 0)
let v = new Vector3(1, 0, 0)
const stats = new Stats()
document.body.appendChild(stats.dom)
const animate = function() {
stats.begin()
world.beginFrame()
const Δt = world.running ? 0.05 : 0
if (world.time === 0) {
r = new Vector3(-10, 0, 0)
v = new Vector3(1, 0, 0)
}
world.time = world.time + Δt
r.x = r.x + v.x * Δt
r.y = r.y + v.y * Δt
r.z = r.z + v.z * Δt
sphere.X.x = r.x
sphere.X.y = r.y
sphere.X.z = r.z
world.draw()
stats.end()
// This call keeps the animation going.
requestAnimationFrame(animate)
}
// This call starts the animation.
requestAnimationFrame(animate)
{
"description": "Vector Modeling Problem Framework",
"dependencies": {
"DomReady": "1.0.0",
"jasmine": "2.4.1",
"davinci-eight": "2.245.0",
"dat-gui": "0.5.0",
"stats.js": "0.16.0"
},
"name": "Vector Modeling Problem Framework",
"version": "1.0.0",
"keywords": [
"EIGHT",
"project",
"Getting",
"Started",
"WebGL"
],
"operatorOverloading": true,
"author": "David Geo Holmes"
}
body {
background-color: white;
}
<!DOCTYPE html>
<html>
<head>
<!-- STYLES-MARKER -->
<style>
/* STYLE-MARKER */
</style>
<script src='https://jspm.io/system.js'></script>
<!-- SCRIPTS-MARKER -->
</head>
<body>
<script>
// CODE-MARKER
</script>
<script>
System.import('./tests.js')
</script>
</body>
</html>
import Vector3 from './Vector3.spec'
window['jasmine'] = jasmineRequire.core(jasmineRequire)
jasmineRequire.html(window['jasmine'])
const env = jasmine.getEnv()
const jasmineInterface = jasmineRequire.interface(window['jasmine'], env)
extend(window, jasmineInterface)
const htmlReporter = new jasmine.HtmlReporter({
env: env,
getContainer: function() { return document.body },
createElement: function() { return document.createElement.apply(document, arguments) },
createTextNode: function() { return document.createTextNode.apply(document, arguments) },
timer: new jasmine.Timer()
})
env.addReporter(htmlReporter)
DomReady.ready(function() {
htmlReporter.initialize()
describe("Vector3", Vector3)
env.execute()
})
/*
* Helper function for extending the properties on objects.
*/
export default function extend<T>(destination: T, source: any): T {
for (let property in source) {
destination[property] = source[property]
}
return destination
}
import Vector3 from './Vector3';
export default function() {
describe("constructor", function() {
const x = Math.random();
const y = Math.random();
const z = Math.random();
const v = new Vector3(x, y, z);
it("should initialize x-coordinate", function() {
expect(v.x).toBe(x)
})
})
}
export default class Vector3 {
constructor(public x = 0, public y = 0, public z = 0) {
}
}
const origin = EIGHT.Geometric3.vector(0, 0, 0)
const e1 = EIGHT.Geometric3.vector(1, 0, 0)
const e2 = EIGHT.Geometric3.vector(0, 1, 0)
const e3 = EIGHT.Geometric3.vector(0, 0, 1)
export default class World {
private engine: EIGHT.Engine;
private scene: EIGHT.Scene;
private ambients: EIGHT.Facet[] = [];
private camera: EIGHT.PerspectiveCamera;
private trackball: EIGHT.TrackballControls;
private dirLight: EIGHT.DirectionalLight;
private gui: dat.GUI;
/**
* An flag that determines whether the simulation should move forward.
*/
public running = false;
/**
* Universal Newtonian Time.
*/
public time = 0;
/**
* Creates a new Worls containg a WebGL canvas, a camera, lighting,
* and controllers.
*/
constructor() {
this.engine = new EIGHT.Engine('my-canvas')
.size(500, 500)
.clearColor(0.1, 0.1, 0.1, 1.0)
.enable(EIGHT.Capability.DEPTH_TEST);
this.scene = new EIGHT.Scene(this.engine);
this.camera = new EIGHT.PerspectiveCamera();
this.ambients.push(this.camera)
this.dirLight = new EIGHT.DirectionalLight();
this.ambients.push(this.dirLight)
this.trackball = new EIGHT.TrackballControls(this.camera, window)
// Subscribe to mouse events from the canvas.
this.trackball.subscribe(this.engine.canvas)
this.gui = new dat.GUI({name: 'Yahoo'});
const simFolder = this.gui.addFolder("Simulation")
simFolder.add(this, 'start');
simFolder.add(this, 'stop');
simFolder.add(this, 'reset');
simFolder.open();
const cameraFolder = this.gui.addFolder("Camera")
cameraFolder.add(this, 'planView');
cameraFolder.add(this, 'sideView');
cameraFolder.open();
this.sideView();
}
/**
* This method should be called at the beginning of an animation frame.
* It performs the following tasks:
* 1. Clears the graphics output.
* 2. Updates the camera based upon movements of the mouse.
* 3. Aligns the directional light with the viewing direction.
*/
beginFrame(): void {
this.engine.clear();
// Update the camera based upon mouse events received.
this.trackball.update();
// Keep the directional light pointing in the same direction as the camera.
this.dirLight.direction.copy(this.camera.look).sub(this.camera.eye)
}
/**
* This method should be called after objects have been moved.
*/
draw(): void {
this.scene.draw(this.ambients);
}
/**
* Puts the simulation into the running state.
*/
start(): void {
this.running = true
}
stop(): void {
this.running = false
}
/**
* Resets the universal time property back to zero.
*/
reset(): void {
this.running = false
this.time = 0
}
planView(): void {
this.camera.eye.copy(e3).normalize().scale(29)
this.camera.look.copy(origin)
this.camera.up.copy(e2)
}
sideView(): void {
this.camera.eye.sub2(e3, e2).normalize().scale(33)
this.camera.look.copy(origin)
this.camera.up.copy(e3)
}
/**
* Convenience method for creating a grid in the xy-plane.
*/
createGridXY(options: {
segments?: number;
min?: number;
max?: number;
} = {}): EIGHT.Grid {
const grid = new EIGHT.Grid({
uSegments: options.segments,
uMin: options.min,
uMax: options.max,
vSegments: options.segments,
vMin: options.min,
vMax: options.max
});
this.scene.add(grid);
return grid;
}
/**
* Convenience method for creating a sphere.
*/
createSphere(): EIGHT.Sphere {
const sphere = new EIGHT.Sphere();
this.scene.add(sphere);
return sphere;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment