import { IContainerModel } from '../Interfaces/IContainerModel'; /** * Returns a Generator iterating of over the children depth-first */ export function * MakeIterator(root: IContainerModel): Generator { const queue: IContainerModel[] = [root]; const visited = new Set(queue); while (queue.length > 0) { const container = queue.pop() as IContainerModel; yield container; for (let i = container.children.length - 1; i >= 0; i--) { const child = container.children[i]; if (visited.has(child)) { continue; } visited.add(child); queue.push(child); } } } export interface ContainerAndDepth { container: IContainerModel depth: number } /** * Returns a Generator iterating of over the children depth-first */ export function * MakeBFSIterator(root: IContainerModel): Generator { const queue: IContainerModel[] = [root]; let depth = 0; while (queue.length > 0) { let levelSize = queue.length; while (levelSize-- !== 0) { const container = queue.shift() as IContainerModel; yield { container, depth }; for (let i = container.children.length - 1; i >= 0; i--) { const child = container.children[i]; queue.push(child); } } depth++; } } /** * Returns the depth of the container * @returns The depth of the container */ export function GetDepth(parent: IContainerModel): number { let depth = 0; let current: IContainerModel | null = parent; while (current != null) { depth++; current = current.parent; } return depth; } /** * Returns the absolute position by iterating to the parent * @returns The absolute position of the container */ export function GetAbsolutePosition(container: IContainerModel): [number, number] { const x = container.properties.x; const y = container.properties.y; return CancelParentTransform(container.parent, x, y); } /** * Cancel the hierarchic transformations to the given x, y * @param parent Parent of the container to remove its transform * @param x value to be restored * @param y value to be restored * @returns x and y such that the transformations of the parent are cancelled */ export function CancelParentTransform(parent: IContainerModel | null, x: number, y: number): [number, number] { let current = parent; while (current != null) { x += current.properties.x; y += current.properties.y; current = current.parent; } return [x, y]; } /** * Cancel the hierarchic transformations to the given x, y * @param parent Parent of the container to remove its transform * @param x value to be restored * @param y value to be restored * @returns x and y such that the transformations of the parent are cancelled */ export function ApplyParentTransform(parent: IContainerModel | null, x: number, y: number): [number, number] { let current = parent; while (current != null) { x -= current.properties.x; y -= current.properties.y; current = current.parent; } return [x, y]; } export function FindContainerById(root: IContainerModel, id: string): IContainerModel | undefined { const it = MakeIterator(root); for (const container of it) { if (container.properties.id === id) { return container; } } return undefined; } export interface IPair { cur: T next: T } export function * Pairwise(arr: T[]): Generator, void, unknown> { for (let i = 0; i < arr.length - 1; i++) { yield { cur: arr[i], next: arr[i + 1] }; } } export function * ReversePairwise(arr: T[]): Generator, void, unknown> { for (let i = arr.length - 1; i > 0; i--) { yield { cur: arr[i], next: arr[i - 1] }; } }