UNPKG

plotboilerplate

Version:

A simple javascript plotting boilerplate for 2d stuff.

111 lines (98 loc) 3.42 kB
/** * A wrapper for Lissajous figure params. * * @author Ikaros Kappler * @date 2018-11-22 * @modified 2025-10-29 Ported to typescript from demo 13-lissajous. * @version 1.0.0 */ import { Vertex } from "../Vertex"; export class LissajousFigure { freqA: number; freqB: number; phaseA: number; phaseB: number; /** * Create a new figure with the given settings. * @param {number} freqA - The 'horizontal' frequency. * @param {number} freqB - The 'vertical' frequency. * @param {number} phaseA - The 'horizonal' phase shift. * @param {number} phaseB - The 'vertical' phase shift. */ constructor(freqA: number, freqB: number, phaseA: number, phaseB: number) { this.freqA = freqA; this.freqB = freqB; this.phaseA = phaseA; this.phaseB = phaseB; } /** * Get the point at the given abstract time. * * The result is periodic in 0..TWO_PI. * * @param {number} t - The timing value (for example milliseconds). * @returns {Vertex} The x-y-position on the Lissajous figure at the given time. */ public getPointAt(t: number): Vertex { return new Vertex(Math.sin(this.phaseA + this.freqA * t), Math.sin(this.phaseB + this.freqB * t)); } public toPolyLine(stepSize: number): Array<Vertex> { const polyLine: Array<Vertex> = []; let pA = new Vertex(0, 0); stepSize = Math.abs(stepSize); for (var t = 0; t <= 2 * Math.PI; t += stepSize) { pA = this.getPointAt(t); polyLine.push(pA.clone()); } return polyLine; } public toQuadraticBezierApproximation( stepSize: number // scale: number // alternating: boolean ): Array<[Vertex, Vertex, Vertex] | [Vertex, Vertex]> { const result: Array<[Vertex, Vertex, Vertex] | [Vertex, Vertex]> = []; let pA = new Vertex(0, 0); let pB = new Vertex(0, 0); stepSize = Math.abs(stepSize); let p1 = new Vertex(0, 0); let dx1 = this.freqA; let dy1 = this.freqB; pA = this.getPointAt(stepSize); let x2, y2, dx2, dy2, det, x3, y3; var i = 0; for (var t = stepSize; t <= 2 * Math.PI + 2 * stepSize; t += stepSize) { x2 = Math.sin(this.phaseA + this.freqA * t); y2 = Math.sin(this.phaseB + this.freqB * t); dx2 = this.freqA * Math.cos(this.phaseA + this.freqA * t); dy2 = this.freqB * Math.cos(this.phaseB + this.freqB * t); det = dx1 * dy2 - dy1 * dx2; if (Math.abs(det) > 0.1) { x3 = ((x2 * dy2 - y2 * dx2) * dx1 - (p1.x * dy1 - p1.y * dx1) * dx2) / det; y3 = ((x2 * dy2 - y2 * dx2) * dy1 - (p1.x * dy1 - p1.y * dx1) * dy2) / det; // pB.set(scale * x2, scale * y2 * (alternating ? -1 : 1)); // pB.set(scale * x2, scale * y2); pB.set(x2, y2); // pB.set(x2, y2); if (i > 0) { // pb.draw.quadraticBezier(pA, new Vertex(scale * x3, scale * y3), pB, "rgba(0,108,255,1.0)", 2); // result.push([pA.clone(), new Vertex(scale * x3, scale * y3), pB.clone()]); result.push([pA.clone(), new Vertex(x3, y3), pB.clone()]); } } else { // pB.set(scale * x2, scale * y2); pB.set(x2, y2); if (i > 0) { // pb.draw.line(pA, pB, "rgba(0,192,192,0.8)", 2); result.push([pA.clone(), pB.clone()]); } } p1.set(x2, y2); dx1 = dx2; dy1 = dy2; pA.set(pB); i++; } // END for return result; } }