【SvelteでHTMLアプリ開発】テオ・ヤンセン機構の多足歩行をシミュレートしてみる
※ 当ページには【広告/PR】を含む場合があります。
2022/05/15
テオ・ヤンセン機構(6脚版)のシミュレーション
ソースコード
App.svelte
LegMotion.svelte
util.ts
<script lang="ts">
import { onMount } from 'svelte';
import { updatePoints, TPoints, links } from './util';
import LegMotion from './LegMotion.svelte';
const period = 2; //👈周期[秒]
const ticks = 300;
const timerPeriod = period * 1000 / ticks;
let timerCount = 0;
//👇6脚分の座標点セットを定義
const pointGroup: TPoints[] = [
{
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], sign: 1
},
{
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], sign: 1
},
{
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], sign: 1
},
{
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], sign: -1
},
{
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], sign: -1
},
{
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], sign: -1
}
];
//👇6脚の座標を個別に更新
$: {
pointGroup[0] = updatePoints(timerCount/ticks, pointGroup[0]);
pointGroup[1] = updatePoints(timerCount/ticks + 1/3, pointGroup[1]);
pointGroup[2] = updatePoints(timerCount/ticks + 2/3, pointGroup[2]);
pointGroup[3] = updatePoints(timerCount/ticks, pointGroup[3]);
pointGroup[4] = updatePoints(timerCount/ticks + 1/3, pointGroup[4]);
pointGroup[5] = updatePoints(timerCount/ticks + 2/3, pointGroup[5]);
}
onMount(() => {
const interval = setInterval(() => {
timerCount = timerCount > ticks ? 0 : timerCount + 1;
}, timerPeriod);
return () => clearInterval(interval);
});
</script>
//👇各脚をLegMotionコンポーネントとして描画を更新
{#each pointGroup as point, index}
<LegMotion point={point} index={index}/>
{/each}
LegMotion.svelte
sign
<script lang="ts">
import type { TPoints, links } from './util';
const view = {
w: 600, h: 300,
t: -50, l: -120, b: 150, r: 480,
};
const colors: string[] = ['red','blue','green','red','blue','green'];
//👇コンポーネントへの属性入力
export let point: TPoints;
export let index: number;
//👇css変数を利用する
let cssVarStyles = `--leg-color:${colors[index]};`;
</script>
<svg width="{view.w}" height="{view.h}" viewBox='{view.l} {view.t} {view.r} {view.b}' style="{cssVarStyles}">
<g>
<path d="
M 0 0
L {point.sign*point.A[0]} {-point.A[1]}
L {point.sign*point.C[0]} {-point.C[1]}
L {point.sign*point.B[0]} {-point.B[1]}
L {point.sign*point.E[0]} {-point.E[1]}
L {point.sign*point.C[0]} {-point.C[1]}
"/>
<path d="
M {point.sign*point.E[0]} {-point.E[1]}
L {point.sign*point.F[0]} {-point.F[1]}
L {point.sign*point.G[0]} {-point.G[1]}
L {point.sign*point.D[0]} {-point.D[1]}
L {point.sign*point.F[0]} {-point.F[1]}
"/>
<path d="
M {point.sign*point.A[0]} {-point.A[1]}
L {point.sign*point.D[0]} {-point.D[1]}
L {point.sign*point.B[0]} {-point.B[1]}
"/>
</g>
<g>
<circle class="O" cx="0" cy="0" r="2" />
<circle cx="{point.sign*point.A[0]}" cy="{-point.A[1]}" r="3" />
<circle cx="{point.sign*point.B[0]}" cy="{-point.B[1]}" r="3" />
<circle cx="{point.sign*point.C[0]}" cy="{-point.C[1]}" r="3" />
<circle cx="{point.sign*point.D[0]}" cy="{-point.D[1]}" r="3" />
<circle cx="{point.sign*point.E[0]}" cy="{-point.E[1]}" r="3" />
<circle cx="{point.sign*point.F[0]}" cy="{-point.F[1]}" r="3" />
<circle cx="{point.sign*point.G[0]}" cy="{-point.G[1]}" r="3" />
</g>
</svg>
<style lang="scss">
svg {
position: absolute;
top: 0;
left: 0;
width: 600px;
height: auto;
path {
stroke: var(--leg-color);
stroke-width: 1.2;
fill: none;
}
circle {
fill:none;
stroke:#888888;
stroke-width:2;
&.O {
fill:rgb(118, 118, 49);
stroke:none;
}
}
}
</style>
util.ts
export 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
};
export type TPoints = {
O: number[], A: number[], B: number[], C: number[],
D: number[], E: number[], F: number[], G: number[],
sign: number
}
export function updatePoints(theta: number, prev: TPoints): TPoints {
let theta_ab: number, theta_bc: number, theta_de: number, theta_df: number;
let xc: number, yc: number, AB: number, DE: number;
prev.A = [
links.m * Math.sin(2*Math.PI*prev.sign*theta),
links.m * Math.cos(2*Math.PI*prev.sign*theta)
];
prev.B = [-links.a, -links.l];
AB = Math.sqrt((links.a + prev.A[0])*(links.a + prev.A[0]) + (links.l + prev.A[1])*(links.l + prev.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(prev.A[1] - prev.B[1], prev.A[0] - prev.B[0]);
prev.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(prev.C[1] - prev.B[1], prev.C[0] - prev.B[0]);
prev.E = [
prev.B[0] + xc*Math.cos(theta_bc) + yc*Math.cos(theta_bc+Math.PI/2),
prev.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 );
prev.D = [
prev.B[0] + xc*Math.cos(theta_ab) + yc*Math.cos(theta_ab-Math.PI/2),
prev.B[1] + xc*Math.sin(theta_ab) + yc*Math.sin(theta_ab-Math.PI/2)
];
DE = Math.sqrt((prev.D[0] - prev.E[0])*(prev.D[0] - prev.E[0]) + (prev.D[1] - prev.E[1])*(prev.D[1] - prev.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(prev.E[1] - prev.D[1], prev.E[0] - prev.D[0]);
prev.F = [
prev.D[0] + xc*Math.cos(theta_de) + yc*Math.cos(theta_de+Math.PI/2),
prev.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(prev.F[1] - prev.D[1], prev.F[0] - prev.D[0]);
prev.G = [
prev.D[0] + xc*Math.cos(theta_df) + yc*Math.cos(theta_df+Math.PI/2),
prev.D[1] + xc*Math.sin(theta_df) + yc*Math.sin(theta_df+Math.PI/2)
];
return prev;
}
記事を書いた人
ナンデモ系エンジニア
これからの"地方格差"なきプログラミング教育とは何かを考えながら、 地方密着型プログラミング学習関連テーマの記事を不定期で独自にブログ発信しています。
カテゴリー