【SvelteでHTMLアプリ開発】テオ・ヤンセン機構をSvelteアプリで再現してみる
※ 当ページには【広告/PR】を含む場合があります。
2022/05/14
テオ・ヤンセン機構の原理
const links: any = {
a: 38, b: 41.5, c: 39.3, d: 40.1, e: 55.8, f: 39.4,
g: 36.7, h: 65.7, i: 49, j: 50, k: 61.9, l: 7.8,
m: 15
};
const points: any = {
O: [0.0, 0.0], A: [0.0, 0.0], B: [-links.a, -links.l], C: [0.0, 0.0],
D: [0.0, 0.0], E: [0.0, 0.0], F: [0.0, 0.0], G: [0.0, 0.0]
};
C→D→E→F→G
テオ・ヤンセン機構のシミュレーション(一脚)
Svelteコードの実装
<script lang="ts">
import { onMount } from 'svelte';
//👇SVGのビューポート設定
const view = {
w: 300, h: 300,
t: -50, l: -120, b: 150, r: 180,
};
const period = 2; //👈周期[秒]
const ticks = 300;
const timerPeriod = period * 1000 / ticks;
let timerCount = 0;
const links: any = {
a: 38, b: 41.5, c: 39.3, d: 40.1, e: 55.8, f: 39.4,
g: 36.7, h: 65.7, i: 49, j: 50, k: 61.9, l: 7.8,
m: 15
};
const points: any = {
O: [0.0, 0.0], A: [0.0, 0.0], B: [-links.a, -links.l], C: [0.0, 0.0],
D: [0.0, 0.0], E: [0.0, 0.0], F: [0.0, 0.0], G: [0.0, 0.0]
};
//👇座標系は$ラベル構文でリアクティブに更新する
$: {
let theta_ab: number, theta_bc: number, theta_de: number, theta_df: number;
let xc: number, yc: number, AB: number, DE: number;
points.A = [
links.m * Math.sin(2*Math.PI*(timerCount / ticks)),
links.m * Math.cos(2*Math.PI*(timerCount / ticks))
];
points.B = [-links.a, -links.l];
AB = Math.sqrt((links.a + points.A[0])*(links.a + points.A[0]) + (links.l + points.A[1])*(links.l + points.A[1]));
xc = (AB*AB + links.b*links.b - links.j*links.j) / (2.0*AB);
yc = Math.sqrt( links.b*links.b - xc*xc );
theta_ab = Math.atan2(points.A[1] - points.B[1], points.A[0] - points.B[0]);
points.C = [
-links.a + xc*Math.cos(theta_ab) + yc*Math.cos(theta_ab+Math.PI/2),
-links.l + xc*Math.sin(theta_ab) + yc*Math.sin(theta_ab+Math.PI/2)
];
xc = (links.b*links.b + links.d*links.d - links.e*links.e) / (2.0*links.b);
yc = Math.sqrt( links.d*links.d - xc*xc );
theta_bc = Math.atan2(points.C[1] - points.B[1], points.C[0] - points.B[0]);
points.E = [
points.B[0] + xc*Math.cos(theta_bc) + yc*Math.cos(theta_bc+Math.PI/2),
points.B[1] + xc*Math.sin(theta_bc) + yc*Math.sin(theta_bc+Math.PI/2)
];
xc = (AB*AB + links.c*links.c - links.k*links.k) / (2.0*AB);
yc = Math.sqrt( links.c*links.c - xc*xc );
points.D = [
points.B[0] + xc*Math.cos(theta_ab) + yc*Math.cos(theta_ab-Math.PI/2),
points.B[1] + xc*Math.sin(theta_ab) + yc*Math.sin(theta_ab-Math.PI/2)
];
DE = Math.sqrt((points.D[0] - points.E[0])*(points.D[0] - points.E[0]) + (points.D[1] - points.E[1])*(points.D[1] - points.E[1]));
xc = (DE*DE + links.g*links.g - links.f*links.f) / (2.0*DE);
yc = Math.sqrt( links.g*links.g - xc*xc );
theta_de = Math.atan2(points.E[1] - points.D[1], points.E[0] - points.D[0]);
points.F = [
points.D[0] + xc*Math.cos(theta_de) + yc*Math.cos(theta_de+Math.PI/2),
points.D[1] + xc*Math.sin(theta_de) + yc*Math.sin(theta_de+Math.PI/2)
];
xc = (links.g*links.g + links.i*links.i - links.h*links.h) / (2.0*links.g);
yc = Math.sqrt( links.i*links.i - xc*xc );
theta_df = Math.atan2(points.F[1] - points.D[1], points.F[0] - points.D[0]);
points.G = [
points.D[0] + xc*Math.cos(theta_df) + yc*Math.cos(theta_df+Math.PI/2),
points.D[1] + xc*Math.sin(theta_df) + yc*Math.sin(theta_df+Math.PI/2)
];
}
onMount(() => {
const interval = setInterval(() => {
timerCount = timerCount >= ticks - 1 ? 0 : timerCount + 1;
}, timerPeriod);
return () => clearInterval(interval);
});
</script>
<svg width="{view.w}" height="{view.h}" viewBox='{view.l} {view.t} {view.r} {view.b}'>
<g>
<path class="OACBEC" d="
M 0 0
L {points.A[0]} {-points.A[1]}
L {points.C[0]} {-points.C[1]}
L {points.B[0]} {-points.B[1]}
L {points.E[0]} {-points.E[1]}
L {points.C[0]} {-points.C[1]}
"/>
<path class="EFGDF" d="
M {points.E[0]} {-points.E[1]}
L {points.F[0]} {-points.F[1]}
L {points.G[0]} {-points.G[1]}
L {points.D[0]} {-points.D[1]}
L {points.F[0]} {-points.F[1]}
"/>
<path class="ADB" d="
M {points.A[0]} {-points.A[1]}
L {points.D[0]} {-points.D[1]}
L {points.B[0]} {-points.B[1]}
"/>
<path class="Oal" d="
M 0 0
L 0 {links.l}
L {-links.a} {links.l}
"/>
</g>
<g>
<circle class="O" cx="0" cy="0" r="2" />
<circle cx="{points.A[0]}" cy="{-points.A[1]}" r="3" />
<circle cx="{points.B[0]}" cy="{-points.B[1]}" r="3" />
<circle cx="{points.C[0]}" cy="{-points.C[1]}" r="3" />
<circle cx="{points.D[0]}" cy="{-points.D[1]}" r="3" />
<circle cx="{points.E[0]}" cy="{-points.E[1]}" r="3" />
<circle cx="{points.F[0]}" cy="{-points.F[1]}" r="3" />
<circle cx="{points.G[0]}" cy="{-points.G[1]}" r="3" />
</g>
<g>
<text x="0" y="0" class="point">O</text>
<text x="{points.A[0]}" y="{-points.A[1]}" class="point">A</text>
<text x="{points.B[0]}" y="{-points.B[1]}" class="point">B</text>
<text x="{points.C[0]}" y="{-points.C[1]}" class="point">C</text>
<text x="{points.D[0]}" y="{-points.D[1]}" class="point">D</text>
<text x="{points.E[0]}" y="{-points.E[1]}" class="point">E</text>
<text x="{points.F[0]}" y="{-points.F[1]}" class="point">F</text>
<text x="{points.G[0]}" y="{-points.G[1]}" class="point">G</text>
</g>
<g>
<text x="{points.B[0]/2}" y="{-points.B[1]/2}" class="link">a</text>
<text x="{(points.B[0] + points.C[0])/2}" y="{-(points.B[1] + points.C[1])/2}" class="link">b</text>
<text x="{(points.B[0] + points.D[0])/2}" y="{-(points.B[1] + points.D[1])/2}" class="link">c</text>
<text x="{(points.B[0] + points.E[0])/2}" y="{-(points.B[1] + points.E[1])/2}" class="link">d</text>
<text x="{(points.C[0] + points.E[0])/2}" y="{-(points.C[1] + points.E[1])/2}" class="link">e</text>
<text x="{(points.E[0] + points.F[0])/2}" y="{-(points.E[1] + points.F[1])/2}" class="link">f</text>
<text x="{(points.D[0] + points.F[0])/2}" y="{-(points.D[1] + points.F[1])/2}" class="link">g</text>
<text x="{(points.F[0] + points.G[0])/2}" y="{-(points.F[1] + points.G[1])/2}" class="link">h</text>
<text x="{(points.D[0] + points.G[0])/2}" y="{-(points.D[1] + points.G[1])/2}" class="link">i</text>
<text x="{(points.A[0] + points.C[0])/2}" y="{-(points.A[1] + points.C[1])/2}" class="link">j</text>
<text x="{(points.A[0] + points.D[0])/2}" y="{-(points.A[1] + points.D[1])/2}" class="link">k</text>
<text x="0" y="{-points.B[1]}" class="link">l</text>
<text x="{points.A[0]/2}" y="{-points.A[1]/2}" class="link">m</text>
</g>
</svg>
<style lang="scss">
svg {
width: 300px;
height: auto;
path {
&.OACBEC {
stroke: blue;
stroke-width: 1.2;
fill: none;
}
&.EFGDF {
stroke: red;
stroke-width: 1.2;
fill: none;
}
&.ADB {
stroke: rgb(255, 153, 0);
stroke-width: 1.2;
fill: none;
}
&.Oal {
stroke: rgb(55, 100, 41);
stroke-width: 1.2;
fill: none;
}
}
circle {
fill:none;
stroke:#888888;
stroke-width:2;
&.O {
fill:rgb(118, 118, 49);
stroke:none;
}
}
text {
&.link {font-size: 7px}
&.point {font-size: 10px}
}
}
</style>
参考サイト
記事を書いた人
ナンデモ系エンジニア
これからの"地方格差"なきプログラミング教育とは何かを考えながら、 地方密着型プログラミング学習関連テーマの記事を不定期で独自にブログ発信しています。
カテゴリー