summaryrefslogtreecommitdiff
path: root/src/Terrain.js
blob: a51c0a389506e80fa6c2bd72d9c709d7fd16f92d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import { Mat3, Vec3, Point, RandomNormal, Shape, ConvexHull } from './Geometry.js';


export function RandomPoints(n) {
	const points = [];
	for (let i=0; i<n; i++) {
		points.push(RandomNormal());
	}
	return points;
}


export class Plate {
	constructor(points) {
		this.color = `hsl(${360*Math.random()}, 100%, 50%)`
		this.points = points;
		this.hull = ConvexHull(points);
		let [avgX, avgY, avgZ] = [0, 0, 0];
		for (let point of points) {
			avgX += point.x;
			avgY += point.y;
			avgZ += point.z;
		}
		avgX /= points.length;
		avgY /= points.length;
		avgZ /= points.length;
		this.center = new Vec3(avgX, avgY, avgZ).normalize();
		this.extent = 0;
		for (let point of points) {
			this.extent = Math.max(this.extent, this.center.dot(point));
		}

		this.speed = Math.random();
		this.axis = RandomNormal().cross(this.center).normalize();
	}

	filterColliding(plate) {
		const extent = Math.max(this.extent, plate.extent);
		return this.center.dot(plate.center) < extent;
	}

	checkColliding(plate) {
		if (!this.filterColliding(plate)) {
			return false;
		}
		
		console.log("check", this, plate);

		const threshold = 0.00001;
		let collisionTotal = 0;
		for (let pa of this.points) {
			for (let pb of plate.points) {
				collisionTotal += pa.dot(pb);
			}
		}
		collisionTotal /= this.points.length * plate.points.length;
		console.log(this, plate, collisionTotal);
		if (collisionTotal > threshold) {
			return true;
		}
		return false;
	}

	move() {
		const matrix = new Mat3().rotation(this.axis, this.speed * 0.01 * Math.PI);
		for (let i=0; i<this.points.length; i++) {
			this.points[i] = matrix.mulv(this.points[i]);
		}
		this.hull.translate(this.axis, this.speed * 0.01 * Math.PI);
		this.center = matrix.mulv(this.center);
	}

	render(ct, view) {
		ct.fillStyle = this.color;
		for (let point of this.points) {
			point.render(ct, view);
		}
		this.hull.render(ct, view);
	}
}


function randomChoice(array) {
	const index = Math.floor(array.length * Math.random());
	return array[index];
}


export class PlateManager {
	constructor(points, plateCount) {
		this.points = points;
		this.plates = this.buildPlates(plateCount);
	}


	buildPlates(plateCount) {
		const seedPoints = [];
		const points = [];
		for (let i=0; i<plateCount; i++) {
			seedPoints.push(randomChoice(this.points));
			points.push([]);
		}
		
		for (let point of this.points) {
			let maxDot = -1;
			let index = -1;
			for (let i=0; i<plateCount; i++) {
				const seed = seedPoints[i];
				const d = seed.dot(point);
				if (d > maxDot) {
					maxDot = d;
					index = i;
				}
			}
			if (index == -1) {
				console.error("no closest point", point);
			}
			points[index].push(point);
		}

		const plates = [];
		for (let p of points) {
			plates.push(new Plate(p));
		}
		return plates;
	}

	update() {
		for (let plate of this.plates) {
			plate.move();
		}
	}

	render(ct, view) {
		for (let plate of this.plates) {
			plate.render(ct, view);
		}
	}
}