Compare commits
4 Commits
c4462b0f50
...
239bc60500
Author | SHA1 | Date | |
---|---|---|---|
239bc60500 | |||
e240b690f4 | |||
2631bad801 | |||
5de6db868b |
|
@ -140,6 +140,26 @@ function danceAsLowLevelMoves(moves: Move[], startingVariants: AllVariantsForMov
|
||||||
if (move.progression) numProgessions++;
|
if (move.progression) numProgessions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there's multiple variants, check if there's fewer that flow into the first move.
|
||||||
|
if (currentVariantMoves.size !== 1) {
|
||||||
|
let newMoves: VariantCollection | undefined;
|
||||||
|
try {
|
||||||
|
newMoves = allVariantsForMove({ move: moves[0], nextMove: moves[1], startingVariants: currentVariants, numProgessions });
|
||||||
|
} catch {
|
||||||
|
newMoves = undefined;
|
||||||
|
}
|
||||||
|
if (newMoves) {
|
||||||
|
const firstMoveVariants = [...newMoves.values()].map(v => v.previousMoveVariant);
|
||||||
|
if (firstMoveVariants.length > 0) {
|
||||||
|
for (const variant of [...currentVariantMoves.keys()]) {
|
||||||
|
if (!firstMoveVariants.includes(variant)) {
|
||||||
|
currentVariantMoves.delete(variant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const res = [...currentVariantMoves.values()].at(-1)!;
|
const res = [...currentVariantMoves.values()].at(-1)!;
|
||||||
if (currentVariantMoves.size !== 1) {
|
if (currentVariantMoves.size !== 1) {
|
||||||
res.get(DancerIdentity.OnesRobin)![0].interpreterError = "Expected exactly one variant. Found "
|
res.get(DancerIdentity.OnesRobin)![0].interpreterError = "Expected exactly one variant. Found "
|
||||||
|
@ -156,12 +176,15 @@ function danceAsLowLevelMoves(moves: Move[], startingVariants: AllVariantsForMov
|
||||||
if (!lowLevelMoves[i].endPosition) throw "endPosition is undefined";
|
if (!lowLevelMoves[i].endPosition) throw "endPosition is undefined";
|
||||||
lowLevelMoves[i].endPosition = lowLevelMoves[i + 1].startPosition;
|
lowLevelMoves[i].endPosition = lowLevelMoves[i + 1].startPosition;
|
||||||
if (!lowLevelMoves[i].endPosition) throw "endPosition is undefined now";
|
if (!lowLevelMoves[i].endPosition) throw "endPosition is undefined now";
|
||||||
|
// TODO Exactly what is the StandStill fixup needed for? Can it be handled in other ways? Should it be rotation only?
|
||||||
|
/*
|
||||||
if (lowLevelMoves[i].movementPattern.kind === SemanticAnimationKind.StandStill) {
|
if (lowLevelMoves[i].movementPattern.kind === SemanticAnimationKind.StandStill) {
|
||||||
lowLevelMoves[i].startPosition = lowLevelMoves[i].endPosition;
|
lowLevelMoves[i].startPosition = lowLevelMoves[i].endPosition;
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
lowLevelMoves[i - 1].endPosition = lowLevelMoves[i].startPosition;
|
lowLevelMoves[i - 1].endPosition = lowLevelMoves[i].startPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
// If progression isn't detected properly, do nothing.
|
// If progression isn't detected properly, do nothing.
|
||||||
if (progressionInSets === 0) {
|
if (progressionInSets === 0) {
|
||||||
|
|
|
@ -349,6 +349,10 @@ export class ShortLinesPosition {
|
||||||
return this.isLeft() ? Facing.Right : Facing.Left;
|
return this.isLeft() ? Facing.Right : Facing.Left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isToLeftOf(otherPos: ShortLinesPosition): boolean {
|
||||||
|
return this.enumValue < otherPos.enumValue;
|
||||||
|
}
|
||||||
|
|
||||||
public toString() : string {
|
public toString() : string {
|
||||||
return this.enumValue.toString();
|
return this.enumValue.toString();
|
||||||
}
|
}
|
||||||
|
@ -520,3 +524,83 @@ export function handToDancerToSideInCircleFacingUpOrDown(which: CirclePosition):
|
||||||
: [Hand.Left, { hand: Hand.Right, to: HandTo.DancerLeft }]
|
: [Hand.Left, { hand: Hand.Right, to: HandTo.DancerLeft }]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function facingAdjacent(pos: SemanticPosition, otherPos: SemanticPosition): Facing | undefined {
|
||||||
|
if (pos.kind !== otherPos.kind) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos.kind === PositionKind.ShortLines) {
|
||||||
|
if (otherPos.kind !== PositionKind.ShortLines) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if ((pos.setOffset ?? 0) !== (otherPos.setOffset ?? 0)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if ((pos.lineOffset ?? 0) !== (otherPos.lineOffset ?? 0)) {
|
||||||
|
if (pos.which === ShortLinesPosition.FarLeft && otherPos.which === ShortLinesPosition.FarRight
|
||||||
|
&& ((pos.lineOffset ?? 0) - 1) === (otherPos.lineOffset ?? 0)) {
|
||||||
|
return Facing.Left;
|
||||||
|
} else if (pos.which === ShortLinesPosition.FarRight && otherPos.which === ShortLinesPosition.FarLeft
|
||||||
|
&& ((pos.lineOffset ?? 0) + 1) === (otherPos.lineOffset ?? 0)) {
|
||||||
|
return Facing.Right;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherPos.which.isToLeftOf(pos.which)) {
|
||||||
|
return Facing.Left;
|
||||||
|
} else {
|
||||||
|
return Facing.Right;
|
||||||
|
}
|
||||||
|
} else if (pos.kind === PositionKind.Circle) {
|
||||||
|
if (otherPos.kind !== PositionKind.Circle) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pos.lineOffset ?? 0) !== (otherPos.lineOffset ?? 0)) {
|
||||||
|
// TODO
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if ((pos.setOffset ?? 0) !== (otherPos.setOffset ?? 0)) {
|
||||||
|
// TODO
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos.which.leftRightSide() === otherPos.which.leftRightSide()) {
|
||||||
|
if (pos.which.topBottomSide() === otherPos.which.topBottomSide()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pos.lineOffset ?? 0) !== (otherPos.lineOffset ?? 0)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pos.setOffset ?? 0) === (otherPos.setOffset ?? 0)) {
|
||||||
|
return pos.which.facingUpOrDown();
|
||||||
|
} else if (((pos.setOffset ?? 0) + 1) === (otherPos.setOffset ?? 0) && pos.which.isTop()) {
|
||||||
|
return Facing.Up;
|
||||||
|
} else if (((pos.setOffset ?? 0) - 1) === (otherPos.setOffset ?? 0) && !pos.which.isTop()) {
|
||||||
|
return Facing.Down;
|
||||||
|
}
|
||||||
|
} else if (pos.which.topBottomSide() === otherPos.which.topBottomSide()) {
|
||||||
|
if ((pos.setOffset ?? 0) === (otherPos.setOffset ?? 0)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pos.lineOffset ?? 0) !== (otherPos.lineOffset ?? 0)) {
|
||||||
|
return pos.which.facingAcross();
|
||||||
|
} else if (((pos.lineOffset ?? 0) + 1) === (otherPos.lineOffset ?? 0) && pos.which.isLeft()) {
|
||||||
|
return Facing.Left;
|
||||||
|
} else if (((pos.lineOffset ?? 0) - 1) === (otherPos.lineOffset ?? 0) && !pos.which.isLeft()) {
|
||||||
|
return Facing.Right;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Opposite corners of circle.
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Unexpected PositionKind: " + otherPos.kind);
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,6 +77,8 @@ export type SemanticAnimation = {
|
||||||
|
|
||||||
// If true, move in close while rotating.
|
// If true, move in close while rotating.
|
||||||
close: boolean,
|
close: boolean,
|
||||||
|
|
||||||
|
facing?: animation.RotationAnimationFacing,
|
||||||
} | {
|
} | {
|
||||||
kind: SemanticAnimationKind.Swing,
|
kind: SemanticAnimationKind.Swing,
|
||||||
|
|
||||||
|
@ -292,7 +294,7 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
|
||||||
&& (semantic.balance === BalanceWeight.Backward || semantic.balance === BalanceWeight.Forward)) {
|
&& (semantic.balance === BalanceWeight.Backward || semantic.balance === BalanceWeight.Forward)) {
|
||||||
balanceOffset = {
|
balanceOffset = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: position.y * (
|
y: Math.sign(position.y) * (
|
||||||
semantic.balance === BalanceWeight.Forward
|
semantic.balance === BalanceWeight.Forward
|
||||||
? -balanceAmount
|
? -balanceAmount
|
||||||
: balanceAmount)
|
: balanceAmount)
|
||||||
|
@ -352,9 +354,9 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
|
||||||
case HandTo.DancerRight:
|
case HandTo.DancerRight:
|
||||||
return OffsetPlus({ x: +1, y: 0 }, balanceHandAdjustment);
|
return OffsetPlus({ x: +1, y: 0 }, balanceHandAdjustment);
|
||||||
case HandTo.DancerForward:
|
case HandTo.DancerForward:
|
||||||
const armLength = yAmount + (semantic.balance === BalanceWeight.Backward ? balanceAmount : 0);
|
const armLength = yAmount + (semantic.balance === BalanceWeight.Backward ? balanceAmount : semantic.balance === BalanceWeight.Forward ? -balanceAmount : 0);
|
||||||
if (hand === connection.hand) {
|
if (hand === connection.hand) {
|
||||||
return { x: 0, y: +armLength/2 };
|
return { x: 0, y: +armLength };
|
||||||
} else {
|
} else {
|
||||||
return { x: dancerWidth / 2 * (hand === Hand.Left ? -1 : +1), y: +armLength };
|
return { x: dancerWidth / 2 * (hand === Hand.Left ? -1 : +1), y: +armLength };
|
||||||
}
|
}
|
||||||
|
@ -655,7 +657,7 @@ function animateLowLevelMoveWithoutSlide(move: LowLevelMove): animation.Animatio
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 1,
|
height: 1,
|
||||||
},
|
},
|
||||||
facing: animation.RotationAnimationFacing.Forward,
|
facing: move.movementPattern.facing ?? animation.RotationAnimationFacing.Forward,
|
||||||
closer: move.movementPattern.close ? {
|
closer: move.movementPattern.close ? {
|
||||||
transitionBeats: 1,
|
transitionBeats: 1,
|
||||||
minDistance: 1,
|
minDistance: 1,
|
||||||
|
|
|
@ -428,7 +428,7 @@ displaySettingsDiv.appendChild(debugRenderLabel);
|
||||||
wrapperDiv.appendChild(displaySettingsDiv);
|
wrapperDiv.appendChild(displaySettingsDiv);
|
||||||
|
|
||||||
// Default dance is Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
// Default dance is Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
||||||
const defaultDanceTitle = "Two Hearts in Time";
|
const defaultDanceTitle = "March for Andrea";
|
||||||
|
|
||||||
const danceList = document.createElement('select');
|
const danceList = document.createElement('select');
|
||||||
for (const [idx, dance] of danceLibrary.dances.entries()) {
|
for (const [idx, dance] of danceLibrary.dances.entries()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CoupleRole, DanceRole, DancerIdentity, ExtendedDancerIdentity } from "../danceCommon.js";
|
import { CoupleRole, DanceRole, DancerIdentity, ExtendedDancerIdentity } from "../danceCommon.js";
|
||||||
import { CirclePosition, CircleSideOrCenter, PositionKind, SemanticPosition } from "../interpreterCommon.js";
|
import { CirclePosition, CircleSideOrCenter, DancerDistance, PositionKind, SemanticPosition } from "../interpreterCommon.js";
|
||||||
import { Move, chooser_pairz } from "../libfigureMapper.js";
|
import { Move, chooser_pairz } from "../libfigureMapper.js";
|
||||||
import { LowLevelMove, SemanticAnimation, SemanticAnimationKind } from "../lowLevelMove.js";
|
import { LowLevelMove, SemanticAnimation, SemanticAnimationKind } from "../lowLevelMove.js";
|
||||||
|
|
||||||
|
@ -44,12 +44,25 @@ export abstract class SingleVariantMoveInterpreter<T extends MoveInterpreter<N>,
|
||||||
constructor(moveInterpreter: T, startingPos: SemanticPositionsForAllDancers) {
|
constructor(moveInterpreter: T, startingPos: SemanticPositionsForAllDancers) {
|
||||||
this.moveInterpreter = moveInterpreter;
|
this.moveInterpreter = moveInterpreter;
|
||||||
this.startingPos = startingPos;
|
this.startingPos = startingPos;
|
||||||
|
|
||||||
|
if (!this.allowStartingClose()) {
|
||||||
|
for (const [id, startPos] of this.startingPos) {
|
||||||
|
if (startPos.dancerDistance && startPos.dancerDistance !== DancerDistance.Normal) {
|
||||||
|
throw new Error("Can not start " + this.move.move + " at dancerDistance " + startPos.dancerDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get move() : Move & { move: N } {
|
get move() : Move & { move: N } {
|
||||||
return this.moveInterpreter.move;
|
return this.moveInterpreter.move;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowStartingClose(): boolean {
|
||||||
|
// Swings can end close, but most moves can't start close, so do this check by default for all moves.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
||||||
throw new Error("You must implement either moveAsLowLevelMoves() or moveAsVariants().");
|
throw new Error("You must implement either moveAsLowLevelMoves() or moveAsVariants().");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,101 @@
|
||||||
import { BalanceWeight } from "../interpreterCommon.js";
|
import { BalanceWeight, Facing, HandConnection, HandTo, PositionKind, facingAdjacent } from "../interpreterCommon.js";
|
||||||
import { SemanticAnimationKind } from "../lowLevelMove.js";
|
import { SemanticAnimationKind } from "../lowLevelMove.js";
|
||||||
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, MoveInterpreterCtorArgs, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js";
|
import { Hand } from "../rendererConstants.js";
|
||||||
|
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, MoveInterpreterCtorArgs, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, Variant, VariantCollection, moveInterpreters } from "./_moveInterpreter.js";
|
||||||
|
|
||||||
class BalanceSingleVariant extends SingleVariantMoveInterpreter<Balance, "balance"> {
|
class BalanceSingleVariant extends SingleVariantMoveInterpreter<Balance, "balance"> {
|
||||||
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
private static readonly balanceOptions : [BalanceWeight, BalanceWeight | undefined, Hand | undefined][]= [
|
||||||
return this.handleMove(({ startPos }) => {
|
// TODO Any others?
|
||||||
// TODO Use who to determine facing?
|
[BalanceWeight.Forward, undefined, undefined],
|
||||||
// TODO Could be left to right, not back and forth?
|
[BalanceWeight.Forward, BalanceWeight.Backward, undefined],
|
||||||
// TODO How to determine hand... by next move, I guess?
|
// TODO Should be left/right/inside/outside hands?
|
||||||
|
[BalanceWeight.Forward, BalanceWeight.Backward, Hand.Left],
|
||||||
|
[BalanceWeight.Forward, BalanceWeight.Backward, Hand.Right],
|
||||||
|
[BalanceWeight.Right, BalanceWeight.Backward, undefined],
|
||||||
|
[BalanceWeight.Right, BalanceWeight.Left, undefined],
|
||||||
|
[BalanceWeight.Left, BalanceWeight.Right, undefined],
|
||||||
|
];
|
||||||
|
|
||||||
return this.combine([
|
moveAsVariants(previousMoveVariant: string): VariantCollection {
|
||||||
{
|
const res = new Map<string, Variant>();
|
||||||
beats: this.moveInterpreter.forwardBeats,
|
|
||||||
endPosition: { ...startPos, balance: BalanceWeight.Forward },
|
for (const [firstWeight, secondWeight, hand] of BalanceSingleVariant.balanceOptions) {
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear },
|
// If balancing someone, need to know by which hand.
|
||||||
},
|
if ((hand === undefined) !== (this.move.parameters.who === "everyone")) continue;
|
||||||
{
|
try {
|
||||||
beats: this.moveInterpreter.backwardBeats,
|
res.set((firstWeight?.toString() ?? "") + (secondWeight?.toString() ?? "") + (hand === undefined ? "" : hand.toString() + "Hand"), {
|
||||||
endPosition: { ...startPos, balance: BalanceWeight.Backward },
|
lowLevelMoves: this.moveAsLowLevelMovesWeights(firstWeight, secondWeight, hand),
|
||||||
movementPattern: { kind: SemanticAnimationKind.Linear },
|
previousMoveVariant
|
||||||
},
|
});
|
||||||
], startPos);
|
}
|
||||||
});
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
moveAsLowLevelMovesWeights(firstWeight?: BalanceWeight, secondWeight?: BalanceWeight, hand?: Hand): LowLevelMovesForAllDancers {
|
||||||
|
if (this.move.parameters.who !== "everyone") {
|
||||||
|
return this.handlePairedMove(this.move.parameters.who, ({ startPos, withPos }) => {
|
||||||
|
// TODO Does this need to support balancing inside/outside hands? If so how to identify them?
|
||||||
|
const hands = hand === undefined ? startPos.hands : new Map<Hand, HandConnection>([[hand, {hand, to: HandTo.DancerForward}]]);
|
||||||
|
|
||||||
|
const facing = facingAdjacent(startPos, withPos);
|
||||||
|
if (facing === undefined) {
|
||||||
|
throw new Error("Not adjacent to paired dancer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const startingPos = {...startPos, facing, hands};
|
||||||
|
|
||||||
|
return this.combine([
|
||||||
|
{
|
||||||
|
beats: this.moveInterpreter.balancePartBeats,
|
||||||
|
endPosition: { ...startingPos, balance: firstWeight, hands },
|
||||||
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
beats: this.moveInterpreter.balancePartBeats,
|
||||||
|
endPosition: { ...startingPos, balance: secondWeight, hands },
|
||||||
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
||||||
|
},
|
||||||
|
], startingPos);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return this.handleMove(({ startPos }) => {
|
||||||
|
// TODO Use who to determine facing?
|
||||||
|
// TODO Could be left to right, not back and forth?
|
||||||
|
// TODO How to determine hand... by next move, I guess?
|
||||||
|
if (startPos.kind === PositionKind.Circle && startPos.facing === Facing.CenterOfCircle) {
|
||||||
|
if (firstWeight === BalanceWeight.Left || firstWeight === BalanceWeight.Right || firstWeight === BalanceWeight.Backward
|
||||||
|
|| secondWeight === BalanceWeight.Left || secondWeight === BalanceWeight.Right || secondWeight === BalanceWeight.Backward) {
|
||||||
|
throw new Error("Balancing left or right in a circle is unsupported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.combine([
|
||||||
|
{
|
||||||
|
beats: this.moveInterpreter.balancePartBeats,
|
||||||
|
endPosition: { ...startPos, balance: firstWeight },
|
||||||
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
beats: this.moveInterpreter.balancePartBeats,
|
||||||
|
endPosition: { ...startPos, balance: secondWeight },
|
||||||
|
movementPattern: { kind: SemanticAnimationKind.Linear },
|
||||||
|
},
|
||||||
|
], startPos);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Balance extends MoveInterpreter<"balance"> {
|
class Balance extends MoveInterpreter<"balance"> {
|
||||||
public readonly forwardBeats: number;
|
public readonly balancePartBeats: number;
|
||||||
public readonly backwardBeats: number;
|
|
||||||
|
|
||||||
constructor(args: MoveInterpreterCtorArgs<"balance">) {
|
constructor(args: MoveInterpreterCtorArgs<"balance">) {
|
||||||
super(args);
|
super(args);
|
||||||
|
|
||||||
this.forwardBeats = this.move.beats / 2;
|
this.balancePartBeats = this.move.beats / 2;
|
||||||
this.backwardBeats = this.move.beats - this.forwardBeats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter {
|
buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { BalanceWeight, Facing, HandConnection, HandTo, PositionKind, SemanticPosition } from "../interpreterCommon.js";
|
import { BalanceWeight, Facing, HandConnection, HandTo, PositionKind, SemanticPosition, handsInCircle } from "../interpreterCommon.js";
|
||||||
import { Move } from "../libfigureMapper.js";
|
import { Move } from "../libfigureMapper.js";
|
||||||
import { LowLevelMove, SemanticAnimationKind } from "../lowLevelMove.js";
|
import { LowLevelMove, SemanticAnimationKind } from "../lowLevelMove.js";
|
||||||
import { Hand } from "../rendererConstants.js";
|
import { Hand } from "../rendererConstants.js";
|
||||||
|
@ -11,14 +11,11 @@ export function balanceCircleInAndOut(move: Move, startPos: SemanticPosition, ba
|
||||||
}
|
}
|
||||||
|
|
||||||
balanceBeats ??= 4;
|
balanceBeats ??= 4;
|
||||||
const balancePartBeats = balanceBeats/2;
|
const balancePartBeats = balanceBeats / 2;
|
||||||
|
|
||||||
const holdingHandsInCircle: SemanticPosition = {...startPos,
|
const holdingHandsInCircle: SemanticPosition = {...startPos,
|
||||||
facing: Facing.CenterOfCircle,
|
facing: Facing.CenterOfCircle,
|
||||||
hands: new Map<Hand, HandConnection>([
|
hands: handsInCircle,
|
||||||
[Hand.Left, { hand: Hand.Right, to: HandTo.LeftInCircle }],
|
|
||||||
[Hand.Right, { hand: Hand.Left, to: HandTo.RightInCircle }],
|
|
||||||
]),
|
|
||||||
};
|
};
|
||||||
const circleBalancedIn: SemanticPosition = {...holdingHandsInCircle,
|
const circleBalancedIn: SemanticPosition = {...holdingHandsInCircle,
|
||||||
balance: BalanceWeight.Forward,
|
balance: BalanceWeight.Forward,
|
||||||
|
|
|
@ -18,6 +18,10 @@ class BoxTheGnatSingleVariant extends SingleVariantMoveInterpreter<BoxTheGnat, t
|
||||||
const balancePartBeats = balanceBeats / 2;
|
const balancePartBeats = balanceBeats / 2;
|
||||||
const twirlBeats = this.move.beats - balanceBeats;
|
const twirlBeats = this.move.beats - balanceBeats;
|
||||||
|
|
||||||
|
if (startPos.hands && startPos.hands.get(Hand.Right) === undefined && startPos.hands.get(Hand.Left)?.hand === Hand.Left) {
|
||||||
|
throw new Error(this.move.move + " shouldn't start with holding left hands. Something went wrong.");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Adjust facing?
|
// TODO Adjust facing?
|
||||||
const startPosition = { ...startPos, hands: new Map<Hand, HandConnection>([[hand, { hand, to: HandTo.DancerForward }]]) };
|
const startPosition = { ...startPos, hands: new Map<Hand, HandConnection>([[hand, { hand, to: HandTo.DancerForward }]]) };
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { RotationAnimationFacing } from "../animation.js";
|
||||||
import { Move } from "../libfigureMapper.js";
|
import { Move } from "../libfigureMapper.js";
|
||||||
import { SemanticAnimationKind } from "../lowLevelMove.js";
|
import { SemanticAnimationKind } from "../lowLevelMove.js";
|
||||||
import { Hand } from "../rendererConstants.js";
|
import { Hand } from "../rendererConstants.js";
|
||||||
|
@ -6,6 +7,10 @@ import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpre
|
||||||
const moveName: Move["move"] = "butterfly whirl";
|
const moveName: Move["move"] = "butterfly whirl";
|
||||||
|
|
||||||
class ButterflyWhirlSingleVariant extends SingleVariantMoveInterpreter<ButterflyWhirl, typeof moveName> {
|
class ButterflyWhirlSingleVariant extends SingleVariantMoveInterpreter<ButterflyWhirl, typeof moveName> {
|
||||||
|
override allowStartingClose(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
||||||
return this.handleCircleMove(({ startPos }) => {
|
return this.handleCircleMove(({ startPos }) => {
|
||||||
return this.combine([{
|
return this.combine([{
|
||||||
|
@ -14,8 +19,10 @@ class ButterflyWhirlSingleVariant extends SingleVariantMoveInterpreter<Butterfly
|
||||||
movementPattern: {
|
movementPattern: {
|
||||||
kind: SemanticAnimationKind.RotateAround,
|
kind: SemanticAnimationKind.RotateAround,
|
||||||
around: startPos.which.leftRightSide(),
|
around: startPos.which.leftRightSide(),
|
||||||
// TODO hand around isn't the same as allemande...
|
|
||||||
byHand: startPos.which.isOnLeftLookingAcross() ? Hand.Right : Hand.Left,
|
byHand: startPos.which.isOnLeftLookingAcross() ? Hand.Right : Hand.Left,
|
||||||
|
facing: startPos.which.isOnLeftLookingAcross()
|
||||||
|
? RotationAnimationFacing.Forward
|
||||||
|
: RotationAnimationFacing.Backward,
|
||||||
close: true,
|
close: true,
|
||||||
minAmount: 360,
|
minAmount: 360,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Facing, handsInCircle } from "../interpreterCommon.js";
|
import { DancerDistance, Facing, handsInCircle } from "../interpreterCommon.js";
|
||||||
import { Move } from "../libfigureMapper.js";
|
import { Move } from "../libfigureMapper.js";
|
||||||
import { SemanticAnimationKind } from "../lowLevelMove.js";
|
import { SemanticAnimationKind } from "../lowLevelMove.js";
|
||||||
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js";
|
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js";
|
||||||
|
|
|
@ -22,6 +22,9 @@ class DownTheHallSingleVariant extends SingleVariantMoveInterpreter<DownTheHall,
|
||||||
}
|
}
|
||||||
return this.handleMove(({ startPos }) => {
|
return this.handleMove(({ startPos }) => {
|
||||||
const startFacing = this.move.parameters.facing === "backward" ? Facing.Up : Facing.Down;
|
const startFacing = this.move.parameters.facing === "backward" ? Facing.Up : Facing.Down;
|
||||||
|
if (startPos.facing !== startFacing && (startPos.facing === Facing.Up || startPos.facing === Facing.Down)) {
|
||||||
|
throw new Error("Started facing the wrong direction.");
|
||||||
|
}
|
||||||
const startWhich: ShortLinesPosition = startPos.kind === PositionKind.ShortLines
|
const startWhich: ShortLinesPosition = startPos.kind === PositionKind.ShortLines
|
||||||
? startPos.which
|
? startPos.which
|
||||||
// TODO Is this always the right way to convert circle to short lines?
|
// TODO Is this always the right way to convert circle to short lines?
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Facing, SemanticPosition } from "../interpreterCommon.js";
|
import { DancerDistance, Facing, SemanticPosition } from "../interpreterCommon.js";
|
||||||
import { SemanticAnimationKind, LowLevelMove } from "../lowLevelMove.js";
|
import { SemanticAnimationKind, LowLevelMove } from "../lowLevelMove.js";
|
||||||
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, PartialLowLevelMove, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js";
|
import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, PartialLowLevelMove, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js";
|
||||||
import { balanceCircleInAndOut } from "./balanceTheRing.js";
|
import { balanceCircleInAndOut } from "./balanceTheRing.js";
|
||||||
|
|
|
@ -9,7 +9,7 @@ const moveName: Move["move"] = "roll away";
|
||||||
class RollAwaySingleVariant extends SingleVariantMoveInterpreter<RollAway, typeof moveName> {
|
class RollAwaySingleVariant extends SingleVariantMoveInterpreter<RollAway, typeof moveName> {
|
||||||
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
moveAsLowLevelMoves(): LowLevelMovesForAllDancers {
|
||||||
// TODO maybe can roll away in short lines?
|
// TODO maybe can roll away in short lines?
|
||||||
return this.handleCirclePairedMove(this.move.parameters.who, ({ id, startPos, withPos }) => {
|
return this.handleCirclePairedMove(this.move.parameters.whom, ({ id, startPos, withPos }) => {
|
||||||
let isRoller: boolean;
|
let isRoller: boolean;
|
||||||
switch (this.move.parameters.who) {
|
switch (this.move.parameters.who) {
|
||||||
case "gentlespoons":
|
case "gentlespoons":
|
||||||
|
|
|
@ -33,6 +33,10 @@ const swingEndValues: SwingEnd[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
class SwingSingleVariant extends SingleVariantMoveInterpreter<Swing, typeof moveName> {
|
class SwingSingleVariant extends SingleVariantMoveInterpreter<Swing, typeof moveName> {
|
||||||
|
override allowStartingClose(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
moveAsVariants(previousMoveVariant: string): VariantCollection {
|
moveAsVariants(previousMoveVariant: string): VariantCollection {
|
||||||
const res = new Map<string, Variant>();
|
const res = new Map<string, Variant>();
|
||||||
|
|
||||||
|
@ -204,10 +208,12 @@ class Swing extends MoveInterpreter<typeof moveName> {
|
||||||
? 2
|
? 2
|
||||||
: this.move.beats / 4;
|
: this.move.beats / 4;
|
||||||
this.swingBeats = this.move.beats - this.balancePartBeats * 2;
|
this.swingBeats = this.move.beats - this.balancePartBeats * 2;
|
||||||
|
break;
|
||||||
case "meltdown":
|
case "meltdown":
|
||||||
this.balancePartBeats = 0;
|
this.balancePartBeats = 0;
|
||||||
this.meltdownBeats = this.move.beats >= 8 ? 4 : this.move.beats / 2;
|
this.meltdownBeats = this.move.beats >= 8 ? 4 : this.move.beats / 2;
|
||||||
this.swingBeats = this.move.beats - this.meltdownBeats;
|
this.swingBeats = this.move.beats - this.meltdownBeats;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error ("Unknown swing prefix: " + this.move.parameters.prefix);
|
throw new Error ("Unknown swing prefix: " + this.move.parameters.prefix);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user