Compare commits

..

No commits in common. "f533e3d2023260ed6ee9f42fccf955753bbd2c4e" and "084088dded800486351545c261c5b058834cd948" have entirely different histories.

4 changed files with 20 additions and 132 deletions

View File

@ -40,11 +40,6 @@
} }
table, tr, th, td { table, tr, th, td {
border: solid black 1px; border: solid black 1px;
vertical-align: top;
}
table pre {
position: sticky;
top: 0;
} }
th.Ones.Lark { th.Ones.Lark {
background-color: hsl(0, 80%, 50%); background-color: hsl(0, 80%, 50%);

View File

@ -1,4 +1,4 @@
import { DancerIdentity, Rotation, normalizeRotation } from "./danceCommon.js"; import { DancerIdentity, normalizeRotation } from "./danceCommon.js";
import { DancerSetPosition, DancersSetPositions, Hand } from "./rendererConstants.js"; import { DancerSetPosition, DancersSetPositions, Hand } from "./rendererConstants.js";
import { Offset, leftShoulder, rightShoulder, degreesToRadians, radiansToDegrees } from "./rendererConstants.js"; import { Offset, leftShoulder, rightShoulder, degreesToRadians, radiansToDegrees } from "./rendererConstants.js";
@ -82,7 +82,6 @@ export class LinearAnimationSegment extends AnimationSegment {
export enum RotationAnimationFacing { export enum RotationAnimationFacing {
Linear = "Linear", // Default, linearly interpolate. Linear = "Linear", // Default, linearly interpolate.
Center = "Center", // Always face the center. Center = "Center", // Always face the center.
CenterRelative = "CenterRelative", // Always face the center.
Forward = "Forward", // Always face the direction of the rotation. Forward = "Forward", // Always face the direction of the rotation.
Backward = "Backward", // Opposite of forward. Backward = "Backward", // Opposite of forward.
} }
@ -96,7 +95,6 @@ export class RotationAnimationSegment extends AnimationSegment {
private readonly endRotation: number; private readonly endRotation: number;
private readonly center: Offset; private readonly center: Offset;
private readonly facing: RotationAnimationFacing; private readonly facing: RotationAnimationFacing;
private readonly startFacing: Rotation;
constructor(beats: number, startPosition: DancerSetPosition, endPosition: DancerSetPosition, constructor(beats: number, startPosition: DancerSetPosition, endPosition: DancerSetPosition,
rotation: number, around: RotationAround, facing: RotationAnimationFacing) { rotation: number, around: RotationAround, facing: RotationAnimationFacing) {
@ -115,7 +113,6 @@ export class RotationAnimationSegment extends AnimationSegment {
return -radiansToDegrees(radians); return -radiansToDegrees(radians);
} }
this.startRotation = positionToDegrees(startPosition.position); this.startRotation = positionToDegrees(startPosition.position);
this.startFacing = startPosition.rotation;
const actualRotation = normalizeRotation(positionToDegrees(endPosition.position) - this.startRotation, const actualRotation = normalizeRotation(positionToDegrees(endPosition.position) - this.startRotation,
rotation); rotation);
this.endRotation = this.startRotation + actualRotation; this.endRotation = this.startRotation + actualRotation;
@ -145,8 +142,6 @@ export class RotationAnimationSegment extends AnimationSegment {
switch (this.facing) { switch (this.facing) {
case RotationAnimationFacing.Center: case RotationAnimationFacing.Center:
return degrees - 90; return degrees - 90;
case RotationAnimationFacing.CenterRelative:
return degrees - this.startRotation + this.startFacing;
case RotationAnimationFacing.Forward: case RotationAnimationFacing.Forward:
return degrees + 180; return degrees + 180;
case RotationAnimationFacing.Backward: case RotationAnimationFacing.Backward:

View File

@ -160,14 +160,6 @@ enum BalanceWeight {
Left = "Left", Left = "Left",
Right = "Right", Right = "Right",
} }
enum DancerDistance {
Normal = "Normal",
Compact = "Compact", // allemande, etc.
// Swings asymmetrical, but some dances may have the Lark do a swing as a Robin or vice versa,
// especially any dance with Larks Swing or Robins Swing.
SwingLark = "SwingLark",
SwingRobin = "SwingRobin",
}
type SemanticPosition = { type SemanticPosition = {
kind: PositionKind.Circle, kind: PositionKind.Circle,
setOffset?: number, setOffset?: number,
@ -176,7 +168,7 @@ type SemanticPosition = {
facing: Facing, facing: Facing,
hands?: Map<Hand, HandConnection>, hands?: Map<Hand, HandConnection>,
balance?: BalanceWeight, balance?: BalanceWeight,
dancerDistance?: DancerDistance, sideCompact?: boolean, // if true, have moved in for swing/allemande/etc.
} | { } | {
kind: PositionKind.ShortLines, kind: PositionKind.ShortLines,
setOffset?: number, setOffset?: number,
@ -213,10 +205,8 @@ enum SemanticAnimationKind {
// California twirl, box the gnat, etc. // California twirl, box the gnat, etc.
TwirlSwap = "TwirlSwap", TwirlSwap = "TwirlSwap",
// Rotate as a pair around a point. Allemande, right/left shoulder round // Rotate as a pair around a point. Allemande, right/left shoulder round, maybe swing?
RotateAround = "RotateAround", RotateAround = "RotateAround",
Swing = "Swing",
} }
type SemanticAnimation = { type SemanticAnimation = {
kind: SemanticAnimationKind.StandStill, kind: SemanticAnimationKind.StandStill,
@ -245,14 +235,6 @@ type SemanticAnimation = {
minAmount: number, minAmount: number,
around: CircleSide | "Center", around: CircleSide | "Center",
} | {
kind: SemanticAnimationKind.Swing,
minAmount: number,
around: CircleSide | "Center",
endFacing: Facing,
} | { } | {
kind: SemanticAnimationKind.TwirlSwap, kind: SemanticAnimationKind.TwirlSwap,
} }
@ -574,25 +556,23 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
: startPos.which.swapUpAndDown(), : startPos.which.swapUpAndDown(),
facing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left, facing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
balance: undefined, balance: undefined,
dancerDistance: undefined, sideCompact: undefined,
hands: new Map<Hand, HandConnection>([id.danceRole === DanceRole.Lark hands: new Map<Hand, HandConnection>([id.danceRole === DanceRole.Lark
? [Hand.Right, { to: HandTo.DancerRight, hand: Hand.Left }] ? [Hand.Right, { to: HandTo.DancerRight, hand: Hand.Left }]
: [Hand.Left, { to: HandTo.DancerLeft, hand: Hand.Right }]]), : [Hand.Left, { to: HandTo.DancerLeft, hand: Hand.Right }]]),
}; };
// TODO same role swing currently unsupported.
const swingRole = id.danceRole === DanceRole.Lark ? DancerDistance.SwingLark : DancerDistance.SwingRobin;
switch (move.parameters.prefix) { switch (move.parameters.prefix) {
case "none": case "none":
res.set(id, combine([ res.set(id, combine([
{ {
beats: 1, beats: 1,
endPosition: { ...startPosition, dancerDistance: DancerDistance.Compact }, endPosition: { ...startPosition, sideCompact: true },
movementPattern: { kind: SemanticAnimationKind.Linear, }, movementPattern: { kind: SemanticAnimationKind.Linear, },
}, },
{ {
beats: move.beats - 2, beats: move.beats - 2,
endPosition: { ...endPosition, dancerDistance: DancerDistance.Compact }, endPosition: { ...endPosition, sideCompact: true },
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.RotateAround, kind: SemanticAnimationKind.RotateAround,
minAmount: 360, minAmount: 360,
@ -623,7 +603,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
endPosition: { endPosition: {
...startWithBalHands, ...startWithBalHands,
balance: BalanceWeight.Forward, balance: BalanceWeight.Forward,
dancerDistance: DancerDistance.Compact, sideCompact: true,
}, },
movementPattern: { kind: SemanticAnimationKind.Linear, }, movementPattern: { kind: SemanticAnimationKind.Linear, },
}, },
@ -640,18 +620,16 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
endPosition: { endPosition: {
...prevEnd, ...prevEnd,
balance: undefined, balance: undefined,
dancerDistance: swingRole,
}, },
movementPattern: { kind: SemanticAnimationKind.Linear, }, movementPattern: { kind: SemanticAnimationKind.Linear, },
}), }),
{ {
beats: move.beats - 2 * balancePartBeats - 1, beats: move.beats - 2 * balancePartBeats - 1,
endPosition: { ...endPosition, dancerDistance: DancerDistance.Compact }, endPosition: { ...endPosition, sideCompact: true },
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.Swing, kind: SemanticAnimationKind.RotateAround,
minAmount: 360, minAmount: 360,
around: startPos.which.leftRightSide(), around: startPos.which.leftRightSide(),
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
}, },
}, },
{ {
@ -670,7 +648,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
beats: meltdownBeats, beats: meltdownBeats,
endPosition: { endPosition: {
...prevEnd, ...prevEnd,
dancerDistance: swingRole, sideCompact: true,
}, },
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.RotateAround, kind: SemanticAnimationKind.RotateAround,
@ -682,10 +660,9 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
beats: move.beats - meltdownBeats, beats: move.beats - meltdownBeats,
endPosition: endPosition, endPosition: endPosition,
movementPattern: { movementPattern: {
kind: SemanticAnimationKind.Swing, kind: SemanticAnimationKind.RotateAround,
minAmount: 360, minAmount: 360,
around: startPos.which.leftRightSide(), around: startPos.which.leftRightSide(),
endFacing: startPos.which.leftRightSide() === CircleSide.Left ? Facing.Right : Facing.Left,
}, },
}, },
], startPos)); ], startPos));
@ -1048,22 +1025,7 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
default: default:
throw "Unexpected facing: " + semantic.facing; throw "Unexpected facing: " + semantic.facing;
} }
let yAmount : number; const yAmount = semantic.sideCompact ? 0.75 : 1;
switch (semantic.dancerDistance) {
case DancerDistance.Normal:
case undefined:
yAmount = 1;
break;
case DancerDistance.Compact:
yAmount = 0.75;
break;
case DancerDistance.SwingLark:
case DancerDistance.SwingRobin:
yAmount = 0.5;
break;
default:
throw "Unknown DancerDistance: " + semantic.dancerDistance;
}
let position: Offset; let position: Offset;
switch (semantic.which) { switch (semantic.which) {
case CirclePosition.TopLeft: case CirclePosition.TopLeft:
@ -1104,35 +1066,6 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
position.x += setOffset.x; position.x += setOffset.x;
position.y += setOffset.y; position.y += setOffset.y;
const isFacingUpOrDown = semantic.facing === Facing.Up || semantic.facing === Facing.Down;
if (semantic.dancerDistance === DancerDistance.SwingLark) {
if (isFacingUpOrDown) {
rotation -= 45;
} else {
rotation += 45;
}
return {
position,
rotation,
leftArmEnd: { x: 0, y: Math.sqrt(1/2)},
rightArmEnd: { x: 0.8, y: 0.5 },
};
} else if (semantic.dancerDistance === DancerDistance.SwingRobin) {
if (isFacingUpOrDown) {
rotation += 45;
} else {
rotation -= 45;
}
return {
position,
rotation,
leftArmEnd: { x: -0.8, y: 0.5 },
rightArmEnd: { x: 0, y: Math.sqrt(1/2) },
};
}
function processHand(hand: Hand, connection: HandConnection | undefined): Offset | undefined { function processHand(hand: Hand, connection: HandConnection | undefined): Offset | undefined {
// 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;
@ -1162,8 +1095,8 @@ function SemanticToSetPosition(semantic: SemanticPosition): DancerSetPosition {
return { return {
position, position,
rotation, rotation,
leftArmEnd: processHand(Hand.Left, semantic.hands?.get(Hand.Left)), leftArmEnd: processHand(Hand.Left, semantic.hands?.get(Hand.Left))
rightArmEnd: processHand(Hand.Right, semantic.hands?.get(Hand.Right)), rightArmEnd: processHand(Hand.Right, semantic.hands?.get(Hand.Right))
}; };
default: default:
throw "Unsupported PositionKind: " + semantic.kind; throw "Unsupported PositionKind: " + semantic.kind;
@ -1241,7 +1174,7 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
// TODO Parameters: rotation, amount, direction, diagonal? // TODO Parameters: rotation, amount, direction, diagonal?
if (move.startPosition.kind !== PositionKind.Circle) { if (move.startPosition.kind !== PositionKind.Circle) {
throw "DoSiDo must start in a circle: " + JSON.stringify(move); throw "DoSoDo must start in a circle: " + JSON.stringify(move);
} }
const center = CenterOfSideOfSet(move.startPosition.which.leftRightSide(), move.startPosition.setOffset, move.startPosition.lineOffset); const center = CenterOfSideOfSet(move.startPosition.which.leftRightSide(), move.startPosition.setOffset, move.startPosition.lineOffset);
return [ return [
@ -1262,7 +1195,7 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
// TODO Parameters: rotation, amount, direction, diagonal? // TODO Parameters: rotation, amount, direction, diagonal?
if (move.startPosition.kind !== PositionKind.Circle) { if (move.startPosition.kind !== PositionKind.Circle) {
throw "Rotate must start in a circle: " + JSON.stringify(move); throw "DoSoDo must start in a circle: " + JSON.stringify(move);
} }
// TODO Could rotate around other things. // TODO Could rotate around other things.
const rotateCenter = move.movementPattern.around === "Center" const rotateCenter = move.movementPattern.around === "Center"
@ -1281,36 +1214,6 @@ export function animateLowLevelMove(move: LowLevelMove): animation.AnimationSegm
animation.RotationAnimationFacing.Center, animation.RotationAnimationFacing.Center,
), ),
]; ];
case SemanticAnimationKind.Swing:
// TODO Handle swing.
// TODO Rotation
// TODO Parameters: rotation, amount, direction, diagonal?
if (move.startPosition.kind !== PositionKind.Circle || move.endPosition.kind !== PositionKind.Circle) {
throw "Swing must start in a circle: " + JSON.stringify(move);
}
// TODO Could rotate around other things.
const rotateSwingCenter = move.movementPattern.around === "Center"
? CenterOfSet(move.startPosition.setOffset, move.startPosition.lineOffset)
: CenterOfSideOfSet(move.movementPattern.around, move.startPosition.setOffset, move.startPosition.lineOffset);
const beforeUnfold = SemanticToSetPosition({...move.endPosition, dancerDistance: move.startPosition.dancerDistance });
return [
new animation.RotationAnimationSegment(move.beats,
startSetPosition,
beforeUnfold,
move.movementPattern.minAmount,
{
center: rotateSwingCenter,
width: setWidth / 5,
height: setHeight / 5,
},
animation.RotationAnimationFacing.CenterRelative,
),
new animation.LinearAnimationSegment(move.beats,
beforeUnfold,
endSetPosition,
),
];
case SemanticAnimationKind.TwirlSwap: case SemanticAnimationKind.TwirlSwap:
// TODO // TODO
const twirlRotation : number = 180; const twirlRotation : number = 180;

View File

@ -79,15 +79,10 @@ function createJsonCell(content: any, rowSpan?: number, id?: DancerIdentity) {
// from https://stackoverflow.com/a/56150320 // from https://stackoverflow.com/a/56150320
function replacer(key, value) { function replacer(key, value) {
if (value instanceof Map) { if (value instanceof Map) {
let res = {}; return {
for (var entry of value.entries()) { dataType: 'Map',
res[entry[0].toString()] = entry[1]; value: Array.from(value.entries()), // or with spread: value: [...value]
} };
return res;
} else if (!value) {
return value;
} else if (value.enumValue) {
return value.enumValue;
} else { } else {
return value; return value;
} }