|
import Bug from './Bug' |
|
import Triangle from './Triangle' |
|
import Forward from './Forward' |
|
import Repeat from './Repeat' |
|
import Left from './Left' |
|
import Right from './Right' |
|
import Rotate from './Rotate' |
|
import SphericalPolars from './SphericalPolars' |
|
import Steppable from './Steppable' |
|
import SteppableList from './SteppableList' |
|
import Track from './Track' |
|
import World from './World' |
|
|
|
const origin = EIGHT.Geometric3.zero() |
|
const e1 = EIGHT.Geometric3.e1() |
|
const e2 = EIGHT.Geometric3.e2() |
|
const e3 = EIGHT.Geometric3.e3() |
|
|
|
/** |
|
* The initial frame sets the orientation, but since the position and |
|
* up direction are the same on a sphere, this also sets the position. |
|
*/ |
|
const INITIAL_FRAME = [e2, -e1, e3] |
|
const INITIAL_POINTER = e2 |
|
|
|
/** |
|
* A brave new World. |
|
*/ |
|
const world = new World() |
|
|
|
const bug = new Bug() |
|
|
|
const viz = new Triangle(world.engine) |
|
viz.height = 0.1 |
|
viz.width = 0.0618 |
|
viz.color = EIGHT.Color.white |
|
|
|
const coords = new SphericalPolars(world.engine) |
|
coords.color = EIGHT.Color.gray |
|
|
|
const track = new Track(world.engine) |
|
track.color = EIGHT.Color.gray |
|
track.color = EIGHT.Color.white |
|
|
|
const arrow = new EIGHT.Arrow() |
|
arrow.subscribe(world.engine) |
|
arrow.synchUp() |
|
|
|
world.reset() |
|
world.sideView() |
|
|
|
/** |
|
* Use to control the speed of the animation. |
|
* Roughly the number of frames used to execute a motion step. |
|
*/ |
|
const FRAMES_PER_STEP = 50 |
|
const ONE_TURN = 2 * Math.PI |
|
const QUARTER_TURN = ONE_TURN / 4 |
|
/** |
|
* Divisor for the movement and turning angle. |
|
*/ |
|
const N = 1 // must be an integer |
|
/** |
|
* Ratio of forward movement to turn angle. |
|
*/ |
|
const ρ = 1 |
|
/** |
|
* Distance that we move forward. |
|
*/ |
|
const s = ρ * QUARTER_TURN / N |
|
/** |
|
* Angle that we turn through. |
|
*/ |
|
const θ = QUARTER_TURN / N |
|
/** |
|
* The number of repetitions. |
|
*/ |
|
const REPETITIONS = 3 * N |
|
|
|
const list = new SteppableList() |
|
list.add(new Repeat(new Forward(bug, s / FRAMES_PER_STEP), FRAMES_PER_STEP)) |
|
list.add(new Repeat(new Left(bug, -θ / FRAMES_PER_STEP), FRAMES_PER_STEP)) |
|
const program = new Repeat(list, REPETITIONS) |
|
let stepper = program.stepper() |
|
|
|
const animate = function() { |
|
|
|
world.beginFrame() |
|
|
|
if (world.time === 0) { |
|
// Initialize or Reset. |
|
bug.pointer.copy(INITIAL_POINTER) |
|
bug.X.copy(e3) |
|
bug.frame = INITIAL_FRAME |
|
// Erasing and adding the start point means we only have one point upon reset. |
|
track.erase() |
|
track.addPoint(bug.X) |
|
// We also need a new stepper. |
|
stepper = program.stepper() |
|
} |
|
|
|
if (world.running && stepper.hasNext()) { |
|
// We'll count steps. |
|
// All that matters is that time moves on from zero so we can reset. |
|
world.time = world.time + 1 |
|
stepper.next(); |
|
track.addPoint(bug.X) |
|
} |
|
|
|
// Render the bug as a triangle. |
|
viz.X.copyVector(bug.X) |
|
viz.R.rotorFromFrameToFrame(INITIAL_FRAME, bug.frame) |
|
viz.render(world.ambients) |
|
|
|
// Render the track of the bug. |
|
track.render(world.ambients) |
|
|
|
// Render the pointer of the bug as a blue arrow. |
|
arrow.h.copy(bug.pointer).normalize().scale(0.3) |
|
arrow.X.copy(bug.X) |
|
arrow.color = EIGHT.Color.blue |
|
arrow.render(world.ambients) |
|
|
|
// Render the initial pointer as a green arrow at the initial location. |
|
arrow.h.copy(INITIAL_POINTER).normalize().scale(0.3) |
|
arrow.X.copy(e3) |
|
arrow.color = EIGHT.Color.green |
|
arrow.render(world.ambients) |
|
|
|
// Render the Spherical Polar Coordinate curves. |
|
coords.render(world.ambients) |
|
|
|
// This call keeps the animation going. |
|
requestAnimationFrame(animate) |
|
} |
|
|
|
// This call starts the animation. |
|
requestAnimationFrame(animate) |