UNPKG

@dominicstop/utils

Version:

Yet another event emitter written in typescript.

193 lines (192 loc) 7.75 kB
import { ArrayHelpers } from "../helpers"; import { BoxedHexagon } from "./BoxedHexagon"; import { Point } from "./Point"; const DEBUG_SHOULD_LOG = false; export class HexagonGrid { constructor(args) { this.hexagonType = args.hexagonType; this.maxRingCount = args.maxRingCount; this.centerHexagon = BoxedHexagon.initFromPresetHexagon({ mode: 'relativeToOrigin', origin: args.centerHexagon.origin, circumRadius: args.centerHexagon.circumRadius, hexagonType: args.hexagonType, }); } ; convertAxialCoordinatesToCartesian(args) { const { hexagonCoords, hexagonType } = args; const { ringRowIndex: q, ringColumnIndex: r } = hexagonCoords; const R = this.centerHexagon.circumRadius; let offsetX; let offsetY; switch (hexagonType) { case 'pointyTopped': offsetX = R * 3 / 2 * q; offsetY = R * Math.sqrt(3) * (q + r / 2); break; case 'flatTopped': offsetX = R * Math.sqrt(3) * (q + r / 2); offsetY = R * 3 / 2 * r; break; default: throw new Error('Invalid hexagonType'); } ; return new Point({ x: this.centerHexagon.origin.x + offsetX, y: this.centerHexagon.origin.y + offsetY }); } ; // MARK: - Static Methods // ---------------------- static computeHexagonsForFlowerArrangment(args) { const startEdgeOffset = args.startEdgeOffset ?? 0; const centerHexagon = new BoxedHexagon({ center: args.centerPoint, circumRadius: args.circumRadius, mode: 'relativeToCenter', }); const centerHexagonEdgesRaw = centerHexagon.edgeLines; const centerHexagonEdges = ArrayHelpers.copyArrayWithCyclicOffset( /* sourceArray: */ centerHexagonEdgesRaw, /* offset: */ startEdgeOffset); const outerHexagonRing = centerHexagonEdges.map((edgeLine) => (centerHexagon.computeTiledHexagonAlongsideEdge({ edgeLine, extraPositionOffset: args.extraPositionOffset, }))); const hexagons = [centerHexagon, ...outerHexagonRing]; const allPoints = hexagons.reduce((acc, curr) => { acc.push(...curr.cornerPointsAsArray); return acc; }, [...centerHexagon.cornerPointsAsArray]); const boundingBox = Point.getBoundingBoxForPoints(allPoints); DEBUG_SHOULD_LOG && console.log({ 'HexagonGrid.computeHexagonsForFlowerArrangment.centerHexagonEdgesRaw.length': centerHexagonEdgesRaw.length, 'HexagonGrid.computeHexagonsForFlowerArrangment.centerHexagonEdges.length': centerHexagonEdges.length, 'HexagonGrid.computeHexagonsForFlowerArrangment.allPoints.length': allPoints.length, 'HexagonGrid.computeHexagonsForFlowerArrangment.outerHexagonRing.length': outerHexagonRing.length, 'HexagonGrid.computeHexagonsForFlowerArrangment.hexagons.length': hexagons.length, }); return { centerHexagon, outerHexagonRing, boundingBox, }; } ; static computeHexagonsForTriangleArrangement(args) { const startEdgeOffset = args.startEdgeOffset ?? 0; const firstHexagon = new BoxedHexagon({ center: args.centerPoint, circumRadius: args.circumRadius, mode: 'relativeToCenter', }); const edgeLinesRaw = firstHexagon.edgeLines; const edgeLines = ArrayHelpers.copyArrayWithCyclicOffset( /* sourceArray: */ edgeLinesRaw, /* offset: */ startEdgeOffset); const secondHexagon = firstHexagon.computeTiledHexagonAlongsideEdge({ edgeLine: edgeLines[0], extraPositionOffset: args.extraPositionOffset, }); const thirdHexagon = firstHexagon.computeTiledHexagonAlongsideEdge({ edgeLine: edgeLines[1], extraPositionOffset: args.extraPositionOffset, }); const hexagons = [ firstHexagon, secondHexagon, thirdHexagon, ]; const allPoints = [ ...firstHexagon.cornerPointsAsArray, ...secondHexagon.cornerPointsAsArray, ...thirdHexagon.cornerPointsAsArray, ]; const boundingBox = Point.getBoundingBoxForPoints(allPoints); BoxedHexagon.recenterHexagonsRelativeToPoint({ hexagons, centerPoint: args.centerPoint, }); return { hexagons, boundingBox }; } ; static computeHexagonsForTriangleAndFlowerArrangement(args) { if (args.hexagonCount == 1) { const hexagon = new BoxedHexagon({ mode: 'relativeToCenter', center: args.centerPoint, circumRadius: args.circumRadius, }); return ({ hexagons: [hexagon], boundingBox: hexagon.boundingBox, }); } ; if (args.hexagonCount <= 3) { const startEdgeOffset = args.hexagonCount == 2 ? 1 : 0; const shouldReCenter = args.hexagonCount == 2; const hexagonsToRemoveCount = 3 - args.hexagonCount; const hexagonGroup = this.computeHexagonsForTriangleArrangement({ ...args, startEdgeOffset, }); if (hexagonsToRemoveCount > 0) { hexagonGroup.hexagons.splice(-hexagonsToRemoveCount); } ; if (shouldReCenter) { BoxedHexagon.recenterHexagonsRelativeToPoint({ hexagons: hexagonGroup.hexagons, centerPoint: args.centerPoint, }); } ; return ({ hexagons: hexagonGroup.hexagons, boundingBox: hexagonGroup.boundingBox, }); } else if (args.hexagonCount <= 7) { const startEdgeOffset = args.hexagonCount == 5 || args.hexagonCount == 6 ? 1 : 0; const shouldReCenter = args.hexagonCount == 4; const hexagonsToRemoveCount = 7 - args.hexagonCount; const hexagonGroup = this.computeHexagonsForFlowerArrangment({ ...args, startEdgeOffset, }); const hexagons = [ hexagonGroup.centerHexagon, ...hexagonGroup.outerHexagonRing ]; if (hexagonsToRemoveCount > 0) { hexagons.splice(-hexagonsToRemoveCount); } ; if (shouldReCenter) { BoxedHexagon.recenterHexagonsRelativeToPoint({ hexagons, centerPoint: args.centerPoint, }); } ; DEBUG_SHOULD_LOG && console.log({ 'HexagonGrid.computeHexagonsForTriangleAndFlowerArrangement.hexagonsToRemoveCount': hexagonsToRemoveCount, 'HexagonGrid.computeHexagonsForTriangleAndFlowerArrangement.shouldReCenter': shouldReCenter, 'HexagonGrid.computeHexagonsForTriangleAndFlowerArrangement.hexagonGroup.outerHexagonRing.length': hexagonGroup.outerHexagonRing.length, 'HexagonGrid.computeHexagonsForTriangleAndFlowerArrangement.hexagons.length': hexagons.length, }); return { hexagons, boundingBox: hexagonGroup.boundingBox }; } ; throw new Error("Hexagon count > 6 not supported"); } ; } ;