import { DanceRole, CoupleRole } from "../danceCommon.js"; import { SemanticPosition, Facing, HandConnection, HandTo, BalanceWeight, handsInLine, LongLines } 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, Variant, VariantCollection, moveInterpreters } from "./_moveInterpreter.js"; const moveName: Move["move"] = "box circulate"; class BoxCirculateSingleVariant extends SingleVariantMoveInterpreter { moveAsVariants(previousMoveVariant: string): VariantCollection { const res = new Map(); for (const crossPartway of (this.move.note?.includes("catch") ? [true] : [true, false])) { try { res.set(crossPartway ? "CrossPartway" : "Normal", { lowLevelMoves: this.moveAsLowLevelMovesCross(crossPartway), previousMoveVariant }); } catch { } } return res; } moveAsLowLevelMovesCross(crossPartway: boolean): LowLevelMovesForAllDancers { const circulateRight: boolean = this.move.parameters.hand; const whoCrosses = this.move.parameters.who; return this.handleCircleMove(({ id, startPos }) => { let isCrossing: boolean; switch (whoCrosses) { case "gentlespoons": isCrossing = id.danceRole === DanceRole.Lark; break; case "ladles": isCrossing = id.danceRole === DanceRole.Robin; break; case "ones": isCrossing = id.coupleRole === CoupleRole.Ones; break; case "twos": isCrossing = id.coupleRole === CoupleRole.Twos; break; case "first corners": case "second corners": throw "first/second corner leading box circulate doesn't make sense?"; } // Starts in long wavy lines. const startingPos: SemanticPosition = { ...startPos, facing: isCrossing ? startPos.which.facingAcross() : startPos.which.facingOut(), hands: new Map([ [Hand.Left, { hand: Hand.Left, to: HandTo.DancerLeft }], [Hand.Right, { hand: Hand.Right, to: HandTo.DancerRight }], ]), balance: undefined, longLines: undefined, dancerDistance: undefined, }; const balance: PartialLowLevelMove[] = this.move.parameters.bal ? [ { beats: 2, endPosition: { ...startingPos, balance: circulateRight ? BalanceWeight.Right : BalanceWeight.Left }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, { beats: 2, endPosition: { ...startingPos, balance: BalanceWeight.Backward }, movementPattern: { kind: SemanticAnimationKind.Linear }, }, ] : []; const circulate: PartialLowLevelMove = { beats: this.move.beats - (this.move.parameters.bal ? 4 : 0), endPosition: { ...startingPos, which: isCrossing ? startingPos.which.swapAcross() : startingPos.which.swapUpAndDown(), facing: isCrossing ? startingPos.facing : startingPos.facing === Facing.Right ? Facing.Left : Facing.Right, longLines: isCrossing && crossPartway ? LongLines.Center : undefined, }, movementPattern: { // TODO Not sure loop should really be linear... kind: SemanticAnimationKind.Linear, minRotation: isCrossing ? undefined : circulateRight ? 180 : -180, handsDuring: "None", } }; return this.combine([...balance, circulate], startingPos); }); } } class BoxCirculate extends MoveInterpreter { buildSingleVariantMoveInterpreter(startingPos: SemanticPositionsForAllDancers): ISingleVariantMoveInterpreter { return new BoxCirculateSingleVariant(this, startingPos); } } moveInterpreters.set(moveName, BoxCirculate);