Compare commits

...

3 Commits

3 changed files with 154 additions and 25 deletions

View File

@ -18,9 +18,9 @@ function handsInShortLine({ which, facing, wavy }: { which: ShortLinesPosition;
: [Hand.Right, { hand: wavy ? Hand.Left : Hand.Right, to: HandTo.DancerRight }] : [Hand.Right, { hand: wavy ? Hand.Left : Hand.Right, to: HandTo.DancerRight }]
]); ]);
} }
function handsInLine(args: { wavy: boolean } & ({ which: ShortLinesPosition, facing: Facing.Up | Facing.Down } | { which: CirclePosition })) { function handsInLine(args: { wavy: boolean, which: ShortLinesPosition | CirclePosition, facing?: Facing }) {
if (args.which instanceof ShortLinesPosition && /*always true, type system limitation*/ 'facing' in args) { if (args.which instanceof ShortLinesPosition && (args.facing === Facing.Up || args.facing === Facing.Down)) {
return handsInShortLine(args); return handsInShortLine({ wavy: args.wavy, which: args.which, facing: args.facing });
} else { } else {
return new Map<Hand, HandConnection>([ return new Map<Hand, HandConnection>([
[Hand.Left, { hand: args.wavy ? Hand.Right : Hand.Left, to: HandTo.DancerLeft }], [Hand.Left, { hand: args.wavy ? Hand.Right : Hand.Left, to: HandTo.DancerLeft }],
@ -254,7 +254,8 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
beats: move.beats, beats: move.beats,
startPosition: { ...startPos, hands: undefined }, startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined }, endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill }, // TODO Not sure this is actually a good default...
movementPattern: { kind: SemanticAnimationKind.Linear, handsDuring: "None" },
}]); }]);
} }
} }
@ -276,13 +277,13 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
} }
const startWhich = startPosAdjusted.which; const startWhich = startPosAdjusted.which;
// TODO Can swing be across the set (top or bottom)? // TODO Can swing be across the set (top or bottom)?
const around = withPos.kind === PositionKind.Circle const around = withPos.which.leftRightSide() === startWhich.leftRightSide()
? (withPos.which.leftRightSide() === startWhich.leftRightSide() ? startWhich.leftRightSide()
? startWhich.leftRightSide() : withPos.kind === PositionKind.Circle
: startWhich instanceof CirclePosition && withPos.which.topBottomSide() === startWhich.topBottomSide() ? (startWhich instanceof CirclePosition && withPos.which.topBottomSide() === startWhich.topBottomSide()
? startWhich.topBottomSide() ? startWhich.topBottomSide()
: "Center") : "Center")
: "Center"; : "Center";
return dancerFunc({ id, startPos: startPosAdjusted, withId, withPos, around }); return dancerFunc({ id, startPos: startPosAdjusted, withId, withPos, around });
}); });
@ -498,21 +499,59 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
}); });
case "do si do": case "do si do":
return handleCirclePairedMove(move.parameters.who, ({ startPos, around }) => { if (!move.parameters.shoulder) {
throw new Error("do si do by left shoulder is unsupported.");
}
let doSiDoEndKind: "Start" | "Swap" | "ShortLinesLeft" | "ShortLinesRight";
const doSiDoCircling = move.parameters.circling % 360;
if (doSiDoCircling === 360) {
doSiDoEndKind = "Start";
} else if (doSiDoCircling === 180) {
doSiDoEndKind = "Swap";
} else if (doSiDoCircling === 90) {
doSiDoEndKind = move.parameters.shoulder ? "ShortLinesLeft" : "ShortLinesRight";
} else if (doSiDoCircling === 270) {
doSiDoEndKind = move.parameters.shoulder ? "ShortLinesRight" : "ShortLinesLeft";
} else {
throw new Error("do si do by " + move.parameters.circling + " degrees is unsupported.");
}
return handleCirclePairedMove(move.parameters.who, ({ startPos, around, withPos }) => {
// TODO Use other parameters? // TODO Use other parameters?
const startAndEndPos = { const startingPos: SemanticPosition = {
...startPos, ...startPos,
hands: undefined, hands: undefined,
facing: around === "Center" facing: around === "Center"
? Facing.CenterOfCircle ? Facing.CenterOfCircle
: around === CircleSide.Left || around === CircleSide.Right : around === CircleSide.Left || around === CircleSide.Right
? (startPos.which.isTop() ? Facing.Down : Facing.Up) ? startPos.which.facingUpOrDown()
: (startPos.which.isLeft() ? Facing.Right : Facing.Left), : startPos.which.facingAcross(),
}; };
let endPos: SemanticPosition;
switch(doSiDoEndKind) {
case "Start":
endPos = startingPos;
break;
case "Swap":
endPos = { ...withPos, facing: startingPos.facing };
break;
case "ShortLinesLeft":
case "ShortLinesRight":
endPos = {
kind: PositionKind.ShortLines,
which: startPos.which.toShortLines(doSiDoEndKind === "ShortLinesLeft" ? Hand.Left : Hand.Right),
facing: startingPos.facing,
setOffset: startingPos.setOffset,
lineOffset: startingPos.lineOffset,
}
}
return combine([{ return combine([{
beats: move.beats, beats: move.beats,
startPosition: startAndEndPos, startPosition: startingPos,
endPosition: startAndEndPos, endPosition: endPos,
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.DoSiDo, kind: SemanticAnimationKind.DoSiDo,
amount: move.parameters.circling, amount: move.parameters.circling,
@ -588,6 +627,7 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
facing: endFacing, facing: endFacing,
balance: undefined, balance: undefined,
dancerDistance: undefined, dancerDistance: undefined,
longLines: undefined,
hands: handsInLine({ wavy: false, which: endWhich, facing: endFacing }), hands: handsInLine({ wavy: false, which: endWhich, facing: endFacing }),
}; };
} }
@ -1998,6 +2038,64 @@ function moveAsLowLevelMoves({ move, nextMove, startingPos, numProgessions }: {
}], startAndEndPos); }], startAndEndPos);
}) })
case "Rory O'More":
if (move.parameters.who !== "everyone") {
throw new Error(move.move + " that doesn't include everyone is unsupported.");
}
// TODO Could be in long or short lines.
const roryDir = move.parameters.slide ? Hand.Left : Hand.Right;
const balBeats = move.parameters.bal ? move.beats / 2 : 0;
const balPartBeats = balBeats / 2;
const roryBeats = move.beats - balBeats;
return handleMove(({startPos}) => {
const isShortLines: boolean = startPos.kind === PositionKind.ShortLines;
const startingPos: SemanticPosition = {
...startPos,
hands: handsInLine({ wavy: true, which: startPos.which, facing: startPos.facing })
};
let endPos: SemanticPosition;
if (startPos.kind === PositionKind.ShortLines) {
if (startPos.facing !== Facing.Up && startPos.facing !== Facing.Down) {
throw new Error("To be in wavy lines, must be facing up or down, not " + startPos.facing);
}
const endWhich = startPos.which.shift(roryDir, startPos.facing);
endPos = {...startPos,
which: endWhich,
hands: handsInLine({ wavy: true, which: endWhich, facing: startPos.facing })
};
} else {
throw new Error(move.move + " is currently only supported in short lines.");
}
const maybeBalance: PartialLowLevelMove[] = (move.parameters.bal ? [
{
beats: balPartBeats,
endPosition: { ...startingPos, balance: roryDir === Hand.Left ? BalanceWeight.Left : BalanceWeight.Right },
movementPattern: { kind: SemanticAnimationKind.Linear },
},
{
beats: balPartBeats,
endPosition: { ...startingPos, balance: roryDir === Hand.Left ? BalanceWeight.Right : BalanceWeight.Left },
movementPattern: { kind: SemanticAnimationKind.Linear },
},
] : []);
return combine([...maybeBalance,
{
beats: roryBeats,
endPosition: endPos,
movementPattern: {
kind: SemanticAnimationKind.Linear,
minRotation: roryDir === Hand.Right ? +360 : -360,
handsDuring: "None",
},
}
], startingPos);
});
case "custom": case "custom":
if (move.parameters.custom.includes("mirrored mad robin")) { if (move.parameters.custom.includes("mirrored mad robin")) {
return handleCircleMove(({ id, startPos }) => { return handleCircleMove(({ id, startPos }) => {

View File

@ -95,6 +95,22 @@ export class CirclePosition {
][CirclePosition.enumValueToNumber(this.enumValue)]; ][CirclePosition.enumValueToNumber(this.enumValue)];
} }
public toShortLines(slideTo: Hand) : ShortLinesPosition {
return slideTo === Hand.Left
? [
ShortLinesPosition.FarLeft,
ShortLinesPosition.MiddleLeft,
ShortLinesPosition.FarRight,
ShortLinesPosition.MiddleRight,
][CirclePosition.enumValueToNumber(this.enumValue)]
: [
ShortLinesPosition.MiddleLeft,
ShortLinesPosition.FarLeft,
ShortLinesPosition.MiddleRight,
ShortLinesPosition.FarRight,
][CirclePosition.enumValueToNumber(this.enumValue)];
}
public swapDiagonal() : CirclePosition { public swapDiagonal() : CirclePosition {
return this.swapAcross().swapUpAndDown(); return this.swapAcross().swapUpAndDown();
} }
@ -220,6 +236,16 @@ export class ShortLinesPosition {
][ShortLinesPosition.enumValueToNumber(this.enumValue)]; ][ShortLinesPosition.enumValueToNumber(this.enumValue)];
} }
public shift(dir: Hand, facing: Facing.Up | Facing.Down): ShortLinesPosition {
const shift = (dir === Hand.Left) === (facing === Facing.Down) ? -1 : +1;
const newNum = ShortLinesPosition.enumValueToNumber(this.enumValue) + shift;
if (newNum < 0 || newNum > 3) {
throw new Error("Invalid shift: " + this + " facing " + facing + " to " + dir + ".");
}
return ShortLinesPosition.get(ShortLinesPosition.numberToEnumValue(newNum));
}
public isMiddle() : boolean { public isMiddle() : boolean {
return this.enumValue === ShortLinesPositionEnum.MiddleRight || this.enumValue === ShortLinesPositionEnum.MiddleLeft; return this.enumValue === ShortLinesPositionEnum.MiddleRight || this.enumValue === ShortLinesPositionEnum.MiddleLeft;
} }

View File

@ -3,7 +3,7 @@ import * as common from "./danceCommon.js";
import { DanceRole, DancerIdentity, Rotation } from "./danceCommon.js"; import { DanceRole, DancerIdentity, Rotation } from "./danceCommon.js";
import { BalanceWeight, CirclePosition, CircleSide, CircleSideOrCenter, DancerDistance, Facing, HandConnection, HandTo, LongLines, PositionKind, SemanticPosition, ShortLinesPosition, StarGrip, handsInCircle } from "./interpreterCommon.js"; import { BalanceWeight, CirclePosition, CircleSide, CircleSideOrCenter, DancerDistance, Facing, HandConnection, HandTo, LongLines, PositionKind, SemanticPosition, ShortLinesPosition, StarGrip, handsInCircle } from "./interpreterCommon.js";
import { Move } from "./libfigureMapper.js"; import { Move } from "./libfigureMapper.js";
import { DancerSetPosition, Hand, Offset, OffsetPlus, OffsetRotate, OffsetTimes, OffsetTranspose, dancerHeightOffset, dancerWidth, lineDistance, offsetZero, setDistance, setHeight, setSpacing, setWidth } from "./rendererConstants.js"; import { DancerSetPosition, Hand, Offset, OffsetPlus, OffsetRotate, OffsetTimes, OffsetTranspose, dancerHeight, dancerHeightOffset, dancerWidth, lineDistance, offsetZero, setDistance, setHeight, setSpacing, setWidth } from "./rendererConstants.js";
export enum SemanticAnimationKind { export enum SemanticAnimationKind {
@ -374,12 +374,15 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
}; };
case PositionKind.ShortLines: case PositionKind.ShortLines:
let yOffset = 0;
switch (semantic.facing) { switch (semantic.facing) {
case Facing.Up: case Facing.Up:
rotation = Rotation.Up; rotation = Rotation.Up;
yOffset = +dancerHeight;
break; break;
case Facing.Down: case Facing.Down:
rotation = Rotation.Down; rotation = Rotation.Down;
yOffset = -dancerHeight;
break; break;
case Facing.Left: case Facing.Left:
rotation = Rotation.Left; rotation = Rotation.Left;
@ -393,16 +396,16 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
switch (semantic.which) { switch (semantic.which) {
case ShortLinesPosition.FarLeft: case ShortLinesPosition.FarLeft:
position = { x: -1.5, y: 0 }; position = { x: -1.5, y: yOffset };
break; break;
case ShortLinesPosition.MiddleLeft: case ShortLinesPosition.MiddleLeft:
position = { x: -0.5, y: 0 }; position = { x: -0.5, y: yOffset };
break; break;
case ShortLinesPosition.MiddleRight: case ShortLinesPosition.MiddleRight:
position = { x: +0.5, y: 0 }; position = { x: +0.5, y: yOffset };
break; break;
case ShortLinesPosition.FarRight: case ShortLinesPosition.FarRight:
position = { x: +1.5, y: 0 }; position = { x: +1.5, y: yOffset };
break; break;
default: default:
throw "Invalid circle position: " + semantic.which; throw "Invalid circle position: " + semantic.which;
@ -445,12 +448,14 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
// TODO Hands. Might need more info? Or need context of nearby dancer SemanticPositions? // TODO Hands. Might need more info? Or need context of nearby dancer SemanticPositions?
if (!connection) return undefined; if (!connection) return undefined;
const balanceYOffset = semantic.balance === BalanceWeight.Forward ? -shortWavesBalanceAmount : semantic.balance === BalanceWeight.Backward ? shortWavesBalanceAmount : 0; const balanceYOffset = (semantic.facing === Facing.Up ? yOffset : -yOffset)
+ (semantic.balance === BalanceWeight.Forward ? -shortWavesBalanceAmount : semantic.balance === BalanceWeight.Backward ? shortWavesBalanceAmount : 0);
const balanceXOffset = semantic.balance === BalanceWeight.Left ? -balanceAmount : semantic.balance === BalanceWeight.Right ? balanceAmount : 0;
switch (connection.to) { switch (connection.to) {
case HandTo.DancerLeft: case HandTo.DancerLeft:
return { x: -0.5, y: balanceYOffset }; return { x: -0.5 + balanceXOffset, y: balanceYOffset };
case HandTo.DancerRight: case HandTo.DancerRight:
return { x: +0.5, y: balanceYOffset }; return { x: +0.5 + balanceXOffset, y: balanceYOffset };
case HandTo.DancerForward: case HandTo.DancerForward:
if (hand === connection.hand) { if (hand === connection.hand) {
return { x: 0, y: +0.5 }; return { x: 0, y: +0.5 };