Compare commits

..

No commits in common. "1b3411b21ad03bf5bd5efbfddb1eee2eeef09242" and "f96165963fe4adb86849171a3d1c61705613f353" have entirely different histories.

4 changed files with 23 additions and 578 deletions

View File

@ -4,7 +4,7 @@ import * as common from "./danceCommon.js";
import { Hand, setDistance, setHeight } from "./rendererConstants.js"; import { Hand, setDistance, setHeight } from "./rendererConstants.js";
import { nameLibFigureParameters, Move, LibFigureDance, chooser_pairz } from "./libfigureMapper.js"; import { nameLibFigureParameters, Move, LibFigureDance, chooser_pairz } from "./libfigureMapper.js";
import { LowLevelMove, SemanticAnimation, SemanticAnimationKind, animateFromLowLevelMoves } from "./lowLevelMove.js"; import { LowLevelMove, SemanticAnimation, SemanticAnimationKind, animateFromLowLevelMoves } from "./lowLevelMove.js";
import { BalanceWeight, CirclePosition, CircleSide, CircleSideOrCenter, DancerDistance, Facing, HandConnection, HandTo, LongLines, PositionKind, SemanticPosition } from "./interpreterCommon.js"; import { BalanceWeight, CirclePosition, CircleSide, DancerDistance, Facing, HandConnection, HandTo, PositionKind, SemanticPosition } from "./interpreterCommon.js";
const handsInCircle = new Map<Hand, HandConnection>([ const handsInCircle = new Map<Hand, HandConnection>([
@ -139,29 +139,6 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
return res; return res;
} }
// If true, dancer is not selected by who so they stand still for the move (or possibly do a meanwhile figure).
function excludedByWho(who: chooser_pairz, id: DancerIdentity): boolean {
switch (who) {
case "partners":
case "neighbors":
case "same roles":
case "shadows":
case "first corners":
case "second corners":
return false;
case "gentlespoons":
return id.danceRole === DanceRole.Robin;
case "ladles":
return id.danceRole === DanceRole.Lark;
case "ones":
return id.coupleRole === CoupleRole.Twos;
case "twos":
return id.coupleRole === CoupleRole.Ones;
default:
throw "Unsupported who: " + who;
}
}
function findPairOpposite(who: chooser_pairz, id: DancerIdentity): common.ExtendedDancerIdentity | null { function findPairOpposite(who: chooser_pairz, id: DancerIdentity): common.ExtendedDancerIdentity | null {
switch (who) { switch (who) {
case "partners": case "partners":
@ -193,20 +170,16 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
} }
} }
function getPosFor(id: common.ExtendedDancerIdentity) { // TOOD Type for this? Probably SemanticPosition?
const basePos = startingPos.get(id.setIdentity)!; function findCenterBetween(id: DancerIdentity, other: common.ExtendedDancerIdentity) {
return {...basePos,
setOffset: (basePos.setOffset ?? 0) + id.relativeSet,
lineOffset: (basePos.lineOffset ?? 0) + id.relativeLine,
};
}
function findCenterBetween(id: DancerIdentity, other: common.ExtendedDancerIdentity): CircleSideOrCenter {
const selfPos = startingPos.get(id)!; const selfPos = startingPos.get(id)!;
selfPos.setOffset ??= 0; selfPos.setOffset ??= 0;
selfPos.lineOffset ??= 0; selfPos.lineOffset ??= 0;
const otherBasePos = startingPos.get(other.setIdentity)!;
const otherPos = getPosFor(other); const otherPos : SemanticPosition = {...otherBasePos,
setOffset: (otherBasePos.setOffset ?? 0) + other.relativeSet,
lineOffset: (otherBasePos.lineOffset ?? 0) + other.relativeLine,
};
if (selfPos.kind === PositionKind.Circle && otherPos.kind === PositionKind.Circle) { if (selfPos.kind === PositionKind.Circle && otherPos.kind === PositionKind.Circle) {
if (!(selfPos.lineOffset === otherPos.lineOffset && selfPos.setOffset === otherPos.setOffset)) { if (!(selfPos.lineOffset === otherPos.lineOffset && selfPos.setOffset === otherPos.setOffset)) {
@ -225,11 +198,6 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
const res = new Map<DancerIdentity, LowLevelMove[]>(); const res = new Map<DancerIdentity, LowLevelMove[]>();
switch (move.move) { switch (move.move) {
case "balance the ring":
for (const [id, startPos] of startingPos.entries()) {
res.set(id, balanceCircleInAndOut(move, startPos));
}
return res;
case "petronella": case "petronella":
for (const [id, startPos] of startingPos.entries()) { for (const [id, startPos] of startingPos.entries()) {
if (startPos.kind !== PositionKind.Circle) { if (startPos.kind !== PositionKind.Circle) {
@ -300,16 +268,6 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
return res; return res;
case "swing": case "swing":
for (const [id, startPos] of startingPos.entries()) { for (const [id, startPos] of startingPos.entries()) {
if (excludedByWho(move.parameters.who, id)) {
res.set(id, combine([{
beats: move.beats,
startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
}]));
continue;
}
// TODO swing can start from other positions. // TODO swing can start from other positions.
// TODO swing end is only in notes / looking at next move. // TODO swing end is only in notes / looking at next move.
if (startPos.kind !== PositionKind.Circle) { if (startPos.kind !== PositionKind.Circle) {
@ -442,18 +400,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
return res; return res;
case "allemande": case "allemande":
case "gyre":
for (const [id, startPos] of startingPos.entries()) { for (const [id, startPos] of startingPos.entries()) {
if (excludedByWho(move.parameters.who, id)) {
res.set(id, combine([{
beats: move.beats,
startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
}]));
continue;
}
// TODO allemande can start from other positions. // TODO allemande can start from other positions.
if (startPos.kind !== PositionKind.Circle) { if (startPos.kind !== PositionKind.Circle) {
throw move.move + " must start in a circle, but " + id + " is at " + startPos; throw move.move + " must start in a circle, but " + id + " is at " + startPos;
@ -462,12 +409,18 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
const withId = findPairOpposite(move.parameters.who, id); const withId = findPairOpposite(move.parameters.who, id);
// findPairOpposite of null means this dancer doesn't participate in this move. // findPairOpposite of null means this dancer doesn't participate in this move.
if (!withId) { if (!withId) {
throw "fairPairOpposite and excludedByWho disagree on who does not act: who=" + move.parameters.who + ", id=" + id; res.set(id, combine([prevEnd => ({
} beats: move.beats,
startPosition: { ...prevEnd, hands: undefined },
endPosition: { ...prevEnd, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
})], startPos));
continue;
};
const around = findCenterBetween(id, withId); const around = findCenterBetween(id, withId);
// TODO Not sure if this is right. // TODO Not sure if this is right.
const byHandOrShoulder = (move.move === "allemande" ? move.parameters.hand : move.parameters.shoulder) ? Hand.Right : Hand.Left; const byHand = move.parameters.hand ? Hand.Right : Hand.Left;
const swap = move.parameters.circling % 360 === 180; const swap = move.parameters.circling % 360 === 180;
if (!swap && move.parameters.circling % 360 !== 0) { if (!swap && move.parameters.circling % 360 !== 0) {
throw "Unsupported allemande circle amount: " + move.parameters.circling; throw "Unsupported allemande circle amount: " + move.parameters.circling;
@ -485,9 +438,9 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
endPosition, endPosition,
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.RotateAround, kind: SemanticAnimationKind.RotateAround,
minAmount: byHandOrShoulder === Hand.Right ? move.parameters.circling : -move.parameters.circling, minAmount: byHand === Hand.Right ? move.parameters.circling : -move.parameters.circling,
around, around,
byHand: move.move === "allemande" ? byHandOrShoulder : undefined, byHand,
}, },
}, },
], startPos)); ], startPos));
@ -504,11 +457,10 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
} }
res.set(id, combine([ res.set(id, combine([
{ prevEnd => ({
beats: move.beats, beats: move.beats,
endPosition: { endPosition: {
...startPos, ...prevEnd,
facing: Facing.CenterOfCircle,
hands: handsInCircle, hands: handsInCircle,
which: startPos.which.circleLeft(places), which: startPos.which.circleLeft(places),
}, },
@ -516,7 +468,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
kind: SemanticAnimationKind.Circle, kind: SemanticAnimationKind.Circle,
places, places,
} }
}, }),
], { ...startPos, facing: Facing.CenterOfCircle })); ], { ...startPos, facing: Facing.CenterOfCircle }));
} }
@ -524,24 +476,11 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
case "California twirl": case "California twirl":
for (const [id, startPos] of startingPos.entries()) { for (const [id, startPos] of startingPos.entries()) {
if (excludedByWho(move.parameters.who, id)) {
res.set(id, combine([{
beats: move.beats,
startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
}]));
continue;
}
if (startPos.kind !== PositionKind.Circle) { if (startPos.kind !== PositionKind.Circle) {
throw move.move + " must start in a circle, but " + id + " is at " + startPos; throw move.move + " must start in a circle, but " + id + " is at " + startPos;
} }
// TODO does "who" matter here or is it entirely positional? At least need to know who to omit.
const onLeft : boolean = startPos.which.isOnLeftLookingUpAndDown(); const onLeft : boolean = startPos.which.isOnLeftLookingUpAndDown();
// TODO get rid of this 1 beat set up and make it part of TwirlSwap?
res.set(id, combine([ res.set(id, combine([
{ {
beats: 1, beats: 1,
@ -571,380 +510,6 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
}], startPos)); }], startPos));
} }
return res;
case "box the gnat":
for (const [id, startPos] of startingPos.entries()) {
if (excludedByWho(move.parameters.who, id)) {
res.set(id, combine([{
beats: move.beats,
startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
}]));
continue;
}
const hand = move.parameters.hand ? Hand.Right : Hand.Left;
const balanceBeats = move.parameters.bal
? move.beats > 4
? move.beats - 4
: 2
: 0;
const balancePartBeats = balanceBeats / 2;
const twirlBeats = move.beats - balanceBeats;
// TODO Adjust facing?
const startPosition = { ...startPos, hands: new Map<Hand, HandConnection>([[hand, { hand, to: HandTo.DancerForward }]]) };
const withId = findPairOpposite(move.parameters.who, id);
// findPairOpposite of null means this dancer doesn't participate in this move.
if (!withId) {
throw "fairPairOpposite and excludedByWho disagree on who does not act: who=" + move.parameters.who + ", id=" + id;
}
const around = findCenterBetween(id, withId);
if (around === "Center") {
throw "TwirlSwap around center is unsupported.";
}
if (move.parameters.bal) {
res.set(id, combine([
{
beats: balancePartBeats,
endPosition: {
...startPosition,
balance: BalanceWeight.Forward,
},
movementPattern: {
kind: SemanticAnimationKind.Linear,
}
},
{
beats: balancePartBeats,
endPosition: {
...startPosition,
balance: BalanceWeight.Backward,
},
movementPattern: {
kind: SemanticAnimationKind.Linear,
}
},
{
beats: twirlBeats,
endPosition: getPosFor(withId),
movementPattern: {
kind: SemanticAnimationKind.TwirlSwap,
around,
hand,
}
}], startPosition));
} else {
res.set(id, combine([
{
beats: twirlBeats,
endPosition: getPosFor(withId),
movementPattern: {
kind: SemanticAnimationKind.TwirlSwap,
around,
hand,
}
}], startPosition));
}
}
return res;
case "pull by dancers":
for (const [id, startPos] of startingPos.entries()) {
if (excludedByWho(move.parameters.who, id)) {
res.set(id, combine([{
beats: move.beats,
startPosition: { ...startPos, hands: undefined },
endPosition: { ...startPos, hands: undefined },
movementPattern: { kind: SemanticAnimationKind.StandStill },
}]));
continue;
}
const hand = move.parameters.hand ? Hand.Right : Hand.Left;
const balanceBeats = move.parameters.bal
? move.beats > 4
? move.beats - 4
: 2
: 0;
const balancePartBeats = balanceBeats / 2;
const pullBeats = move.beats - balanceBeats;
const withId = findPairOpposite(move.parameters.who, id);
// findPairOpposite of null means this dancer doesn't participate in this move.
if (!withId) {
throw "fairPairOpposite and excludedByWho disagree on who does not act: who=" + move.parameters.who + ", id=" + id;
}
const around = findCenterBetween(id, withId);
// TODO Adjust facing?
const startPosition = {
...startPos,
hands: new Map<Hand, HandConnection>([
[
hand,
{ hand, to: around === "Center" ? HandTo.DiagonalAcrossCircle : HandTo.DancerForward }
]])
};
if (move.parameters.bal) {
res.set(id, combine([
{
beats: balancePartBeats,
endPosition: {
...startPosition,
balance: BalanceWeight.Forward,
},
movementPattern: {
kind: SemanticAnimationKind.Linear,
}
},
{
beats: balancePartBeats,
endPosition: {
...startPosition,
balance: BalanceWeight.Backward,
},
movementPattern: {
kind: SemanticAnimationKind.Linear,
}
},
{
beats: pullBeats,
endPosition: getPosFor(withId),
movementPattern: {
kind: SemanticAnimationKind.PassBy,
around,
side: hand,
withHands: true,
}
}], startPosition));
} else {
res.set(id, combine([
{
beats: pullBeats,
endPosition: getPosFor(withId),
movementPattern: {
kind: SemanticAnimationKind.PassBy,
around,
side: hand,
withHands: true,
}
}], startPosition));
}
}
return res;
case "chain":
for (const [id, startPos] of startingPos.entries()) {
if (startPos.kind !== PositionKind.Circle) {
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
}
const mainRole = move.parameters.who === "gentlespoons" ? DanceRole.Lark : DanceRole.Robin;
const pullBeats = move.beats / 2;
const turnBeats = move.beats - pullBeats;
if (id.danceRole === mainRole) {
const hand = move.parameters.hand ? Hand.Right : Hand.Left;
const endWhich = startPos.which.swapDiagonal();
let endSet = startPos.setOffset ?? 0;
let to : HandTo;
switch (move.parameters.dir) {
case "along":
throw "Don't know what chaining along the set means.";
case "across":
to = HandTo.DiagonalAcrossCircle;
break;
case "right diagonal":
to = HandTo.RightDiagonalAcrossCircle;
endSet += startPos.which.isLeft() ? -1 : +1;
break;
case "left diagonal":
to = HandTo.LeftDiagonalAcrossCircle;
endSet += startPos.which.isLeft() ? +1 : -1;
break;
}
const startPosition = { ...startPos, hands: new Map<Hand, HandConnection>([[hand, { hand, to }]]) };
const turnTo = hand === Hand.Right ? HandTo.DancerRight : HandTo.DancerLeft;
res.set(id, combine([
{
beats: pullBeats,
endPosition: {
...startPos,
which: endWhich,
setOffset: endSet,
hands: new Map<Hand, HandConnection>([
[Hand.Left, { hand: Hand.Left, to: turnTo }],
[Hand.Right, { hand: Hand.Right, to: turnTo }],
]),
},
movementPattern: {
kind: SemanticAnimationKind.PassBy,
around: "Center",
side: hand,
withHands: true,
}
},
prevEnd => ({
beats: turnBeats,
endPosition: {
kind: PositionKind.Circle,
which: endWhich.swapUpAndDown(),
facing: endWhich.isLeft() ? Facing.Right : Facing.Left,
hands: prevEnd.hands,
setOffset: prevEnd.setOffset,
lineOffset: prevEnd.lineOffset,
},
movementPattern: {
kind: SemanticAnimationKind.CourtesyTurn,
}
})
], startPosition));
} else {
res.set(id, combine([
{
beats: pullBeats,
endPosition: startPos,
movementPattern: {
kind: SemanticAnimationKind.StandStill,
}
},
{
beats: turnBeats,
endPosition: {
...startPos,
// TODO Does CourtesyTurn always swap?
which: startPos.which.swapUpAndDown(),
},
movementPattern: {
kind: SemanticAnimationKind.CourtesyTurn,
}
}
], startPos));
}
}
return res;
case "long lines":
for (const [id, startPos] of startingPos.entries()) {
if (startPos.kind !== PositionKind.Circle) {
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
}
const startPosition: SemanticPosition = {
...startPos,
longLines: undefined,
// TODO Occassionally dances have long lines facing out. This will get that wrong.
facing: startPos.which.isLeft() ? Facing.Right : Facing.Left,
hands: new Map<Hand, HandConnection>([
[Hand.Left, { hand: Hand.Right, to: HandTo.DancerLeft }],
[Hand.Right, { hand: Hand.Left, to: HandTo.DancerRight }],
]),
};
if (move.parameters.go) {
const forwardBeats = move.beats / 2;
const backwardBeats = move.beats - forwardBeats;
res.set(id, combine([
{
beats: forwardBeats,
endPosition: { ...startPosition, longLines: LongLines.Forward },
movementPattern: { kind: SemanticAnimationKind.Linear },
},
{
beats: backwardBeats,
endPosition: startPosition,
movementPattern: { kind: SemanticAnimationKind.Linear },
},
], startPosition));
} else {
res.set(id, combine([{
beats: move.beats,
endPosition: { ...startPosition, longLines: LongLines.Forward },
movementPattern: { kind: SemanticAnimationKind.Linear },
}], startPosition));
}
}
return res;
case "roll away":
for (const [id, startPos] of startingPos.entries()) {
if (startPos.kind !== PositionKind.Circle) {
throw move.move + " must start in a circle, but " + id + " is at " + startPos;
}
let isRoller: boolean;
switch (move.parameters.who) {
case "gentlespoons":
isRoller = id.danceRole === DanceRole.Lark;
break;
case "ladles":
isRoller = id.danceRole === DanceRole.Robin;
break;
case "ones":
isRoller = id.coupleRole === CoupleRole.Ones;
break;
case "twos":
isRoller = id.coupleRole === CoupleRole.Twos;
break;
case "first corners":
case "second corners":
throw "Roll away in contra corners is unsupported.";
}
let oppositeId = findPairOpposite(move.parameters.whom, id);
if (!oppositeId) {
// TODO
throw "Failed to identify dancer to roll away with.";
}
// TODO This isn't quite right if there's no 1/2 sash?
const oppositePos = getPosFor(oppositeId);
let swapPos = oppositePos;
if (swapPos.kind === PositionKind.Circle && swapPos.longLines) {
swapPos = { ...swapPos, longLines: undefined };
}
// TODO animate hands?
if (isRoller) {
if (move.parameters["½sash"]) {
// swap positions by sliding
res.set(id, combine([{
beats: move.beats,
endPosition: swapPos,
movementPattern: { kind: SemanticAnimationKind.Linear },
}], startPos));
} else {
// just stand still
res.set(id, combine([{
beats: move.beats,
endPosition: { ...startPos, longLines: undefined },
movementPattern: { kind: SemanticAnimationKind.Linear },
}], startPos));
}
} else {
// being rolled away, so do a spin
res.set(id, combine([{
beats: move.beats,
// TODO Is this the right end position logic?
endPosition: move.parameters["½sash"] ? swapPos : { ...startPos, which: startPos.which.swapDiagonal() },
movementPattern: { kind: SemanticAnimationKind.RollAway },
}], startPos));
}
}
return res; return res;
} }

View File

@ -95,10 +95,6 @@ export class CirclePosition {
][CirclePosition.enumValueToNumber(this.enumValue)]; ][CirclePosition.enumValueToNumber(this.enumValue)];
} }
public swapDiagonal() : CirclePosition {
return this.swapAcross().swapUpAndDown();
}
public facingCenterRotation() : Rotation { public facingCenterRotation() : Rotation {
return (45 + 90 * CirclePosition.enumValueToNumber(this.enumValue)) % 360; return (45 + 90 * CirclePosition.enumValueToNumber(this.enumValue)) % 360;
} }
@ -136,79 +132,6 @@ export class CirclePosition {
} }
} }
enum ShortLinesPositionEnum {
FarLeft = "FarLeft",
MiddleLeft = "MiddleLeft",
MiddleRight = "MiddleRight",
FarRight = "FarRight",
}
export class ShortLinesPosition {
public static readonly FarLeft = new ShortLinesPosition(ShortLinesPositionEnum.FarLeft);
public static readonly MiddleLeft = new ShortLinesPosition(ShortLinesPositionEnum.MiddleLeft);
public static readonly MiddleRight = new ShortLinesPosition(ShortLinesPositionEnum.MiddleRight);
public static readonly FarRight = new ShortLinesPosition(ShortLinesPositionEnum.FarRight);
private readonly enumValue: ShortLinesPositionEnum;
private constructor(enumValue: ShortLinesPositionEnum) {
this.enumValue = enumValue;
}
private static enumValueToNumber(enumValue: ShortLinesPositionEnum) : number {
switch (enumValue) {
case ShortLinesPositionEnum.FarLeft:
return 0;
case ShortLinesPositionEnum.MiddleLeft:
return 1;
case ShortLinesPositionEnum.MiddleRight:
return 2;
case ShortLinesPositionEnum.FarRight:
return 3;
}
}
private static numberToEnumValue(num: number) : ShortLinesPositionEnum {
if (num < 0 || num > 3) {
num %= 4;
if (num < 0) num += 4;
}
return [
ShortLinesPositionEnum.FarLeft,
ShortLinesPositionEnum.MiddleLeft,
ShortLinesPositionEnum.MiddleRight,
ShortLinesPositionEnum.FarRight,
][num];
}
private static get(enumValue: ShortLinesPositionEnum) : ShortLinesPosition {
return [
ShortLinesPosition.FarLeft,
ShortLinesPosition.MiddleLeft,
ShortLinesPosition.MiddleRight,
ShortLinesPosition.FarRight,
][this.enumValueToNumber(enumValue)];
}
public isMiddle() : boolean {
return this.enumValue === ShortLinesPositionEnum.MiddleRight || this.enumValue === ShortLinesPositionEnum.MiddleLeft;
}
public leftRightSide() : CircleSide.Left | CircleSide.Right {
return this.enumValue === ShortLinesPositionEnum.FarLeft || this.enumValue === ShortLinesPositionEnum.MiddleLeft
? CircleSide.Left
: CircleSide.Right;
}
public isLeft() : boolean {
return this.leftRightSide() === CircleSide.Left;
}
public toString() : string {
return this.enumValue.toString();
}
}
export enum Facing { export enum Facing {
CenterOfCircle = "CenterOfCircle", CenterOfCircle = "CenterOfCircle",
Up = "Up", Up = "Up",
@ -220,9 +143,6 @@ export enum HandTo {
LeftInCircle = "LeftInCircle", LeftInCircle = "LeftInCircle",
RightInCircle = "RightInCircle", RightInCircle = "RightInCircle",
AcrossCircle = "AcrossCircle", AcrossCircle = "AcrossCircle",
DiagonalAcrossCircle = "DiagonalAcrossCircle",
LeftDiagonalAcrossCircle = "LeftDiagonalAcrossCircle",
RightDiagonalAcrossCircle = "RightDiagonalAcrossCircle",
DancerForward = "DancerForward", DancerForward = "DancerForward",
DancerLeft = "DancerLeft", DancerLeft = "DancerLeft",
DancerRight = "DancerRight", DancerRight = "DancerRight",
@ -245,9 +165,6 @@ export enum DancerDistance {
SwingLark = "SwingLark", SwingLark = "SwingLark",
SwingRobin = "SwingRobin", SwingRobin = "SwingRobin",
} }
export enum LongLines {
Forward = "Forward",
}
export type SemanticPosition = { export type SemanticPosition = {
kind: PositionKind.Circle, kind: PositionKind.Circle,
setOffset?: number, setOffset?: number,
@ -257,13 +174,10 @@ export type SemanticPosition = {
hands?: Map<Hand, HandConnection>, hands?: Map<Hand, HandConnection>,
balance?: BalanceWeight, balance?: BalanceWeight,
dancerDistance?: DancerDistance, dancerDistance?: DancerDistance,
longLines?: LongLines,
} | { } | {
kind: PositionKind.ShortLines, kind: PositionKind.ShortLines,
setOffset?: number, setOffset?: number,
lineOffset?: number, lineOffset?: number,
which: ShortLinesPosition,
facing: Facing,
hands?: Map<Hand, HandConnection>, hands?: Map<Hand, HandConnection>,
balance?: BalanceWeight, balance?: BalanceWeight,
}; };

View File

@ -28,11 +28,6 @@ export enum SemanticAnimationKind {
RotateAround = "RotateAround", RotateAround = "RotateAround",
Swing = "Swing", Swing = "Swing",
CourtesyTurn = "CourtesyTurn",
// Dancer being rolled away / spinning. Other dancer is just Linear.
RollAway = "RollAway",
} }
export type SemanticAnimation = { export type SemanticAnimation = {
kind: SemanticAnimationKind.StandStill, kind: SemanticAnimationKind.StandStill,
@ -82,19 +77,6 @@ export type SemanticAnimation = {
around: CircleSide, around: CircleSide,
hand: Hand, hand: Hand,
} | {
kind: SemanticAnimationKind.PassBy,
around: CircleSideOrCenter,
side: Hand,
// If true, pull by the specified hand, if false, just pass by that side without hands.
withHands: boolean,
} | {
kind: SemanticAnimationKind.CourtesyTurn,
} | {
kind: SemanticAnimationKind.RollAway,
} }
@ -271,9 +253,6 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
const xSign = connection.to === HandTo.LeftInCircle ? -1 : +1; const xSign = connection.to === HandTo.LeftInCircle ? -1 : +1;
const balanceFactor = semantic.balance === BalanceWeight.Forward ? 1-balanceAmount : 1; const balanceFactor = semantic.balance === BalanceWeight.Forward ? 1-balanceAmount : 1;
return { x: balanceFactor*xSign/Math.sqrt(2), y: balanceFactor/Math.sqrt(2) }; return { x: balanceFactor*xSign/Math.sqrt(2), y: balanceFactor/Math.sqrt(2) };
case HandTo.DiagonalAcrossCircle:
// TODO Is "diagonal" even enough information?
return { x: -0.5, y: +0.5 }
default: default:
throw "Unkown connection: " + connection.to; throw "Unkown connection: " + connection.to;
} }
@ -515,17 +494,6 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
endTransitionBeats: 1, endTransitionBeats: 1,
}) })
]; ];
// TODO Unsupported moves, just doing linear for now.
case SemanticAnimationKind.PassBy:
case SemanticAnimationKind.CourtesyTurn:
case SemanticAnimationKind.RollAway:
return [
new animation.LinearAnimationSegment({
beats: move.beats,
startPosition: startSetPosition,
endPosition: endSetPosition,
})
]
} }
throw "Unsupported move in animateLowLevelMove: " + JSON.stringify(move); throw "Unsupported move in animateLowLevelMove: " + JSON.stringify(move);

View File

@ -143,9 +143,7 @@ export class Renderer {
const trailLengthInBeats = 1; const trailLengthInBeats = 1;
const incrementLength = trailLengthInBeats / increments; const incrementLength = trailLengthInBeats / increments;
progression ??= 0; progression ??= 0;
const offsetSets = this.animation.progression.y === 0 const offsetSets = -((progression - (progression % 2)) / 2) / ((this.animation.progression.y * 2) / setDistance);
? 0
: -((progression - (progression % 2)) / 2) / ((this.animation.progression.y * 2) / setDistance);
for (var i = increments; i >= 0; i--) { for (var i = increments; i >= 0; i--) {
const beatToDraw = beat - i*incrementLength; const beatToDraw = beat - i*incrementLength;
this.ctx.globalAlpha = i == 0 ? 1 : (1 - i/increments)*0.3; this.ctx.globalAlpha = i == 0 ? 1 : (1 - i/increments)*0.3;