// PendulumComponents.js // John Breaux 2022-06-30 // Classes used by Pendulum.js "use strict"; // // Classes // // Polygon class: Construct and display a regular polygon in 2D class Polygon extends ShapedObject { // constructor: Make a new regular polygon constructor({ sides = 6, radius = 1, center = { x: 0, y: 0 }, color = { r: 0, g: 0, b: 1, a: 1 } } = {}) { super({ color: color }); // Create vertices this.vertices = []; for (var i = 0; i <= sides; i++) { // Create vertices by adding center-point in Homogeneous coordinates to an offset vector generated from polar coordinates. this.vertices[i] = new Homogeneous2D().from_polar(radius, 2 * Math.PI * i / sides, 0).add_m(new Homogeneous2D(center.x, center.y, 1)); } } // Wrap the init function to set the draw_primitive type to TRIANGLE_FAN init(gl) { this.draw_primitive = gl.TRIANGLE_FAN; super.init(gl); } } class Rod extends ShapedObject { constructor({ anchor = { x: 0, y: 0 }, bob = { x: 0, y: 0 }, color = { r: 1.0, g: 0.0, b: 0.0, a: 1.0 } } = {}) { super({ color: color }); // Set the object's vertices this.vertices = [new Homogeneous2D(anchor.x, anchor.y, 1), new Homogeneous2D(bob.x, bob.y, 1)] } // Wrap the init function to set the draw_primitive type to LINES init(gl) { this.draw_primitive = gl.LINES; super.init(gl); } } class Anchor extends ShapedObject { constructor({ center = { x: 0, y: 0 }, color = { r: 0.0, g: 1.0, b: 0.0, a: 1.0 } } = {}) { super({ color: color }); // Set the object's vertices this.vertices = [new Homogeneous2D(center.x, center.y, 1)]; } // Wrap the init function to set the draw_primitive type to POINTS init(gl) { this.draw_primitive = gl.POINTS; super.init(gl); } } // This doesn't need to extend ShapedObject, but I love the symmetry class Pendulum extends ShapedObject { constructor({ angle = 60, length = PEN_LENGTH, radius = BOB_RADIUS } = {}) { super(); this.angle_initial = angle; this.angle = angle; this.period = Math.sqrt(9.81 / length); // define where anchor and bob are var anchor = { x: 0, y: 0 }, bob = { x: 0, y: -length }; // create the components this.components = [ new Rod({ anchor: anchor, bob: bob }), new Anchor({ center: anchor }), new Polygon({ sides: 6, radius: radius, center: bob }) ]; } // Initialize the pendulum init(gl) { // initialize the components for (var component of this.components) { component?.init(gl); } // start the clock this.t_prev = Date.now(); } // Draw the pendulum draw(gl, modelMatrix, u_ModelMatrix) { // Rotate the pendulum modelMatrix.setIdentity(); modelMatrix.rotate(this.angle, 0, 0, 1); // Draw each component for (var component of this.components) { component?.draw(gl, modelMatrix, u_ModelMatrix); } } // Tick the pendulum (update and perform movement) tick() { if (REAL_PENDULUM_MODE) { var now = Date.now(), elapsed = (now - this.t_prev) / 1000 * this.period; this.angle = this.angle_initial * Math.cos(elapsed); } else { var now = Date.now(), elapsed = now - this.t_prev; this.t_prev = now; this.angle = (this.angle + (A_VELOCITY * elapsed / 1000)) % 360; } } }