Skip to content

Commit

Permalink
Add tangent vector to parametric curve
Browse files Browse the repository at this point in the history
  • Loading branch information
kzmath committed Jan 14, 2025
1 parent 418ae29 commit 6e3036c
Showing 1 changed file with 43 additions and 22 deletions.
65 changes: 43 additions & 22 deletions parametric-curve.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function parametricCurveApp() {
const margin = 15;
const axSize = (width - 4 * margin) / 2;

const app = new C5({ width: width, height: axSize + 2 * margin});
const app = new C5({ width: width, height: axSize + 2 * margin });

const ax1 = app.addAxis();
ax1.setCrop(margin, margin, margin + axSize, margin + axSize);
Expand All @@ -130,17 +130,24 @@ function parametricCurveApp() {

// Functions to be applied (maps from R to R^2)
const circleMap = (t) => [Math.cos(t), Math.sin(t)];
const circleMap2 = (t) => [Math.cos(t + t**2/10), Math.sin(t+t**2/10)];
const circleMapDerivative = (t) => [-Math.sin(t), Math.cos(t)];

const circleMap2 = (t) => [Math.cos(t + t**2/10), Math.sin(t + t**2/10)];
const circleMap2Derivative = (t) => [-Math.sin(t + t**2/10) * (1 + t/5), Math.cos(t + t**2/10) * (1 + t/5)];

const spiralMap = (t) => [t * Math.cos(t)/2, t * Math.sin(t)/2];
const spiralMapDerivative = (t) => [(Math.cos(t) - t * Math.sin(t))/2, (Math.sin(t) + t * Math.cos(t))/2];

const lissajousMap = (t) => [Math.sin(2 * t), Math.sin(3 * t)];
const lissajousMapDerivative = (t) => [2 * Math.cos(2 * t), 3 * Math.cos(3 * t)];

app.functionName = "circleMap";

app.funcs = {
"circleMap": { func: circleMap, latex: "f(t) = (\\cos(t), \\sin(t))" },
"circleMap2": { func: circleMap2, latex: "f(t) = (\\cos(t + t^2/10), \\sin(t + t^2/10))" },
"spiralMap": { func: spiralMap, latex: "f(t) = (t \\cos(t)/2, t \\sin(t))/2" },
"lissajousMap": { func: lissajousMap, latex: "f(t) = (\\sin(2t), \\sin(3t))" }
"circleMap": { func: circleMap, derivative: circleMapDerivative, latex: "f(t) = (\\cos(t), \\sin(t))" },
"circleMap2": { func: circleMap2, derivative: circleMap2Derivative, latex: "f(t) = (\\cos(t + t^2/10), \\sin(t + t^2/10))" },
"spiralMap": { func: spiralMap, derivative: spiralMapDerivative, latex: "f(t) = (t \\cos(t)/2, t \\sin(t))/2" },
"lissajousMap": { func: lissajousMap, derivative: lissajousMapDerivative, latex: "f(t) = (\\sin(2t), \\sin(3t))" }
}

// Toggle for 3D mode
Expand All @@ -151,28 +158,24 @@ function parametricCurveApp() {
}
app.setCaption("Mapping: " + app.katexM(app.funcs[app.functionName].latex));

for (const k in app.funcs) {
app.addHTMLButton(app.katexM(app.funcs[k].latex), (app) => {app.functionName = k})
}
//
//app.addHTMLButton(app.katexM("f(t) = (\\cos(t), \\sin(t))"), () => { app.functionName = "circleMap" });
//app.addHTMLButton(app.katexM("f(t) = (t \\cos(t)/2, t \\sin(t)/2)"), () => { app.functionName = "spiralMap" });
//app.addHTMLButton(app.katexM("f(t) = (\\sin(2t), \\sin(3t))"), () => { app.functionName = "lissajousMap" });
//
for (const k in app.funcs) {
app.addHTMLButton(app.katexM(app.funcs[k].latex), (app) => { app.functionName = k });
}

// Button to toggle 3D mode
app.addHTMLButton("Toggle Graph Mode", (app) => {
app.is3DMode = !app.is3DMode;
});

app.draw = function () {
app.debugInfo("function name", app.functionName)
app.f = app.funcs[app.functionName].func;
app.debugInfo("function name", app.functionName);
app.f = app.funcs[app.functionName].func;
app.fDerivative = app.funcs[app.functionName].derivative;

ax1.setLimits(0, app.R, -2, 2); // Left panel: x range (0, 2π), y range (-2, 2)
ax1.setLimits(0, app.R, -2, 2); // Left panel: x range (0, 2π), y range (-2, 2)
// Pin the dot A to y = 0
A.y = 0;
A.x = clamp(A.x, 0, app.R);

A.x = clamp(A.x, 0, app.R);

ax1.beginClip();

Expand All @@ -188,7 +191,7 @@ function parametricCurveApp() {
ax2.beginClip();

if (app.is3DMode) {
ax2.setLimits(-2, 4*Math.PI, -4, 4); // Left panel: x range (0, 2π), y range (-2, 2)
ax2.setLimits(-2, 4*Math.PI, -4, 4); // Left panel: x range (0, 2π), y range (-2, 2)
// Draw 3D axes in the right panel
draw3DAxes(ax2);

Expand All @@ -206,9 +209,19 @@ function parametricCurveApp() {
const AProjected = project3DTo2D(...A3D);

ax2.drawDot(...AProjected, 6, { label: "f(A)", fillStyle: c3 });

// Draw tangent vector in 3D mode
const tangent3D = [A.x, ...app.f(A.x)];
const tangentDerivative3D = app.fDerivative(A.x);
const tangentEnd3D = [tangent3D[0] + tangentDerivative3D[0], tangent3D[1] + tangentDerivative3D[1], tangent3D[2] + tangentDerivative3D[1]];
const tangentEndProjected = project3DTo2D(...tangentEnd3D);

ax2.strokePath([AProjected[0], AProjected[1], tangentEndProjected[0], tangentEndProjected[1]], { strokeStyle: c4, lineWidth: 2 });
ax2.drawDot(tangentEndProjected[0], tangentEndProjected[1], 6, { fillStyle: c4 });

} else {
ax2.setLimits(-4, 4, -4, 4); // Left panel: x range (0, 2π), y range (-2, 2)
ax2.axisGrid();
ax2.setLimits(-4, 4, -4, 4); // Left panel: x range (0, 2π), y range (-2, 2)
ax2.axisGrid();

// Map the t range to 2D using f(t)
const curve2D = float2DApply(app.f, tRange);
Expand All @@ -219,6 +232,13 @@ function parametricCurveApp() {
// Draw the function values as dots on the curve
const [xA, yA] = app.f(A.x);
ax2.drawDot(xA, yA, 6, { label: "f(A)", fillStyle: c3 });

// Draw tangent vector in 2D mode
const tangentDerivative = app.fDerivative(A.x);
const tangentEnd = [xA + tangentDerivative[0], yA + tangentDerivative[1]];

ax2.strokePath([xA, yA, tangentEnd[0], tangentEnd[1]], { strokeStyle: c4, lineWidth: 2 });
ax2.drawDot(tangentEnd[0], tangentEnd[1], 6, { fillStyle: c4 });
}

ax2.endClip();
Expand All @@ -228,4 +248,5 @@ function parametricCurveApp() {
return app;
}


parametricCurveApp();

0 comments on commit 6e3036c

Please sign in to comment.