Compare commits

...

2 Commits

4 changed files with 87 additions and 63 deletions

View File

@ -89,7 +89,7 @@ export class LinearAnimationSegment extends AnimationSegment {
export interface AnimationTransitionFlags {
rotation?: boolean;
hands?: boolean;
handsDuring?: "Actual" | "None" | "Start" | "End";
handsDuring?: "Actual" | "None" | "Start" | "End" | Map<Hand, Offset>;
}
export class TransitionAnimationSegment extends AnimationSegment {
private readonly actualAnimation: AnimationSegment;
@ -122,32 +122,33 @@ export class TransitionAnimationSegment extends AnimationSegment {
const transitionEnd = this.actualAnimation.interpolateRotation(1 - this.endTransitionProgress);
if (actualEnd > actualStart) {
while (transitionStart < this.startRotation) {
while (transitionStart <= this.startRotation - 180) {
this.startRotation -= 360;
}
while (transitionEnd > this.endRotation) {
while (transitionEnd >= this.endRotation + 180) {
this.endRotation += 360;
}
} else if (actualEnd < actualStart) {
while (transitionStart > this.startRotation) {
while (transitionStart >= this.startRotation + 180) {
this.startRotation += 360;
}
while (transitionEnd < this.endRotation) {
while (transitionEnd <= this.endRotation - 180) {
this.endRotation -= 360;
}
} else {
while (transitionStart - this.startRotation < 180) {
this.startRotation -= 360;
}
while (transitionStart - this.startRotation > 180) {
this.startRotation += 360;
}
while (transitionEnd - this.endRotation < 180) {
this.endRotation -= 360;
}
while (transitionEnd - this.endRotation > 180) {
this.endRotation += 360;
}
}
// Transitions should be short adjustments, not spins.
while (transitionStart - this.startRotation < -180) {
this.startRotation -= 360;
}
while (transitionStart - this.startRotation > 180) {
this.startRotation += 360;
}
while (transitionEnd - this.endRotation < -180) {
this.endRotation -= 360;
}
while (transitionEnd - this.endRotation > 180) {
this.endRotation += 360;
}
}
}
@ -185,6 +186,8 @@ export class TransitionAnimationSegment extends AnimationSegment {
? startHand
: this.flags.handsDuring === "End"
? endHand
: this.flags.handsDuring instanceof Map
? this.flags.handsDuring.get(hand)
: (() => { throw "Unexpected handsDuring: " + this.flags.handsDuring; })();
if (this.flags.hands) {
@ -238,8 +241,9 @@ export class RotationAnimationSegment extends AnimationSegment {
private readonly startFacing: Rotation;
private readonly closer?: Closer;
private readonly hands: Map<Hand, HandAnimation>;
private readonly centerRelativeTo: number;
constructor({ beats, startPosition, endPosition, rotation, around, facing, closer, hands }: {
constructor({ beats, startPosition, endPosition, rotation, around, facing, closer, hands, centerRelativeTo }: {
beats: number;
startPosition: DancerSetPosition;
endPosition: DancerSetPosition;
@ -248,6 +252,7 @@ export class RotationAnimationSegment extends AnimationSegment {
facing: RotationAnimationFacing;
closer?: CloserDuringRotation;
hands?: Map<Hand, HandAnimation>;
centerRelativeTo?: number;
}) {
super(beats, startPosition, endPosition);
@ -268,6 +273,7 @@ export class RotationAnimationSegment extends AnimationSegment {
}
this.startRotation = positionToDegrees(startPosition.position);
this.startFacing = startPosition.rotation;
this.centerRelativeTo = centerRelativeTo ?? this.startFacing;
const actualRotation = normalizeRotation(positionToDegrees(endPosition.position) - this.startRotation,
rotation);
this.endRotation = this.startRotation + actualRotation;
@ -311,14 +317,13 @@ export class RotationAnimationSegment extends AnimationSegment {
return super.interpolateRotation(progress);
} else {
const degrees = interpolateLinear(progress, this.startRotation, this.endRotation);
let rotation : number;
switch (this.facing) {
case RotationAnimationFacing.Start:
return this.startFacing;
case RotationAnimationFacing.Center:
return degrees - 90;
case RotationAnimationFacing.CenterRelative:
return degrees - this.startRotation + this.startFacing;
return degrees - this.startRotation + this.centerRelativeTo;
case RotationAnimationFacing.Forward:
return degrees + 180;
case RotationAnimationFacing.Backward:

View File

@ -697,7 +697,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
return combine([
prevEnd => ({
beats: meltdownBeats,
endPosition: prevEnd,
endPosition: {...prevEnd, dancerDistance: DancerDistance.Compact },
movementPattern: {
kind: SemanticAnimationKind.RotateAround,
minAmount: 360,

View File

@ -324,5 +324,5 @@ export type SemanticPosition = {
facing: Facing,
hands?: Map<Hand, HandConnection>,
balance?: BalanceWeight,
dancerDistance?: DancerDistance.Normal | DancerDistance.SwingLark | DancerDistance.SwingRobin,
dancerDistance?: DancerDistance,
};

View File

@ -170,6 +170,30 @@ function CenterOf(sideOrCenter: CircleSideOrCenter, setOffset?: number, lineOffs
return { x: setCenter.x + xOffset, y: setCenter.y + yOffset };
}
function swingHandPosition(role: DancerDistance.SwingLark | DancerDistance.SwingRobin, hand: Hand): Offset {
if (role === DancerDistance.SwingLark) {
if (hand === Hand.Left) {
return { x: 0, y: Math.sqrt(1 / 2) };
}
else {
return { x: 0.8, y: 0.5 };
}
} else /* role === DancerDistance.SwingRobin */ {
if (hand === Hand.Left) {
return { x: -0.8, y: 0.5 };
}
else {
return { x: 0, y: Math.sqrt(1 / 2) };
};
}
}
function swingHandPositions(role: DancerDistance.SwingLark | DancerDistance.SwingRobin): Map<Hand, Offset> {
return new Map<Hand, Offset>([
[Hand.Left, swingHandPosition(role, Hand.Left)],
[Hand.Right, swingHandPosition(role, Hand.Right)],
]);
}
function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
let rotation: number;
@ -211,8 +235,6 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
yAmount = 1;
break;
case DancerDistance.Compact:
yAmount = 0.75;
break;
case DancerDistance.SwingLark:
case DancerDistance.SwingRobin:
yAmount = 0.5;
@ -286,8 +308,8 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
position = OffsetPlus(position, balanceOffset, setOffset);
const isFacingUpOrDown = semantic.facing === Facing.Up || semantic.facing === Facing.Down;
if (semantic.dancerDistance === DancerDistance.SwingLark) {
if (isFacingUpOrDown) {
if (semantic.dancerDistance === DancerDistance.SwingLark || semantic.dancerDistance == DancerDistance.SwingRobin) {
if (isFacingUpOrDown == (semantic.dancerDistance === DancerDistance.SwingLark)) {
rotation -= 45;
} else {
rotation += 45;
@ -296,21 +318,8 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
return {
position,
rotation,
leftArmEnd: { x: 0, y: Math.sqrt(1/2)},
rightArmEnd: { x: 0.8, y: 0.5 },
};
} else if (semantic.dancerDistance === DancerDistance.SwingRobin) {
if (isFacingUpOrDown) {
rotation += 45;
} else {
rotation -= 45;
}
return {
position,
rotation,
leftArmEnd: { x: -0.8, y: 0.5 },
rightArmEnd: { x: 0, y: Math.sqrt(1/2) },
leftArmEnd: swingHandPosition(semantic.dancerDistance, Hand.Left),
rightArmEnd: swingHandPosition(semantic.dancerDistance, Hand.Right),
};
}
@ -325,10 +334,11 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
case HandTo.DancerRight:
return OffsetPlus({ x: +1, y: 0 }, balanceHandAdjustment);
case HandTo.DancerForward:
const armLength = yAmount + (semantic.balance === BalanceWeight.Backward ? balanceAmount : 0);
if (hand === connection.hand) {
return { x: 0, y: +0.5 };
return { x: 0, y: +armLength/2 };
} else {
return { x: dancerWidth / 2 * (hand === Hand.Left ? -1 : +1), y: +1 };
return { x: dancerWidth / 2 * (hand === Hand.Left ? -1 : +1), y: +armLength };
}
case HandTo.LeftInCircle:
case HandTo.RightInCircle:
@ -572,13 +582,13 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
rotation: move.movementPattern.minAmount,
around: {
center: rotateCenter,
width: setWidth / 5,
height: setHeight / 5,
width: 1,
height: 1,
},
facing: animation.RotationAnimationFacing.Center,
facing: animation.RotationAnimationFacing.Forward,
closer: move.movementPattern.close ? {
transitionBeats: 1,
minDistance: setWidth,
minDistance: 1,
} : undefined,
hands
}),
@ -611,22 +621,31 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
});
return [
new animation.LinearAnimationSegment({
beats: 1,
startPosition: startSetPosition,
endPosition: swingStart,
}),
new animation.RotationAnimationSegment({
beats: move.beats - 3,
startPosition: swingStart,
endPosition: beforeUnfold,
rotation: move.movementPattern.minAmount,
around: {
center: rotateSwingCenter,
width: setWidth / 5,
height: setHeight / 5,
new animation.TransitionAnimationSegment({
actualAnimation: new animation.RotationAnimationSegment({
beats: move.beats - 2,
startPosition: startSetPosition,
endPosition: beforeUnfold,
rotation: move.movementPattern.minAmount,
around: {
center: rotateSwingCenter,
width: 1,
height: 1,
},
closer: {
minDistance: 1,
transitionBeats: 1,
},
facing: animation.RotationAnimationFacing.CenterRelative,
centerRelativeTo: startSetPosition.rotation + ((move.startPosition.facing === Facing.Up || move.startPosition.facing === Facing.Down) === (dancerDistance === DancerDistance.SwingLark) ? -45 : +45)
}),
flags: {
rotation: true,
hands: true,
handsDuring: swingHandPositions(dancerDistance),
},
facing: animation.RotationAnimationFacing.CenterRelative
startTransitionBeats: 1,
endTransitionBeats: 0,
}),
new animation.LinearAnimationSegment({
beats: 1,