To find out where y
intersects with x
on the surface of the circle i use Math.sqrt(radius * radius - Math.pow( x, 2))
.
How do I find out where y
intersects with x
on the surface of a cycloid?
In the snippets bellow I have a circle and a cycloid. For the circle I am able to get the value of y
from x
with const y = Math.sqrt(radius * radius - Math.pow(radius - x, 2))
. I want to be able to do the same for the cycloid and replace const y = 0
with a working solution.
(() => {
const inputX = document.getElementById('xCircle')
inputX.addEventListener('input', (e) => {
const x = e.target.value
ctx.clearRect(0, 0, radius, radius)
drawCurve()
drawIntersection(x)
})
const radius = 200
const canvas = document.getElementById('circle')
canvas.width = radius
canvas.height = radius
const ctx = canvas.getContext('2d')
const drawCurve = () => {
ctx.beginPath()
ctx.arc(radius, 0, radius, 0, Math.PI * 2)
ctx.stroke()
}
drawCurve()
const drawIntersection = (x) => {
const y = Math.sqrt(radius * radius - Math.pow(radius - x, 2))
document.getElementById('yCircle').textContent = Math.round(y)
ctx.beginPath()
ctx.moveTo(x, radius)
ctx.lineTo(x, y)
ctx.lineTo(radius, y)
ctx.stroke()
}
drawIntersection(inputX.value)
})();
(() => {
const inputX = document.getElementById('xCycloid')
inputX.addEventListener('input', (e) => {
const x = e.target.value
ctx.clearRect(0, 0, canvasW, canvasH)
drawCurve()
drawIntersection(x)
})
const radius = 100
const canvas = document.getElementById('cycloid')
const canvasW = radius * Math.PI, canvasH = radius * 2
canvas.width = canvasW
canvas.height = canvasH
const ctx = canvas.getContext('2d')
const drawCurve = () => {
ctx.beginPath()
for (let t = 0; t <= Math.PI; t += 0.01) {
const x = radius * (t - Math.sin(t))
const y = radius * (1 - Math.cos(t))
ctx.lineTo(x, y)
}
ctx.stroke()
}
drawCurve()
const drawIntersection = (x) => {
const y = 0
document.getElementById('yCycloid').textContent = Math.round(y)
ctx.beginPath()
ctx.moveTo(x, canvasH)
ctx.lineTo(x, y)
ctx.lineTo(canvasW, y)
ctx.stroke()
}
drawIntersection(inputX.value)
})();
canvas {
border: 1px solid
}
<canvas id="circle"></canvas>
<form>
<label>x:<input id="xCircle" type="number" value="30"></label>
y:<span id="yCircle"></span>
</form>
<br>
<canvas id="cycloid"></canvas>
<form>
<label>x:<input id="xCycloid" type="number" value="40"></label>
y:<span id="yCycloid"></span>
</form>
You have to solve approximatively (numerically) the equation
t - Math.sin(t) == x/radius
to get t
for x
, then substitute t
in y = radius * (1 - Math.cos(t))
.
Solving the equation can only be done iteratively, here's a possible implementation based on Newton's method
let t = Math.PI/2; // initial solution (half value)
let converged = false;
for(let iter = 0; iter < 100; iter++){
// tNext = Math.sin(t) + x/radius; // alternative, simpler fixed point iteration
const tNext = t - (t - Math.sin(t) - x/radius)/(1 - Math.cos(t)); // Newton's method
const delta = Math.abs(tNext - t);
t = tNext;
if(delta < 1e-8){
converged = true;
break;
}
}
if(!converged){
throw new Error('No solution found');
}
const y = radius * (1- Math.cos(t));
Here's your snippet with that code inserted:
(() => {
const inputX = document.getElementById('xCircle')
inputX.addEventListener('input', (e) => {
const x = e.target.value
ctx.clearRect(0, 0, radius, radius)
drawCurve()
drawIntersection(x)
})
const radius = 200
const canvas = document.getElementById('circle')
canvas.width = radius
canvas.height = radius
const ctx = canvas.getContext('2d')
const drawCurve = () => {
ctx.beginPath()
ctx.arc(radius, 0, radius, 0, Math.PI * 2)
ctx.stroke()
}
drawCurve()
const drawIntersection = (x) => {
const y = Math.sqrt(radius * radius - Math.pow(radius - x, 2))
document.getElementById('yCircle').textContent = Math.round(y)
ctx.beginPath()
ctx.moveTo(x, radius)
ctx.lineTo(x, y)
ctx.lineTo(radius, y)
ctx.stroke()
}
drawIntersection(inputX.value)
})();
(() => {
const inputX = document.getElementById('xCycloid')
inputX.addEventListener('input', (e) => {
const x = e.target.value
ctx.clearRect(0, 0, canvasW, canvasH)
drawCurve()
drawIntersection(x)
})
const radius = 100
const canvas = document.getElementById('cycloid')
const canvasW = radius * Math.PI, canvasH = radius * 2
canvas.width = canvasW
canvas.height = canvasH
const ctx = canvas.getContext('2d')
const drawCurve = () => {
ctx.beginPath()
for (let t = 0; t <= Math.PI; t += 0.01) {
const x = radius * (t - Math.sin(t))
const y = radius * (1 - Math.cos(t))
ctx.lineTo(x, y)
}
ctx.stroke()
}
drawCurve()
const drawIntersection = (x) => {
let t = Math.PI/2;
let converged = false;
for(let iter = 0; iter < 100; iter++){
const tNext = t - (t - Math.sin(t) - x/radius)/(1 - Math.cos(t)); // Newton's method
// tNext = Math.sin(t) + x/radius; // simple fixed point iteration
const delta = Math.abs(tNext - t);
t = tNext;
if(delta < 1e-8){
converged = true;
break;
}
}
if(!converged){
throw new Error('No solution found');
}
const y = radius * (1- Math.cos(t));
document.getElementById('yCycloid').textContent = Math.round(y)
ctx.beginPath()
ctx.moveTo(x, canvasH)
ctx.lineTo(x, y)
ctx.lineTo(canvasW, y)
ctx.stroke()
}
drawIntersection(inputX.value)
})();
canvas {
border: 1px solid
}
<canvas id="circle"></canvas>
<form>
<label>x:<input id="xCircle" type="number" value="30"></label>
y:<span id="yCircle"></span>
</form>
<br>
<canvas id="cycloid"></canvas>
<form>
<label>x:<input id="xCycloid" type="number" value="40"></label>
y:<span id="yCycloid"></span>
</form>