File

src/app/models/builder-distribution-collection.ts

Constructor

constructor(x: number, y: number)

Properties

x
x: number
y
y: number
export class Point {
	constructor(public x: number, public y: number) {}
}

export class Position {
	public left: string;
	public top: string;
	public point: Point;
	constructor(point: Point) {
		this.point = point;
		this.left = point.x + "%";
		this.top = point.y + "%";
	}
}

// Builder of array of positions in percentages
// With a n-size collection it can generate n-size array of {top, left} positions
// You can then use the array to distribute the elements of the collection with the 'position: absolute' css attribute
export class BuilderDistributionCollection {
	public static generatePositionsOverGrid(collectionLength: number) {
		let point: Point;
		let pos: Position;
		const positions: Position[] = [];

		// We want a never full grid
		const gridWidth = Math.floor(Math.sqrt(collectionLength) + 1);
		const m = gridWidth ** 2;
		const paddingBetweenElements = 100 / gridWidth;

		// Get range of the possible positions in the flatten grid
		const positionsArray = Array.from(Array(m).keys());
		// For each place drawn, generate the pos
		const i = 0;
		let place, placeIndex: number;
		let topPosPercentage, leftPosPercentage: number;
		for (let i = 0; i < collectionLength; i++) {
			placeIndex = Math.floor(Math.random() * (m - i));
			place = positionsArray[placeIndex];
			positionsArray.splice(placeIndex, 1);
			// Ex : With a 4x4 grid & place_drawn=11 we have pos = 2,3 (2*4+3)
			// And transform the place into top/left percentage
			topPosPercentage = Math.floor(place / gridWidth) * paddingBetweenElements;
			leftPosPercentage = (place % gridWidth) * paddingBetweenElements;
			point = new Point(leftPosPercentage, topPosPercentage);
			pos = new Position(point);
			positions.push(pos);
		}
		return positions;
	}

	// Generate an array of positions (ie percentages {top:50%, left:25%})
	// Positions are uniform over a circle
	public static generatePositionsOverCircle(collectionLength: number, randomize = true) {
		let point: Point;
		let pos: Position;
		const positions: Position[] = [];

		const radius = 50;
		const padding = (2 * Math.PI) / collectionLength;

		let angle = Math.random() * 2 * Math.PI; // Radians
		let x, y: number; // Euclidean coordinates
		for (let i = 0; i < collectionLength; i++) {
			// With init=30 and padding=25 we have angles=30,55,80... (here in 'deg' but below it is 'rad')
			angle = (angle + padding) % (2 * Math.PI);
			// Transforms with polar coordinates
			point = new Point(Math.floor(radius * Math.sin(angle)), Math.floor(radius * Math.cos(angle)));
			point.x += radius;
			point.y += radius;
			pos = new Position(point);
			positions.push(pos);
		}
		if (randomize) {
			this.shuffle(positions);
		}
		return positions;
	}

	// Shuffle/randomize a collection (inplace)
	public static shuffle(collection: Array<any>) {
		let m: number = collection.length,
			t: any,
			i: number;
		while (m) {
			i = Math.floor(Math.random() * m--);
			t = collection[m];
			collection[m] = collection[i];
			collection[i] = t;
		}
	}

	// Generate an array of positions, distributed over a universe
	// Src : yahiko from https://www.developpez.net/forums/d1470523/applications/developpement-2d-3d-jeux/generation-aleatoire-d-univers/
	public static generatePositionsOverUniverse(collectionLength: number, epsilon: number = 0.02) {
		let universe: Position[] = [];
		let iteratorCount = 0;
		let i = 0;
		let point: Point;
		while (i < collectionLength) {
			point = new Point(0.05 + 0.95 * Math.random() * 100, 0.05 + 0.95 * Math.random() * 100);
			if (isValidLocation(point, universe)) {
				universe.push(new Position(point));
				i++;
			}
			iteratorCount++;
			if(iteratorCount % 100 === 0){
				epsilon *= 0.95;
			}
		}
		function isValidLocation(point: Point, universe: Position[]): boolean {
			for (let i = 0; i < universe.length; i++) {
				let pos = universe[i];
				if (distance(point.x, point.y, pos.point.x, pos.point.y) < epsilon) {
					return false;
				} else if (distance(point.x, point.y, pos.point.x, pos.point.y) < 0) {
					return true;
				}
			}

			return true;
		}
		function distance(x1: number, y1: number, x2: number, y2: number): number {
			return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
		}
		return universe;
	}
}

results matching ""

    No results matching ""