@js-draw/math 1.17.0 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/cjs/Mat33.js +6 -1
- package/dist/cjs/Vec3.d.ts +2 -1
- package/dist/cjs/Vec3.js +5 -7
- package/dist/cjs/lib.d.ts +2 -1
- package/dist/cjs/lib.js +5 -1
- package/dist/cjs/shapes/BezierJSWrapper.d.ts +4 -0
- package/dist/cjs/shapes/BezierJSWrapper.js +35 -0
- package/dist/cjs/shapes/LineSegment2.d.ts +11 -0
- package/dist/cjs/shapes/LineSegment2.js +26 -1
- package/dist/cjs/shapes/Parameterized2DShape.d.ts +6 -1
- package/dist/cjs/shapes/Parameterized2DShape.js +6 -1
- package/dist/cjs/shapes/Path.d.ts +96 -12
- package/dist/cjs/shapes/Path.js +338 -15
- package/dist/cjs/shapes/QuadraticBezier.d.ts +2 -3
- package/dist/cjs/shapes/QuadraticBezier.js +2 -3
- package/dist/cjs/shapes/Rect2.d.ts +6 -1
- package/dist/cjs/shapes/Rect2.js +5 -1
- package/dist/cjs/utils/convexHull2Of.d.ts +9 -0
- package/dist/cjs/utils/convexHull2Of.js +61 -0
- package/dist/cjs/utils/convexHull2Of.test.d.ts +1 -0
- package/dist/mjs/Mat33.mjs +6 -1
- package/dist/mjs/Vec3.d.ts +2 -1
- package/dist/mjs/Vec3.mjs +5 -7
- package/dist/mjs/lib.d.ts +2 -1
- package/dist/mjs/lib.mjs +2 -1
- package/dist/mjs/shapes/BezierJSWrapper.d.ts +4 -0
- package/dist/mjs/shapes/BezierJSWrapper.mjs +35 -0
- package/dist/mjs/shapes/LineSegment2.d.ts +11 -0
- package/dist/mjs/shapes/LineSegment2.mjs +26 -1
- package/dist/mjs/shapes/Parameterized2DShape.d.ts +6 -1
- package/dist/mjs/shapes/Parameterized2DShape.mjs +6 -1
- package/dist/mjs/shapes/Path.d.ts +96 -12
- package/dist/mjs/shapes/Path.mjs +335 -14
- package/dist/mjs/shapes/QuadraticBezier.d.ts +2 -3
- package/dist/mjs/shapes/QuadraticBezier.mjs +2 -3
- package/dist/mjs/shapes/Rect2.d.ts +6 -1
- package/dist/mjs/shapes/Rect2.mjs +5 -1
- package/dist/mjs/utils/convexHull2Of.d.ts +9 -0
- package/dist/mjs/utils/convexHull2Of.mjs +59 -0
- package/dist/mjs/utils/convexHull2Of.test.d.ts +1 -0
- package/package.json +2 -2
- package/src/Mat33.ts +8 -2
- package/src/Vec3.test.ts +16 -0
- package/src/Vec3.ts +7 -8
- package/src/lib.ts +3 -0
- package/src/shapes/BezierJSWrapper.ts +41 -0
- package/src/shapes/LineSegment2.test.ts +26 -0
- package/src/shapes/LineSegment2.ts +31 -1
- package/src/shapes/Parameterized2DShape.ts +6 -1
- package/src/shapes/Path.test.ts +173 -5
- package/src/shapes/Path.ts +390 -18
- package/src/shapes/QuadraticBezier.test.ts +21 -0
- package/src/shapes/QuadraticBezier.ts +2 -3
- package/src/shapes/Rect2.ts +6 -2
- package/src/utils/convexHull2Of.test.ts +43 -0
- package/src/utils/convexHull2Of.ts +71 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
import { Point2, Vec2 } from '../Vec2';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Implements Gift Wrapping, in $O(nh)$. This algorithm is not the most efficient in the worst case.
|
5
|
+
*
|
6
|
+
* See https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
|
7
|
+
* and https://www.cs.jhu.edu/~misha/Spring16/06.pdf
|
8
|
+
*/
|
9
|
+
const convexHull2Of = (points: Point2[]) => {
|
10
|
+
if (points.length === 0) {
|
11
|
+
return [];
|
12
|
+
}
|
13
|
+
|
14
|
+
// 1. Start with a vertex on the hull
|
15
|
+
const lowestPoint = points.reduce(
|
16
|
+
(lowest, current) => current.y < lowest.y ? current : lowest,
|
17
|
+
points[0]
|
18
|
+
);
|
19
|
+
const vertices = [ lowestPoint ];
|
20
|
+
let toProcess = [...points.filter(p => !p.eq(lowestPoint))];
|
21
|
+
let lastBaseDirection = Vec2.of(-1, 0);
|
22
|
+
|
23
|
+
// 2. Find the point with greatest angle from the vertex:
|
24
|
+
//
|
25
|
+
// . . .
|
26
|
+
// . . / <- Notice that **all** other points are to the
|
27
|
+
// / **left** of the vector from the current
|
28
|
+
// ./ vertex to the new point.
|
29
|
+
while (toProcess.length > 0) {
|
30
|
+
const lastVertex = vertices[vertices.length - 1];
|
31
|
+
|
32
|
+
let smallestDotProductSoFar: number = lastBaseDirection.dot(lowestPoint.minus(lastVertex).normalizedOrZero());
|
33
|
+
let furthestPointSoFar = lowestPoint;
|
34
|
+
for (const point of toProcess) {
|
35
|
+
// Maximizing the angle is the same as minimizing the dot product:
|
36
|
+
// point.minus(lastVertex)
|
37
|
+
// ^
|
38
|
+
// /
|
39
|
+
// /
|
40
|
+
// ϑ /
|
41
|
+
// <-----. lastBaseDirection
|
42
|
+
const currentDotProduct = lastBaseDirection.dot(point.minus(lastVertex).normalizedOrZero());
|
43
|
+
|
44
|
+
if (currentDotProduct <= smallestDotProductSoFar) {
|
45
|
+
furthestPointSoFar = point;
|
46
|
+
smallestDotProductSoFar = currentDotProduct;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
toProcess = toProcess.filter(p => !p.eq(furthestPointSoFar));
|
50
|
+
|
51
|
+
const newBaseDirection = furthestPointSoFar.minus(lastVertex).normalized();
|
52
|
+
|
53
|
+
// If the last vertex is on the same edge as the current, there's no need to include
|
54
|
+
// the previous one.
|
55
|
+
if (Math.abs(newBaseDirection.dot(lastBaseDirection)) === 1 && vertices.length > 1) {
|
56
|
+
vertices.pop();
|
57
|
+
}
|
58
|
+
|
59
|
+
// Stoping condition: We've gone in a full circle.
|
60
|
+
if (furthestPointSoFar.eq(lowestPoint)) {
|
61
|
+
break;
|
62
|
+
} else {
|
63
|
+
vertices.push(furthestPointSoFar);
|
64
|
+
lastBaseDirection = lastVertex.minus(furthestPointSoFar).normalized();
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
return vertices;
|
69
|
+
};
|
70
|
+
|
71
|
+
export default convexHull2Of;
|