File size: 1,427 Bytes
2b7aae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { Earcut } from './Earcut.js';

class ShapeUtils {
	// calculate area of the contour polygon

	static area(contour) {
		const n = contour.length;
		let a = 0.0;

		for (let p = n - 1, q = 0; q < n; p = q++) {
			a += contour[p].x * contour[q].y - contour[q].x * contour[p].y;
		}

		return a * 0.5;
	}

	static isClockWise(pts) {
		return ShapeUtils.area(pts) < 0;
	}

	static triangulateShape(contour, holes) {
		const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
		const holeIndices = []; // array of hole indices
		const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]

		removeDupEndPts(contour);
		addContour(vertices, contour);

		//

		let holeIndex = contour.length;

		holes.forEach(removeDupEndPts);

		for (let i = 0; i < holes.length; i++) {
			holeIndices.push(holeIndex);
			holeIndex += holes[i].length;
			addContour(vertices, holes[i]);
		}

		//

		const triangles = Earcut.triangulate(vertices, holeIndices);

		//

		for (let i = 0; i < triangles.length; i += 3) {
			faces.push(triangles.slice(i, i + 3));
		}

		return faces;
	}
}

function removeDupEndPts(points) {
	const l = points.length;

	if (l > 2 && points[l - 1].equals(points[0])) {
		points.pop();
	}
}

function addContour(vertices, contour) {
	for (let i = 0; i < contour.length; i++) {
		vertices.push(contour[i].x);
		vertices.push(contour[i].y);
	}
}

export { ShapeUtils };