forked from perelman/contra-renderer
138 lines
3.5 KiB
TypeScript
138 lines
3.5 KiB
TypeScript
import { DancerIdentity, Rotation } from "./danceCommon";
|
|
|
|
export interface Offset {
|
|
x: number;
|
|
y: number;
|
|
}
|
|
|
|
export function OffsetTranspose(a: Offset): Offset {
|
|
return { x: a.y, y: a.x };
|
|
}
|
|
|
|
export function OffsetRotate(a: Offset, r: Rotation): Offset {
|
|
const rad = degreesToRadians(r);
|
|
const sin = Math.sin(rad);
|
|
const cos = Math.cos(rad);
|
|
return {
|
|
x: a.x * cos - a.y * sin,
|
|
y: a.x * sin + a.y * cos,
|
|
};
|
|
}
|
|
|
|
function _OffsetPlus(a: Offset, b: Offset): Offset {
|
|
return {
|
|
x: a.x + b.x,
|
|
y: a.y + b.y,
|
|
};
|
|
}
|
|
|
|
export function OffsetPlus(...args: Offset[]): Offset {
|
|
return args.reduce(_OffsetPlus, offsetZero);
|
|
}
|
|
|
|
export function OffsetTimes(a: Offset, b: number): Offset {
|
|
return {
|
|
x: a.x * b,
|
|
y: a.y * b,
|
|
};
|
|
}
|
|
|
|
export function OffsetMinus(a: Offset, b: Offset): Offset {
|
|
return {
|
|
x: a.x - b.x,
|
|
y: a.y - b.y,
|
|
};
|
|
}
|
|
|
|
export function OffsetEquals(a: Offset, b: Offset): boolean {
|
|
return a.x === b.x && a.y === b.y;
|
|
}
|
|
|
|
export function OffsetDistance(a: Offset, b: Offset): number {
|
|
const dx = a.x - b.x;
|
|
const dy = a.y - b.y;
|
|
return Math.sqrt(dx * dx + dy * dy);
|
|
}
|
|
|
|
export interface DancerSetPosition {
|
|
// Position of the dancer relative to the center of their set.
|
|
position: Offset;
|
|
// Rotation in degrees where 0 is up the hall,
|
|
// 90 is to the right, 180 is down the hall,
|
|
// and 270 is to the left.
|
|
rotation: number;
|
|
leftArmEnd?: Offset;
|
|
rightArmEnd?: Offset;
|
|
drawDebug?: (CanvasRenderingContext2D) => void;
|
|
}
|
|
|
|
export type DancersSetPositions = Map<DancerIdentity, DancerSetPosition>;
|
|
|
|
export const offsetZero : Offset = { x: 0, y: 0 };
|
|
|
|
// Distance from one side of the set to the other. Set so the left
|
|
// of the set is -1 and the right of the set is +1.
|
|
export const setWidth : number = 2;
|
|
|
|
// Distance from top of one hands four to its bottom.
|
|
// Equivalently, the distance between a dancer and their neighbor
|
|
// in improper position. Set so +1 is the top and -1 is the bottom.
|
|
export const setHeight : number = 2;
|
|
|
|
// Distance between two hands fours in neutral position.
|
|
export const setSpacing : number = setHeight;
|
|
|
|
// y offset between any dancer and their previous/next neighbor
|
|
// of the same role.
|
|
export const setDistance : number = setHeight + setSpacing;
|
|
|
|
export const lineSpacing : number = setWidth;
|
|
|
|
// x offset between any dancer and their eqivalent in the line to
|
|
// to left/right.
|
|
export const lineDistance : number = setWidth + lineSpacing;
|
|
|
|
export const dancerWidth : number = 0.75; // Not sure about this value.
|
|
export const dancerHeight : number = 0.25; // Not sure about this value.
|
|
export const dancerHeightOffset : number = dancerHeight/4;
|
|
|
|
|
|
export const leftShoulder : Offset = { x: -dancerWidth/2, y: -dancerHeightOffset };
|
|
export const rightShoulder : Offset = { x: dancerWidth/2, y: -dancerHeightOffset };
|
|
|
|
|
|
export function degreesToRadians(degrees: number) {
|
|
return degrees * (Math.PI / 180);
|
|
}
|
|
|
|
export function radiansToDegrees(radians: number) {
|
|
return radians * (180 / Math.PI);
|
|
}
|
|
|
|
enum HandEnum {
|
|
Left = "Left",
|
|
Right = "Right",
|
|
}
|
|
export class Hand {
|
|
public static readonly Left = new Hand(HandEnum.Left);
|
|
public static readonly Right = new Hand(HandEnum.Right);
|
|
|
|
private readonly enumValue: HandEnum;
|
|
|
|
private constructor(enumValue: HandEnum) {
|
|
this.enumValue = enumValue;
|
|
}
|
|
|
|
public opposite() : Hand {
|
|
return this.enumValue === HandEnum.Left ? Hand.Right : Hand.Left;
|
|
}
|
|
|
|
public shoulderPosition() : Offset {
|
|
return this.enumValue === HandEnum.Left ? leftShoulder : rightShoulder;
|
|
}
|
|
|
|
public toString() : string {
|
|
return this.enumValue.toString();
|
|
}
|
|
}
|