Compare commits
3 Commits
646b4b2ceb
...
53fee2bd0f
Author | SHA1 | Date | |
---|---|---|---|
53fee2bd0f | |||
fb9143f691 | |||
16d15c65de |
|
@ -95,7 +95,12 @@ interface Closer {
|
||||||
transitionProgress: number,
|
transitionProgress: number,
|
||||||
}
|
}
|
||||||
export interface HandAnimation {
|
export interface HandAnimation {
|
||||||
kind: "Linear" | "Center"
|
kind: "Linear" | "Center" | "None",
|
||||||
|
transitionBeats?: number,
|
||||||
|
}
|
||||||
|
interface HandAnimationInternal {
|
||||||
|
kind: "Linear" | "Center" | "None",
|
||||||
|
transitionProgress: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RotationAnimationSegment extends AnimationSegment {
|
export class RotationAnimationSegment extends AnimationSegment {
|
||||||
|
@ -109,16 +114,25 @@ export class RotationAnimationSegment extends AnimationSegment {
|
||||||
private readonly facing: RotationAnimationFacing;
|
private readonly facing: RotationAnimationFacing;
|
||||||
private readonly startFacing: Rotation;
|
private readonly startFacing: Rotation;
|
||||||
private readonly closer?: Closer;
|
private readonly closer?: Closer;
|
||||||
private readonly hands: Map<Hand, HandAnimation>;
|
private readonly hands: Map<Hand, HandAnimationInternal>;
|
||||||
|
|
||||||
constructor(beats: number, startPosition: DancerSetPosition, endPosition: DancerSetPosition,
|
constructor(beats: number, startPosition: DancerSetPosition, endPosition: DancerSetPosition,
|
||||||
rotation: number, around: RotationAround, facing: RotationAnimationFacing,
|
rotation: number, around: RotationAround, facing: RotationAnimationFacing,
|
||||||
closer?: CloserDuringRotation, hands?: Map<Hand, HandAnimation>) {
|
closer?: CloserDuringRotation, hands?: Map<Hand, HandAnimation>) {
|
||||||
super(beats, startPosition, endPosition);
|
super(beats, startPosition, endPosition);
|
||||||
|
|
||||||
this.hands = hands ?? new Map<Hand, HandAnimation>();
|
function convertHandAnimation(anim: HandAnimation | undefined): HandAnimationInternal {
|
||||||
if (!this.hands.has(Hand.Left)) this.hands.set(Hand.Left, {kind: "Linear"});
|
if (!anim) {
|
||||||
if (!this.hands.has(Hand.Right)) this.hands.set(Hand.Right, {kind: "Linear"});
|
return { kind: "Linear", transitionProgress: 0 };
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...anim,
|
||||||
|
transitionProgress: (anim.transitionBeats ?? 0) / beats
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.hands = new Map<Hand, HandAnimationInternal>(
|
||||||
|
[Hand.Left, Hand.Right].map(h => [h, convertHandAnimation(hands?.get(h))]));
|
||||||
|
|
||||||
this.facing = facing;
|
this.facing = facing;
|
||||||
this.xRadius = around.width / 2;
|
this.xRadius = around.width / 2;
|
||||||
|
@ -191,9 +205,17 @@ export class RotationAnimationSegment extends AnimationSegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interpolateHandOffset(progress: number, hand: Hand): Offset | undefined {
|
protected interpolateHandOffset(progress: number, hand: Hand): Offset | undefined {
|
||||||
switch (this.hands.get(hand)!.kind) {
|
const handAnim : HandAnimationInternal = this.hands.get(hand)!;
|
||||||
|
let middlePos : Offset;
|
||||||
|
switch (handAnim.kind) {
|
||||||
case "Linear":
|
case "Linear":
|
||||||
|
if (handAnim.transitionProgress === 0) {
|
||||||
return super.interpolateHandOffset(progress, hand);
|
return super.interpolateHandOffset(progress, hand);
|
||||||
|
} else if (progress < handAnim.transitionProgress) {
|
||||||
|
return super.interpolateHandOffset(progress / handAnim.transitionProgress, hand);
|
||||||
|
} else {
|
||||||
|
return super.interpolateHandOffset(1, hand);
|
||||||
|
}
|
||||||
case "Center":
|
case "Center":
|
||||||
const position = this.interpolateOffset(progress);
|
const position = this.interpolateOffset(progress);
|
||||||
const offset = {
|
const offset = {
|
||||||
|
@ -202,11 +224,32 @@ export class RotationAnimationSegment extends AnimationSegment {
|
||||||
};
|
};
|
||||||
const rotation = degreesToRadians(this.interpolateRotation(progress));
|
const rotation = degreesToRadians(this.interpolateRotation(progress));
|
||||||
|
|
||||||
return {
|
const centerPos = {
|
||||||
x: -Math.cos(rotation) * offset.x + Math.sin(rotation) * offset.y,
|
x: -Math.cos(rotation) * offset.x + Math.sin(rotation) * offset.y,
|
||||||
y: -Math.sin(rotation) * offset.x - Math.cos(rotation) * offset.y,
|
y: -Math.sin(rotation) * offset.x - Math.cos(rotation) * offset.y,
|
||||||
}
|
}
|
||||||
|
middlePos = centerPos;
|
||||||
|
break;
|
||||||
|
case "None":
|
||||||
|
middlePos = hand === Hand.Left ? leftShoulder : rightShoulder;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handAnim.transitionProgress) {
|
||||||
|
if (progress < handAnim.transitionProgress) {
|
||||||
|
const startHand = hand === Hand.Left
|
||||||
|
? this.startPosition.leftArmEnd ?? leftShoulder
|
||||||
|
: this.startPosition.rightArmEnd ?? rightShoulder;
|
||||||
|
return interpolateLinearOffset(progress / handAnim.transitionProgress, startHand, middlePos);
|
||||||
|
} else if (1 - progress < handAnim.transitionProgress) {
|
||||||
|
const endHand = hand === Hand.Left
|
||||||
|
? this.endPosition.leftArmEnd ?? leftShoulder
|
||||||
|
: this.endPosition.rightArmEnd ?? rightShoulder;
|
||||||
|
return interpolateLinearOffset((1 - progress) / handAnim.transitionProgress, endHand, middlePos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return middlePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,25 +310,16 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
case "none":
|
case "none":
|
||||||
res.set(id, combine([
|
res.set(id, combine([
|
||||||
{
|
{
|
||||||
beats: 1,
|
beats: move.beats,
|
||||||
endPosition: { ...startPosition, dancerDistance: swingRole },
|
endPosition: endPosition,
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
beats: move.beats - 2,
|
|
||||||
endPosition: { ...endPosition, dancerDistance: swingRole },
|
|
||||||
movementPattern: {
|
movementPattern: {
|
||||||
kind: SemanticAnimationKind.Swing,
|
kind: SemanticAnimationKind.Swing,
|
||||||
minAmount: 360,
|
minAmount: 360,
|
||||||
around: startPos.which.leftRightSide(),
|
around: startPos.which.leftRightSide(),
|
||||||
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
||||||
|
swingRole: id.danceRole,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
beats: 1,
|
|
||||||
endPosition: endPosition,
|
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
|
||||||
},
|
|
||||||
], startPos));
|
], startPos));
|
||||||
break;
|
break;
|
||||||
case "balance":
|
case "balance":
|
||||||
|
@ -353,37 +344,22 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
||||||
},
|
},
|
||||||
prevEnd => ({
|
prevEnd => ({
|
||||||
beats: balancePartBeats - 1,
|
beats: balancePartBeats,
|
||||||
endPosition: {
|
endPosition: {
|
||||||
...prevEnd,
|
...prevEnd,
|
||||||
balance: BalanceWeight.Backward,
|
balance: BalanceWeight.Backward,
|
||||||
},
|
},
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
||||||
}),
|
}),
|
||||||
prevEnd => ({
|
|
||||||
beats: 1,
|
|
||||||
endPosition: {
|
|
||||||
...prevEnd,
|
|
||||||
balance: undefined,
|
|
||||||
dancerDistance: swingRole,
|
|
||||||
},
|
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear, },
|
|
||||||
}),
|
|
||||||
{
|
{
|
||||||
beats: move.beats - 2 * balancePartBeats - 1,
|
beats: move.beats - 2 * balancePartBeats,
|
||||||
endPosition: { ...endPosition, dancerDistance: DancerDistance.Compact },
|
endPosition: endPosition,
|
||||||
movementPattern: {
|
movementPattern: {
|
||||||
kind: SemanticAnimationKind.Swing,
|
kind: SemanticAnimationKind.Swing,
|
||||||
minAmount: 360,
|
minAmount: 360,
|
||||||
around: startPos.which.leftRightSide(),
|
around: startPos.which.leftRightSide(),
|
||||||
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
||||||
},
|
swingRole: id.danceRole,
|
||||||
},
|
|
||||||
{
|
|
||||||
beats: 1,
|
|
||||||
endPosition: endPosition,
|
|
||||||
movementPattern: {
|
|
||||||
kind: SemanticAnimationKind.Linear,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
], startPos));
|
], startPos));
|
||||||
|
@ -393,14 +369,12 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
res.set(id, combine([
|
res.set(id, combine([
|
||||||
prevEnd => ({
|
prevEnd => ({
|
||||||
beats: meltdownBeats,
|
beats: meltdownBeats,
|
||||||
endPosition: {
|
endPosition: prevEnd,
|
||||||
...prevEnd,
|
|
||||||
dancerDistance: swingRole,
|
|
||||||
},
|
|
||||||
movementPattern: {
|
movementPattern: {
|
||||||
kind: SemanticAnimationKind.RotateAround,
|
kind: SemanticAnimationKind.RotateAround,
|
||||||
minAmount: 360,
|
minAmount: 360,
|
||||||
around: startPos.which.leftRightSide(),
|
around: startPos.which.leftRightSide(),
|
||||||
|
byHand: undefined,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -411,6 +385,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
minAmount: 360,
|
minAmount: 360,
|
||||||
around: startPos.which.leftRightSide(),
|
around: startPos.which.leftRightSide(),
|
||||||
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
|
||||||
|
swingRole: id.danceRole,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
], startPos));
|
], startPos));
|
||||||
|
@ -452,39 +427,15 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
endPosition.lineOffset = (endPosition.lineOffset ?? 0) + withId.relativeLine;
|
endPosition.lineOffset = (endPosition.lineOffset ?? 0) + withId.relativeLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Take more than zero time to change hands?
|
|
||||||
res.set(id, combine([
|
res.set(id, combine([
|
||||||
prevEnd => ({
|
|
||||||
beats: 0,
|
|
||||||
endPosition: {
|
|
||||||
...prevEnd,
|
|
||||||
hands: new Map<Hand, HandConnection>([[byHand, { hand: byHand, to: HandTo.DancerForward }]]),
|
|
||||||
},
|
|
||||||
movementPattern: {
|
|
||||||
kind: SemanticAnimationKind.RotateAround,
|
|
||||||
minAmount: byHand === Hand.Right ? move.parameters.circling : -move.parameters.circling,
|
|
||||||
around,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
{
|
||||||
beats: move.beats,
|
beats: move.beats,
|
||||||
endPosition: {
|
endPosition,
|
||||||
...endPosition,
|
|
||||||
hands: new Map<Hand, HandConnection>([[byHand, { hand: byHand, to: HandTo.DancerForward }]]),
|
|
||||||
},
|
|
||||||
movementPattern: {
|
|
||||||
kind: SemanticAnimationKind.RotateAround,
|
|
||||||
minAmount: byHand === Hand.Right ? move.parameters.circling : -move.parameters.circling,
|
|
||||||
around,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
beats: 0,
|
|
||||||
endPosition: endPosition,
|
|
||||||
movementPattern: {
|
movementPattern: {
|
||||||
kind: SemanticAnimationKind.RotateAround,
|
kind: SemanticAnimationKind.RotateAround,
|
||||||
minAmount: byHand === Hand.Right ? move.parameters.circling : -move.parameters.circling,
|
minAmount: byHand === Hand.Right ? move.parameters.circling : -move.parameters.circling,
|
||||||
around,
|
around,
|
||||||
|
byHand,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
], startPos));
|
], startPos));
|
||||||
|
@ -501,21 +452,11 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
}
|
}
|
||||||
|
|
||||||
res.set(id, combine([
|
res.set(id, combine([
|
||||||
// TODO Is this right? Or should the circling and hands/positioning start at the same time?
|
|
||||||
{
|
|
||||||
beats: 1,
|
|
||||||
endPosition: {...startPos,
|
|
||||||
hands: handsInCircle,
|
|
||||||
facing: Facing.CenterOfCircle,
|
|
||||||
},
|
|
||||||
movementPattern: {
|
|
||||||
kind: SemanticAnimationKind.Linear,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
prevEnd => ({
|
prevEnd => ({
|
||||||
beats: move.beats - 1,
|
beats: move.beats,
|
||||||
endPosition: {
|
endPosition: {
|
||||||
...prevEnd,
|
...prevEnd,
|
||||||
|
hands: handsInCircle,
|
||||||
which: startPos.which.circleLeft(places),
|
which: startPos.which.circleLeft(places),
|
||||||
},
|
},
|
||||||
movementPattern: {
|
movementPattern: {
|
||||||
|
|
|
@ -20,6 +20,7 @@ export enum CircleSide {
|
||||||
Left = "Left",
|
Left = "Left",
|
||||||
Right = "Right",
|
Right = "Right",
|
||||||
}
|
}
|
||||||
|
export type CircleSideOrCenter = CircleSide | "Center";
|
||||||
export class CirclePosition {
|
export class CirclePosition {
|
||||||
public static readonly TopLeft = new CirclePosition(CirclePositionEnum.TopLeft);
|
public static readonly TopLeft = new CirclePosition(CirclePositionEnum.TopLeft);
|
||||||
public static readonly BottomLeft = new CirclePosition(CirclePositionEnum.BottomLeft);
|
public static readonly BottomLeft = new CirclePosition(CirclePositionEnum.BottomLeft);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import * as animation from "./animation.js";
|
import * as animation from "./animation.js";
|
||||||
import * as common from "./danceCommon.js";
|
import * as common from "./danceCommon.js";
|
||||||
import { DancerIdentity, Rotation } from "./danceCommon.js";
|
import { DanceRole, DancerIdentity, Rotation } from "./danceCommon.js";
|
||||||
import { BalanceWeight, CirclePosition, CircleSide, DancerDistance, Facing, HandConnection, HandTo, PositionKind, SemanticPosition } from "./interpreterCommon.js";
|
import { BalanceWeight, CirclePosition, CircleSide, CircleSideOrCenter, DancerDistance, Facing, HandConnection, HandTo, PositionKind, SemanticPosition } from "./interpreterCommon.js";
|
||||||
import { Move } from "./libfigureMapper.js";
|
import { Move } from "./libfigureMapper.js";
|
||||||
import { DancerSetPosition, Hand, Offset, dancerWidth, lineDistance, setDistance, setHeight, setWidth } from "./rendererConstants.js";
|
import { DancerSetPosition, Hand, Offset, dancerWidth, lineDistance, setDistance, setHeight, setSpacing, setWidth } from "./rendererConstants.js";
|
||||||
|
|
||||||
|
|
||||||
export enum SemanticAnimationKind {
|
export enum SemanticAnimationKind {
|
||||||
|
@ -56,6 +56,8 @@ export type SemanticAnimation = {
|
||||||
minAmount: number,
|
minAmount: number,
|
||||||
|
|
||||||
around: CircleSide | "Center",
|
around: CircleSide | "Center",
|
||||||
|
|
||||||
|
byHand: Hand | undefined,
|
||||||
} | {
|
} | {
|
||||||
kind: SemanticAnimationKind.Swing,
|
kind: SemanticAnimationKind.Swing,
|
||||||
|
|
||||||
|
@ -64,6 +66,9 @@ export type SemanticAnimation = {
|
||||||
around: CircleSide | "Center",
|
around: CircleSide | "Center",
|
||||||
|
|
||||||
endFacing: Facing,
|
endFacing: Facing,
|
||||||
|
|
||||||
|
// Swings are asymmetric. This is usually but not always the dancer's role.
|
||||||
|
swingRole: common.DanceRole,
|
||||||
} | {
|
} | {
|
||||||
kind: SemanticAnimationKind.TwirlSwap,
|
kind: SemanticAnimationKind.TwirlSwap,
|
||||||
|
|
||||||
|
@ -103,8 +108,12 @@ function CenterOfSet(setOffset?: number, lineOffset?: number): Offset {
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
function CenterOfSideOfSet(side: CircleSide, setOffset?: number, lineOffset?: number): Offset {
|
function CenterOf(sideOrCenter: CircleSideOrCenter, setOffset?: number, lineOffset?: number): Offset {
|
||||||
const setCenter = CenterOfSet(setOffset, lineOffset);
|
const setCenter = CenterOfSet(setOffset, lineOffset);
|
||||||
|
|
||||||
|
if (sideOrCenter === "Center") return setCenter;
|
||||||
|
const side : CircleSide = sideOrCenter;
|
||||||
|
|
||||||
const xOffset = side === CircleSide.Left ? -1 : side === CircleSide.Right ? +1 : 0;
|
const xOffset = side === CircleSide.Left ? -1 : side === CircleSide.Right ? +1 : 0;
|
||||||
const yOffset = side === CircleSide.Top ? -1 : side === CircleSide.Bottom ? +1 : 0;
|
const yOffset = side === CircleSide.Top ? -1 : side === CircleSide.Bottom ? +1 : 0;
|
||||||
|
|
||||||
|
@ -181,8 +190,8 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
|
||||||
x: position.x,
|
x: position.x,
|
||||||
y: position.y + position.y * (
|
y: position.y + position.y * (
|
||||||
semantic.balance === BalanceWeight.Forward
|
semantic.balance === BalanceWeight.Forward
|
||||||
? balanceAmount
|
? -balanceAmount
|
||||||
: -balanceAmount)
|
: balanceAmount)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,6 +310,11 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
|
||||||
height: setHeight,
|
height: setHeight,
|
||||||
},
|
},
|
||||||
animation.RotationAnimationFacing.Center,
|
animation.RotationAnimationFacing.Center,
|
||||||
|
undefined,
|
||||||
|
new Map<Hand, animation.HandAnimation>([
|
||||||
|
[Hand.Left, { kind: "Linear", transitionBeats: 1 }],
|
||||||
|
[Hand.Right, { kind: "Linear", transitionBeats: 1 }],
|
||||||
|
])
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
case SemanticAnimationKind.DoSiDo:
|
case SemanticAnimationKind.DoSiDo:
|
||||||
|
@ -310,7 +324,7 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
|
||||||
if (move.startPosition.kind !== PositionKind.Circle) {
|
if (move.startPosition.kind !== PositionKind.Circle) {
|
||||||
throw "DoSiDo must start in a circle: " + JSON.stringify(move);
|
throw "DoSiDo must start in a circle: " + JSON.stringify(move);
|
||||||
}
|
}
|
||||||
const center = CenterOfSideOfSet(move.startPosition.which.leftRightSide(), move.startPosition.setOffset, move.startPosition.lineOffset);
|
const center = CenterOf(move.startPosition.which.leftRightSide(), move.startPosition.setOffset, move.startPosition.lineOffset);
|
||||||
return [
|
return [
|
||||||
new animation.RotationAnimationSegment(move.beats,
|
new animation.RotationAnimationSegment(move.beats,
|
||||||
startSetPosition,
|
startSetPosition,
|
||||||
|
@ -332,9 +346,16 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
|
||||||
throw "Rotate must start in a circle: " + JSON.stringify(move);
|
throw "Rotate must start in a circle: " + JSON.stringify(move);
|
||||||
}
|
}
|
||||||
// TODO Could rotate around other things.
|
// TODO Could rotate around other things.
|
||||||
const rotateCenter = move.movementPattern.around === "Center"
|
const rotateCenter = CenterOf(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
||||||
? CenterOfSet(move.startPosition.setOffset, move.startPosition.lineOffset)
|
const hands = move.movementPattern.byHand
|
||||||
: CenterOfSideOfSet(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
? new Map<Hand, animation.HandAnimation>([
|
||||||
|
[move.movementPattern.byHand, { kind: "Center", transitionBeats: 1 }],
|
||||||
|
[move.movementPattern.byHand.opposite(), { kind: "None", transitionBeats: 1 }],
|
||||||
|
])
|
||||||
|
: new Map<Hand, animation.HandAnimation>([
|
||||||
|
[Hand.Left, { kind: "None", transitionBeats: 1 }],
|
||||||
|
[Hand.Right, { kind: "None", transitionBeats: 1 }],
|
||||||
|
]);
|
||||||
return [
|
return [
|
||||||
new animation.RotationAnimationSegment(move.beats,
|
new animation.RotationAnimationSegment(move.beats,
|
||||||
startSetPosition,
|
startSetPosition,
|
||||||
|
@ -350,26 +371,42 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
|
||||||
transitionBeats: 1,
|
transitionBeats: 1,
|
||||||
minDistance: setWidth,
|
minDistance: setWidth,
|
||||||
},
|
},
|
||||||
|
hands,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
case SemanticAnimationKind.Swing:
|
case SemanticAnimationKind.Swing:
|
||||||
// TODO Handle swing.
|
|
||||||
// TODO Rotation
|
|
||||||
// TODO Parameters: rotation, amount, direction, diagonal?
|
|
||||||
|
|
||||||
if (move.startPosition.kind !== PositionKind.Circle || move.endPosition.kind !== PositionKind.Circle) {
|
if (move.startPosition.kind !== PositionKind.Circle || move.endPosition.kind !== PositionKind.Circle) {
|
||||||
throw "Swing must start in a circle: " + JSON.stringify(move);
|
throw "Swing must start in a circle: " + JSON.stringify(move);
|
||||||
}
|
}
|
||||||
// TODO Could rotate around other things.
|
const rotateSwingCenter = CenterOf(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
||||||
const rotateSwingCenter = move.movementPattern.around === "Center"
|
const dancerDistance = move.movementPattern.swingRole === DanceRole.Lark ? DancerDistance.SwingLark : DancerDistance.SwingRobin;
|
||||||
? CenterOfSet(move.startPosition.setOffset, move.startPosition.lineOffset)
|
|
||||||
: CenterOfSideOfSet(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
const swingStart = SemanticToSetPosition({
|
||||||
const beforeUnfold = SemanticToSetPosition({...move.endPosition, dancerDistance: move.startPosition.dancerDistance });
|
...move.startPosition,
|
||||||
|
dancerDistance,
|
||||||
|
balance: undefined,
|
||||||
|
});
|
||||||
|
const beforeUnfold = SemanticToSetPosition({
|
||||||
|
...move.endPosition,
|
||||||
|
dancerDistance,
|
||||||
|
});
|
||||||
|
const unfolded = SemanticToSetPosition({
|
||||||
|
...move.endPosition,
|
||||||
|
dancerDistance: DancerDistance.Normal,
|
||||||
|
hands: move.movementPattern.swingRole === DanceRole.Lark
|
||||||
|
? new Map<Hand, HandConnection>([[Hand.Right, {hand: Hand.Left, to: HandTo.DancerRight}]])
|
||||||
|
: new Map<Hand, HandConnection>([[Hand.Left, {hand: Hand.Right, to: HandTo.DancerLeft}]]),
|
||||||
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new animation.RotationAnimationSegment(move.beats - 1,
|
new animation.LinearAnimationSegment(1,
|
||||||
startSetPosition,
|
startSetPosition,
|
||||||
|
swingStart,
|
||||||
|
),
|
||||||
|
new animation.RotationAnimationSegment(move.beats - 3,
|
||||||
|
swingStart,
|
||||||
beforeUnfold,
|
beforeUnfold,
|
||||||
move.movementPattern.minAmount,
|
move.movementPattern.minAmount, // TODO base minAmount on number of beats?
|
||||||
{
|
{
|
||||||
center: rotateSwingCenter,
|
center: rotateSwingCenter,
|
||||||
width: setWidth / 5,
|
width: setWidth / 5,
|
||||||
|
@ -379,12 +416,16 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
|
||||||
),
|
),
|
||||||
new animation.LinearAnimationSegment(1,
|
new animation.LinearAnimationSegment(1,
|
||||||
beforeUnfold,
|
beforeUnfold,
|
||||||
|
unfolded,
|
||||||
|
),
|
||||||
|
new animation.LinearAnimationSegment(1,
|
||||||
|
unfolded,
|
||||||
endSetPosition,
|
endSetPosition,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
case SemanticAnimationKind.TwirlSwap:
|
case SemanticAnimationKind.TwirlSwap:
|
||||||
const twirlCenter =
|
const twirlCenter =
|
||||||
CenterOfSideOfSet(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
CenterOf(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
|
||||||
const aroundTopOrBottom = move.movementPattern.around === CircleSide.Top || move.movementPattern.around === CircleSide.Bottom;
|
const aroundTopOrBottom = move.movementPattern.around === CircleSide.Top || move.movementPattern.around === CircleSide.Bottom;
|
||||||
const postTwirlPos =
|
const postTwirlPos =
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user