forked from perelman/contra-renderer
365 lines
10 KiB
TypeScript
365 lines
10 KiB
TypeScript
import { DancerIdentity, Rotation } from "./danceCommon.js";
|
|
import { Hand } from "./rendererConstants.js";
|
|
|
|
export enum PositionKind {
|
|
Circle = "Circle",
|
|
ShortLines = "ShortLines",
|
|
};
|
|
// Which of the four corners of a circle.
|
|
// Note that "Left" is the left side of the set, not left from the dancer's PoV,
|
|
// so, in improper, the Robin starts in the BottomLeft.
|
|
enum CirclePositionEnum {
|
|
TopLeft = "TopLeft",
|
|
BottomLeft = "BottomLeft",
|
|
BottomRight = "BottomRight",
|
|
TopRight = "TopRight",
|
|
}
|
|
export enum CircleSide {
|
|
Top = "Top",
|
|
Bottom = "Bottom",
|
|
Left = "Left",
|
|
Right = "Right",
|
|
}
|
|
export type CircleSideOrCenter = CircleSide | "Center";
|
|
export class CirclePosition {
|
|
public static readonly TopLeft = new CirclePosition(CirclePositionEnum.TopLeft);
|
|
public static readonly BottomLeft = new CirclePosition(CirclePositionEnum.BottomLeft);
|
|
public static readonly BottomRight = new CirclePosition(CirclePositionEnum.BottomRight);
|
|
public static readonly TopRight = new CirclePosition(CirclePositionEnum.TopRight);
|
|
|
|
private readonly enumValue: CirclePositionEnum;
|
|
|
|
private constructor(enumValue: CirclePositionEnum) {
|
|
this.enumValue = enumValue;
|
|
}
|
|
|
|
private static enumValueToNumber(enumValue: CirclePositionEnum) : number {
|
|
switch (enumValue) {
|
|
case CirclePositionEnum.TopLeft:
|
|
return 0;
|
|
case CirclePositionEnum.BottomLeft:
|
|
return 1;
|
|
case CirclePositionEnum.BottomRight:
|
|
return 2;
|
|
case CirclePositionEnum.TopRight:
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
private static numberToEnumValue(num: number) : CirclePositionEnum {
|
|
if (num < 0 || num > 3) {
|
|
num %= 4;
|
|
if (num < 0) num += 4;
|
|
}
|
|
|
|
return [
|
|
CirclePositionEnum.TopLeft,
|
|
CirclePositionEnum.BottomLeft,
|
|
CirclePositionEnum.BottomRight,
|
|
CirclePositionEnum.TopRight,
|
|
][num];
|
|
}
|
|
|
|
private static get(enumValue: CirclePositionEnum) : CirclePosition {
|
|
return [
|
|
CirclePosition.TopLeft,
|
|
CirclePosition.BottomLeft,
|
|
CirclePosition.BottomRight,
|
|
CirclePosition.TopRight,
|
|
][this.enumValueToNumber(enumValue)];
|
|
}
|
|
|
|
public circleRight(places?: number) : CirclePosition {
|
|
return CirclePosition.get(CirclePosition.numberToEnumValue(CirclePosition.enumValueToNumber(this.enumValue) - (places ?? 1)));
|
|
}
|
|
|
|
public circleLeft(places?: number) : CirclePosition {
|
|
return CirclePosition.get(CirclePosition.numberToEnumValue(CirclePosition.enumValueToNumber(this.enumValue) + (places ?? 1)));
|
|
}
|
|
|
|
public swapAcross() : CirclePosition {
|
|
return [
|
|
CirclePosition.TopRight,
|
|
CirclePosition.BottomRight,
|
|
CirclePosition.BottomLeft,
|
|
CirclePosition.TopLeft,
|
|
][CirclePosition.enumValueToNumber(this.enumValue)];
|
|
}
|
|
|
|
public swapUpAndDown() : CirclePosition {
|
|
return [
|
|
CirclePosition.BottomLeft,
|
|
CirclePosition.TopLeft,
|
|
CirclePosition.TopRight,
|
|
CirclePosition.BottomRight,
|
|
][CirclePosition.enumValueToNumber(this.enumValue)];
|
|
}
|
|
|
|
public swapDiagonal() : CirclePosition {
|
|
return this.swapAcross().swapUpAndDown();
|
|
}
|
|
|
|
public facingCenterRotation() : Rotation {
|
|
return (45 + 90 * CirclePosition.enumValueToNumber(this.enumValue)) % 360;
|
|
}
|
|
|
|
public topBottomSide() : CircleSide.Top | CircleSide.Bottom {
|
|
return this.enumValue === CirclePositionEnum.TopLeft || this.enumValue === CirclePositionEnum.TopRight
|
|
? CircleSide.Top
|
|
: CircleSide.Bottom;
|
|
}
|
|
|
|
public leftRightSide() : CircleSide.Left | CircleSide.Right {
|
|
return this.enumValue === CirclePositionEnum.TopLeft || this.enumValue === CirclePositionEnum.BottomLeft
|
|
? CircleSide.Left
|
|
: CircleSide.Right;
|
|
}
|
|
|
|
public isTop() : boolean {
|
|
return this.topBottomSide() === CircleSide.Top;
|
|
}
|
|
|
|
public isLeft() : boolean {
|
|
return this.leftRightSide() === CircleSide.Left;
|
|
}
|
|
|
|
public isOnLeftLookingAcross() : boolean {
|
|
return this.enumValue === CirclePositionEnum.TopRight || this.enumValue === CirclePositionEnum.BottomLeft;
|
|
}
|
|
|
|
public isOnLeftLookingUpAndDown() : boolean {
|
|
return this.enumValue === CirclePositionEnum.TopLeft || this.enumValue === CirclePositionEnum.BottomRight;
|
|
}
|
|
|
|
public facingAcross() : Facing.Left | Facing.Right {
|
|
return this.isLeft() ? Facing.Right : Facing.Left;
|
|
}
|
|
|
|
public facingOut() : Facing.Left | Facing.Right {
|
|
return this.isLeft() ? Facing.Left : Facing.Right;
|
|
}
|
|
|
|
public facingUpOrDown() : Facing.Up | Facing.Down {
|
|
return this.isTop() ? Facing.Down : Facing.Up;
|
|
}
|
|
|
|
public toString() : string {
|
|
return this.enumValue.toString();
|
|
}
|
|
}
|
|
|
|
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 swapOnSide() : ShortLinesPosition {
|
|
return [
|
|
ShortLinesPosition.MiddleLeft,
|
|
ShortLinesPosition.FarLeft,
|
|
ShortLinesPosition.FarRight,
|
|
ShortLinesPosition.MiddleRight,
|
|
][ShortLinesPosition.enumValueToNumber(this.enumValue)];
|
|
}
|
|
|
|
public swapSides() : ShortLinesPosition {
|
|
return [
|
|
ShortLinesPosition.FarRight,
|
|
ShortLinesPosition.MiddleRight,
|
|
ShortLinesPosition.MiddleLeft,
|
|
ShortLinesPosition.FarLeft,
|
|
][ShortLinesPosition.enumValueToNumber(this.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 facingSide() : Facing.Left | Facing.Right {
|
|
return this.isLeft() === this.isMiddle() ? Facing.Left : Facing.Right;
|
|
}
|
|
|
|
public toString() : string {
|
|
return this.enumValue.toString();
|
|
}
|
|
}
|
|
|
|
export enum Facing {
|
|
CenterOfCircle = "CenterOfCircle",
|
|
// for star left/right
|
|
LeftInCircle = "LeftInCircle",
|
|
RightInCircle = "RightInCircle",
|
|
Up = "Up",
|
|
Down = "Down",
|
|
Left = "Left",
|
|
Right = "Right",
|
|
}
|
|
export function oppositeFacing(facing: Facing.Up | Facing.Down | Facing.Left | Facing.Right | Facing.LeftInCircle | Facing.RightInCircle) {
|
|
switch (facing) {
|
|
case Facing.LeftInCircle:
|
|
return Facing.RightInCircle;
|
|
case Facing.RightInCircle:
|
|
return Facing.LeftInCircle;
|
|
case Facing.Up:
|
|
return Facing.Down;
|
|
case Facing.Down:
|
|
return Facing.Up;
|
|
case Facing.Left:
|
|
return Facing.Right;
|
|
case Facing.Right:
|
|
return Facing.Left;
|
|
}
|
|
}
|
|
|
|
export enum StarGrip {
|
|
HandsAcross = "HandsAcross",
|
|
WristGrip = "WristGrip",
|
|
}
|
|
export enum HandTo {
|
|
LeftInCircle = "LeftInCircle",
|
|
RightInCircle = "RightInCircle",
|
|
AcrossCircle = "AcrossCircle",
|
|
DiagonalAcrossCircle = "DiagonalAcrossCircle",
|
|
LeftDiagonalAcrossCircle = "LeftDiagonalAcrossCircle",
|
|
RightDiagonalAcrossCircle = "RightDiagonalAcrossCircle",
|
|
DancerForward = "DancerForward",
|
|
DancerLeft = "DancerLeft",
|
|
DancerRight = "DancerRight",
|
|
}
|
|
export interface HandConnection {
|
|
to: HandTo,
|
|
hand: Hand,
|
|
}
|
|
export enum BalanceWeight {
|
|
Forward = "Forward",
|
|
Backward = "Backward",
|
|
Left = "Left",
|
|
Right = "Right",
|
|
}
|
|
export 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",
|
|
}
|
|
export enum LongLines {
|
|
Forward = "Forward",
|
|
}
|
|
export type SemanticPosition = {
|
|
kind: PositionKind.Circle,
|
|
setOffset?: number,
|
|
lineOffset?: number,
|
|
which: CirclePosition,
|
|
facing: Facing,
|
|
hands?: Map<Hand, HandConnection>,
|
|
balance?: BalanceWeight,
|
|
dancerDistance?: DancerDistance,
|
|
longLines?: LongLines,
|
|
} | {
|
|
kind: PositionKind.ShortLines,
|
|
setOffset?: number,
|
|
lineOffset?: number,
|
|
which: ShortLinesPosition,
|
|
facing: Facing,
|
|
hands?: Map<Hand, HandConnection>,
|
|
balance?: BalanceWeight,
|
|
dancerDistance?: DancerDistance,
|
|
};
|
|
|
|
export const handsInCircle = new Map<Hand, HandConnection>([
|
|
[Hand.Left, {
|
|
to: HandTo.LeftInCircle,
|
|
hand: Hand.Right,
|
|
}],
|
|
[Hand.Right, {
|
|
to: HandTo.RightInCircle,
|
|
hand: Hand.Left,
|
|
}],
|
|
]);
|
|
export const handsFourImproper: Map<DancerIdentity, SemanticPosition> = new Map<DancerIdentity, SemanticPosition>([
|
|
[DancerIdentity.OnesLark, {
|
|
kind: PositionKind.Circle,
|
|
which: CirclePosition.TopLeft,
|
|
facing: Facing.CenterOfCircle,
|
|
hands: handsInCircle,
|
|
}],
|
|
[DancerIdentity.OnesRobin, {
|
|
kind: PositionKind.Circle,
|
|
which: CirclePosition.TopRight,
|
|
facing: Facing.CenterOfCircle,
|
|
hands: handsInCircle,
|
|
}],
|
|
[DancerIdentity.TwosLark, {
|
|
kind: PositionKind.Circle,
|
|
which: CirclePosition.BottomRight,
|
|
facing: Facing.CenterOfCircle,
|
|
hands: handsInCircle,
|
|
}],
|
|
[DancerIdentity.TwosRobin, {
|
|
kind: PositionKind.Circle,
|
|
which: CirclePosition.BottomLeft,
|
|
facing: Facing.CenterOfCircle,
|
|
hands: handsInCircle,
|
|
}],
|
|
]); |