楕円の中心から引いた直線と、楕円の円周とが交わる座標を正しく取得する。
Last active
February 5, 2019 04:49
-
-
Save sounisi5011/2dcb436301a06b98ecc03c603f984dfb to your computer and use it in GitHub Desktop.
楕円の円周上の座標を求める
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang=en> | |
<meta charset=utf-8> | |
<meta name=viewport content="width=device-width,initial-scale=1"> | |
<meta name=format-detection content="telephone=no,email=no,address=no"> | |
<title>楕円の円周の座標を求める</title> | |
<h1>楕円の円周の座標を求める</h1> | |
<p> | |
<input id=angle type=number value=0>°<br> | |
radiusX: <input id=rx type=number min=1 value=100><br> | |
radiusY: <input id=ry type=number min=1 value=50> | |
</p> | |
<svg viewBox="-300 -200 600 400" width="600" height="400"> | |
<line id="line" x1="0" y1="0" x2="1000" y2="0" stroke="black"/> | |
<ellipse id="ellipse" cx="0" cy="0" stroke="blue" fill="none"/> | |
<circle id="point" r="4" stroke="red" fill="none"/> | |
</svg> | |
<script src="./main.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 楕円の円周上の座標を返す | |
* @param {number} degree 角度 | |
* @param {number} radiusX 横半径 | |
* @param {number} radiusY 縦半径 | |
* @returns {x: number, y: number} 円周上の座標 | |
* @see https://qiita.com/yoshiweb/items/e88ad2f720d102d1103b#%E6%A5%95%E5%86%86%E3%81%AE%E5%86%86%E5%91%A8%E4%B8%8A%E3%81%AE-x-y-%E5%BA%A7%E6%A8%99%E3%82%92%E8%BF%94%E3%81%99 | |
* @see https://open.mixi.jp/user/35955404/diary/1943102675 | |
*/ | |
function getOvalPosition(degree, radiusX, radiusY) { | |
const radian = deg2rad(degree); | |
/* | |
* Note: 90 < degree <= 270の範囲で座標が反転してしまう。原因は不明。 | |
* TODO: 条件分岐が不要な式に直す | |
*/ | |
const x = 1 / Math.sqrt(((1 / radiusX) ** 2) + ((Math.tan(radian) / radiusY) ** 2)); | |
const y = x * Math.tan(radian); | |
return { | |
x: (90 < degree && degree <= 270) ? -x : x, | |
y: (90 < degree && degree <= 270) ? -y : y, | |
}; | |
} | |
function deg2rad(degree) { | |
return normalizeDeg(degree) * (Math.PI / 180); | |
} | |
function rad2deg(radian) { | |
return normalizeDeg(radian * (180 / Math.PI)); | |
} | |
function normalizeDeg(degree) { | |
return ((Number.parseFloat(degree) || 0) % 360 + 360) % 360; | |
} | |
function main() { | |
const angleInputElem = document.getElementById('angle'); | |
const rxInputElem = document.getElementById('rx'); | |
const ryInputElem = document.getElementById('ry'); | |
const lineElem = document.getElementById('line'); | |
const ellipseElem = document.getElementById('ellipse'); | |
const pointElem = document.getElementById('point'); | |
const state = { | |
angle: angleInputElem.value, | |
rx: rxInputElem.value, | |
ry: ryInputElem.value, | |
}; | |
const render = (newState = state) => { | |
const data = Object.assign(state, newState); | |
const [degree, rx, ry] = [ | |
normalizeDeg(data.angle), | |
Number.parseFloat(data.rx) || 1, | |
Number.parseFloat(data.ry) || 1, | |
]; | |
const pointPos = getOvalPosition( | |
degree, | |
rx, | |
ry, | |
); | |
lineElem.setAttributeNS(null, 'transform', `rotate(${degree})`); | |
ellipseElem.setAttributeNS(null, 'rx', rx); | |
ellipseElem.setAttributeNS(null, 'ry', ry); | |
pointElem.setAttributeNS(null, 'cx', pointPos.x); | |
pointElem.setAttributeNS(null, 'cy', pointPos.y); | |
}; | |
angleInputElem.addEventListener('input', event => { | |
render({ | |
angle: event.currentTarget.value, | |
}); | |
}); | |
angleInputElem.addEventListener('blur', event => { | |
event.currentTarget.value = normalizeDeg(event.currentTarget.value); | |
}); | |
rxInputElem.addEventListener('input', event => { | |
render({ | |
rx: event.currentTarget.value, | |
}); | |
}); | |
ryInputElem.addEventListener('input', event => { | |
render({ | |
ry: event.currentTarget.value, | |
}); | |
}); | |
render(); | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment