import { SemanticPosition, BalanceWeight, ShortLinesPosition, Facing, PositionKind, handsInShortLine, handsInLine } from "../interpreterCommon.js"; import { Move } from "../libfigureMapper.js"; import { SemanticAnimationKind } from "../lowLevelMove.js"; import { Hand } from "../rendererConstants.js"; import { ISingleVariantMoveInterpreter, LowLevelMovesForAllDancers, MoveInterpreter, PartialLowLevelMove, SemanticPositionsForAllDancers, SingleVariantMoveInterpreter, moveInterpreters } from "./_moveInterpreter.js"; const moveName: Move["move"] = "form an ocean wave"; class FormAnOceanWaveSingleVariant extends SingleVariantMoveInterpreter { moveAsLowLevelMoves(): LowLevelMovesForAllDancers { if (this.move.parameters.dir !== "across") { throw new Error("Diagonal ocean waves are unsupported."); } const centerHand = this.move.parameters["c.hand"] ? Hand.Right : Hand.Left; if (this.move.parameters["pass thru"]) { return this.handleCircleMove(({ id, startPos }) => { const balBeats = this.move.parameters.bal ? this.move.beats / 2 : 0; const balPartBeats = balBeats / 2; // TODO balance direction? const balance: ((prevEnd: SemanticPosition) => PartialLowLevelMove)[] = this.move.parameters.bal ? [ prevEnd => ({ beats: balPartBeats, endPosition: { ...prevEnd, balance: BalanceWeight.Forward }, movementPattern: { kind: SemanticAnimationKind.Linear }, }), prevEnd => ({ beats: balPartBeats, endPosition: { ...prevEnd, balance: BalanceWeight.Backward }, movementPattern: { kind: SemanticAnimationKind.Linear }, }), ] : []; const isCenter = this.findPairOpposite(this.move.parameters.center, id) !== null; const which = startPos.which.isLeft() ? isCenter ? ShortLinesPosition.MiddleRight : ShortLinesPosition.FarRight : isCenter ? ShortLinesPosition.MiddleLeft : ShortLinesPosition.FarLeft; // TODO Not sure this facing computation is right. const facing = (centerHand === Hand.Left) !== isCenter !== which.isLeft() ? Facing.Up : Facing.Down; return this.combine([{ beats: this.move.beats - balBeats, endPosition: { kind: PositionKind.ShortLines, which, facing, hands: handsInShortLine({ which, facing, wavy: true }), setOffset: startPos.setOffset, lineOffset: startPos.lineOffset, }, movementPattern: which.isMiddle() ? { kind: SemanticAnimationKind.Linear } : { kind: SemanticAnimationKind.RotateAround, around: "Center", minAmount: centerHand === Hand.Left ? 1 : -1, close: false, byHand: undefined, }, }, ...balance], startPos); }); } else { return this.handleMove(({ id, startPos }) => { const isCenter = this.findPairOpposite(this.move.parameters.center, id) !== null; const which = startPos.which.isLeft() ? (isCenter ? ShortLinesPosition.MiddleLeft : ShortLinesPosition.FarLeft) : (isCenter ? ShortLinesPosition.MiddleRight : ShortLinesPosition.FarRight); const facing = (centerHand === Hand.Right) === (which === ShortLinesPosition.MiddleLeft || which === ShortLinesPosition.FarRight) ? Facing.Down : Facing.Up; const linePos: SemanticPosition = { kind: PositionKind.ShortLines, which, facing, hands: handsInLine({ wavy: true, which, facing }), setOffset: startPos.setOffset, lineOffset: startPos.lineOffset, }; if (this.move.parameters.bal) { // TODO Is balance weight always forward/backward here? const balanceBeats = Math.min(this.move.beats, 4); const transitionBeats = this.move.beats - balanceBeats; const balanceForwardBeats = balanceBeats / 2; const balanceBackwardBeats = balanceBeats - balanceForwardBeats; const balance: [PartialLowLevelMove, PartialLowLevelMove] = [ { beats: balanceForwardBeats, endPosition: { ...linePos, balance: BalanceWeight.Forward }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, { beats: balanceBackwardBeats, endPosition: { ...linePos, balance: BalanceWeight.Backward }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, ]; if (transitionBeats === 0) { // No transition, just balance. return this.combine(balance, linePos); } else { return this.combine([{ beats: transitionBeats, endPosition: linePos, movementPattern: { kind: SemanticAnimationKind.Linear }, }, ...balance], startPos); } } else { return this.combine([{ beats: this.move.beats, endPosition: linePos, movementPattern: { kind: SemanticAnimationKind.Linear }, }], startPos); } }); } } } class FormAnOceanWave extends MoveInterpreter { buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter { return new FormAnOceanWaveSingleVariant(this, startingPos); } } moveInterpreters.set(moveName, FormAnOceanWave);