@matboks/utilities 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/constants.d.ts +1 -0
  2. package/dist/constants.js +1 -0
  3. package/dist/geometry/aabb.d.ts +40 -0
  4. package/dist/geometry/aabb.js +143 -0
  5. package/dist/geometry/cut-polygon.d.ts +7 -0
  6. package/dist/geometry/cut-polygon.js +116 -0
  7. package/dist/geometry/hollowgon.d.ts +24 -0
  8. package/dist/geometry/hollowgon.js +156 -0
  9. package/dist/geometry/index.d.ts +13 -0
  10. package/dist/geometry/index.js +14 -0
  11. package/dist/geometry/line.d.ts +10 -0
  12. package/dist/geometry/line.js +26 -0
  13. package/dist/geometry/polygon-operations.d.ts +31 -0
  14. package/dist/geometry/polygon-operations.js +159 -0
  15. package/dist/geometry/polygon.d.ts +55 -0
  16. package/dist/geometry/polygon.js +353 -0
  17. package/dist/geometry/polyline.d.ts +23 -0
  18. package/dist/geometry/polyline.js +100 -0
  19. package/dist/geometry/ray.d.ts +6 -0
  20. package/dist/geometry/ray.js +6 -0
  21. package/dist/geometry/ray3.d.ts +7 -0
  22. package/dist/geometry/ray3.js +10 -0
  23. package/dist/geometry/segment.d.ts +16 -0
  24. package/dist/geometry/segment.js +50 -0
  25. package/dist/geometry/shared.d.ts +5 -0
  26. package/dist/geometry/shared.js +60 -0
  27. package/dist/geometry/transformations.d.ts +7 -0
  28. package/dist/geometry/transformations.js +28 -0
  29. package/dist/geometry/vec2.d.ts +71 -0
  30. package/dist/geometry/vec2.js +225 -0
  31. package/dist/geometry/vec3.d.ts +102 -0
  32. package/dist/geometry/vec3.js +256 -0
  33. package/dist/geometry/vec4.d.ts +71 -0
  34. package/dist/geometry/vec4.js +238 -0
  35. package/dist/index.d.ts +11 -0
  36. package/dist/index.js +11 -0
  37. package/dist/math/clamp.d.ts +1 -0
  38. package/dist/math/clamp.js +5 -0
  39. package/dist/math/fract.d.ts +1 -0
  40. package/dist/math/fract.js +3 -0
  41. package/dist/math/index.d.ts +8 -0
  42. package/dist/math/index.js +8 -0
  43. package/dist/math/mix.d.ts +1 -0
  44. package/dist/math/mix.js +3 -0
  45. package/dist/math/mod.d.ts +1 -0
  46. package/dist/math/mod.js +5 -0
  47. package/dist/math/signed.d.ts +1 -0
  48. package/dist/math/signed.js +3 -0
  49. package/dist/math/smoothstep.d.ts +3 -0
  50. package/dist/math/smoothstep.js +24 -0
  51. package/dist/math/split-into-int-and-fract.d.ts +1 -0
  52. package/dist/math/split-into-int-and-fract.js +5 -0
  53. package/dist/math/units.d.ts +2 -0
  54. package/dist/math/units.js +6 -0
  55. package/dist/noise/idw.d.ts +11 -0
  56. package/dist/noise/idw.js +10 -0
  57. package/dist/noise/index.d.ts +6 -0
  58. package/dist/noise/index.js +6 -0
  59. package/dist/noise/perlin.d.ts +5 -0
  60. package/dist/noise/perlin.js +29 -0
  61. package/dist/noise/random.d.ts +13 -0
  62. package/dist/noise/random.js +39 -0
  63. package/dist/noise/value.d.ts +4 -0
  64. package/dist/noise/value.js +20 -0
  65. package/dist/noise/voronoise.d.ts +10 -0
  66. package/dist/noise/voronoise.js +26 -0
  67. package/dist/noise/worley.d.ts +4 -0
  68. package/dist/noise/worley.js +39 -0
  69. package/dist/shader-modules/index.d.ts +2 -0
  70. package/dist/shader-modules/index.js +2 -0
  71. package/dist/shader-modules/library.d.ts +2 -0
  72. package/dist/shader-modules/library.js +36 -0
  73. package/dist/shader-modules/modules/camera.d.ts +1 -0
  74. package/dist/shader-modules/modules/camera.js +43 -0
  75. package/dist/shader-modules/modules/color/blend.d.ts +1 -0
  76. package/dist/shader-modules/modules/color/blend.js +108 -0
  77. package/dist/shader-modules/modules/color/index.d.ts +1 -0
  78. package/dist/shader-modules/modules/color/index.js +135 -0
  79. package/dist/shader-modules/modules/constants.d.ts +1 -0
  80. package/dist/shader-modules/modules/constants.js +14 -0
  81. package/dist/shader-modules/modules/geometry.d.ts +1 -0
  82. package/dist/shader-modules/modules/geometry.js +110 -0
  83. package/dist/shader-modules/modules/math.d.ts +1 -0
  84. package/dist/shader-modules/modules/math.js +19 -0
  85. package/dist/shader-modules/modules/noise.d.ts +1 -0
  86. package/dist/shader-modules/modules/noise.js +410 -0
  87. package/dist/shader-modules/modules/random.d.ts +1 -0
  88. package/dist/shader-modules/modules/random.js +147 -0
  89. package/dist/shader-modules/modules/ray-marching.d.ts +1 -0
  90. package/dist/shader-modules/modules/ray-marching.js +54 -0
  91. package/dist/shader-modules/modules/sdf/index.d.ts +1 -0
  92. package/dist/shader-modules/modules/sdf/index.js +183 -0
  93. package/dist/shader-modules/modules/sdf/operations.d.ts +1 -0
  94. package/dist/shader-modules/modules/sdf/operations.js +77 -0
  95. package/dist/shader-modules/modules/utils.d.ts +1 -0
  96. package/dist/shader-modules/modules/utils.js +115 -0
  97. package/dist/shader-modules/registry.d.ts +2 -0
  98. package/dist/shader-modules/registry.js +7 -0
  99. package/dist/shader-modules/shaders.d.ts +1 -0
  100. package/dist/shader-modules/shaders.js +109 -0
  101. package/dist/shader-renderer/helpers.d.ts +10 -0
  102. package/dist/shader-renderer/helpers.js +19 -0
  103. package/dist/shader-renderer/index.d.ts +2 -0
  104. package/dist/shader-renderer/index.js +2 -0
  105. package/dist/shader-renderer/pixel-shader.d.ts +32 -0
  106. package/dist/shader-renderer/pixel-shader.js +172 -0
  107. package/dist/shader-renderer/pixel-vertex-shader.d.ts +1 -0
  108. package/dist/shader-renderer/pixel-vertex-shader.js +14 -0
  109. package/dist/shader-renderer/texture.d.ts +28 -0
  110. package/dist/shader-renderer/texture.js +97 -0
  111. package/dist/shader-renderer/types.d.ts +17 -0
  112. package/dist/shader-renderer/types.js +4 -0
  113. package/dist/shader-renderer/uniform.d.ts +16 -0
  114. package/dist/shader-renderer/uniform.js +134 -0
  115. package/dist/tilings/delaunay.d.ts +11 -0
  116. package/dist/tilings/delaunay.js +28 -0
  117. package/dist/tilings/grid.d.ts +5 -0
  118. package/dist/tilings/grid.js +29 -0
  119. package/dist/tilings/hexagononal.d.ts +4 -0
  120. package/dist/tilings/hexagononal.js +40 -0
  121. package/dist/tilings/index.d.ts +12 -0
  122. package/dist/tilings/index.js +12 -0
  123. package/dist/tilings/line.d.ts +5 -0
  124. package/dist/tilings/line.js +19 -0
  125. package/dist/tilings/mediterranean.d.ts +3 -0
  126. package/dist/tilings/mediterranean.js +49 -0
  127. package/dist/tilings/pythagorean.d.ts +3 -0
  128. package/dist/tilings/pythagorean.js +40 -0
  129. package/dist/tilings/random-cuts.d.ts +6 -0
  130. package/dist/tilings/random-cuts.js +16 -0
  131. package/dist/tilings/recursive-cuts.d.ts +5 -0
  132. package/dist/tilings/recursive-cuts.js +11 -0
  133. package/dist/tilings/rhombille.d.ts +3 -0
  134. package/dist/tilings/rhombille.js +16 -0
  135. package/dist/tilings/rightangled-triangle.d.ts +3 -0
  136. package/dist/tilings/rightangled-triangle.js +29 -0
  137. package/dist/tilings/triangle.d.ts +3 -0
  138. package/dist/tilings/triangle.js +17 -0
  139. package/dist/tilings/voronoi.d.ts +11 -0
  140. package/dist/tilings/voronoi.js +29 -0
  141. package/dist/tilings/weaving.d.ts +1 -0
  142. package/dist/tilings/weaving.js +8 -0
  143. package/dist/transforms/camera/camera.d.ts +32 -0
  144. package/dist/transforms/camera/camera.js +60 -0
  145. package/dist/transforms/camera/index.d.ts +3 -0
  146. package/dist/transforms/camera/index.js +3 -0
  147. package/dist/transforms/camera/orthographic.d.ts +15 -0
  148. package/dist/transforms/camera/orthographic.js +31 -0
  149. package/dist/transforms/camera/perspective.d.ts +16 -0
  150. package/dist/transforms/camera/perspective.js +40 -0
  151. package/dist/transforms/index.d.ts +2 -0
  152. package/dist/transforms/index.js +2 -0
  153. package/dist/transforms/normalize-transform.d.ts +12 -0
  154. package/dist/transforms/normalize-transform.js +20 -0
  155. package/dist/types.d.ts +1 -0
  156. package/dist/types.js +1 -0
  157. package/dist/utilities/create-frame.d.ts +2 -0
  158. package/dist/utilities/create-frame.js +6 -0
  159. package/dist/utilities/ensure-array.d.ts +1 -0
  160. package/dist/utilities/ensure-array.js +3 -0
  161. package/dist/utilities/idw-interpolator.d.ts +9 -0
  162. package/dist/utilities/idw-interpolator.js +18 -0
  163. package/dist/utilities/index.d.ts +8 -0
  164. package/dist/utilities/index.js +8 -0
  165. package/dist/utilities/marching-squares.d.ts +51 -0
  166. package/dist/utilities/marching-squares.js +177 -0
  167. package/dist/utilities/point-sampler.d.ts +12 -0
  168. package/dist/utilities/point-sampler.js +24 -0
  169. package/dist/utilities/poisson/grid.d.ts +21 -0
  170. package/dist/utilities/poisson/grid.js +51 -0
  171. package/dist/utilities/poisson/poissonnier.d.ts +50 -0
  172. package/dist/utilities/poisson/poissonnier.js +118 -0
  173. package/dist/utilities/resolution.d.ts +10 -0
  174. package/dist/utilities/resolution.js +14 -0
  175. package/dist/utilities/rng.d.ts +13 -0
  176. package/dist/utilities/rng.js +80 -0
  177. package/package.json +28 -0
@@ -0,0 +1,3 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ export declare function mediterraneanTiling(shape: Polygon | Hollowgon, rotation: number, ratio: number, resolution: number): Polygon[];
@@ -0,0 +1,49 @@
1
+ import { clip } from "../geometry/polygon-operations.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { vec2 } from "../geometry/vec2.js";
4
+ export function mediterraneanTiling(shape, rotation, ratio, resolution) {
5
+ const centroid = shape.centroid();
6
+ const { xMin, yMin, width, height, aspectRatio } = shape
7
+ .clone()
8
+ .rotate(-rotation, centroid)
9
+ .aabb();
10
+ let [columns, rows, size] = aspectRatio > 1 ?
11
+ [Math.round(aspectRatio * resolution), resolution, height / resolution] :
12
+ [resolution, Math.round(resolution / aspectRatio), width / resolution];
13
+ columns += 1;
14
+ rows += 1;
15
+ const radius = 0.5 * ratio * size;
16
+ const tiles = [];
17
+ for (let row = 0; row < rows; row++) {
18
+ const isFirstRow = row === 0;
19
+ const y0 = yMin + row * size;
20
+ for (let column = 0; column < columns; column++) {
21
+ const isFirstColumn = column === 0;
22
+ const x0 = xMin + column * size;
23
+ const squareCenters = [
24
+ [size, size],
25
+ ...(isFirstRow ? [[size, 0]] : []),
26
+ ...(isFirstColumn ? [[0, size]] : []),
27
+ ...(isFirstRow && isFirstColumn ? [[0, 0]] : []),
28
+ ];
29
+ // Squares
30
+ for (const [ox, oy] of squareCenters) {
31
+ tiles.push(new Polygon([vec2(ox + x0 - radius, oy + y0), vec2(ox + x0, oy + y0 - radius), vec2(ox + x0 + radius, oy + y0), vec2(ox + x0, oy + y0 + radius)]));
32
+ }
33
+ // Octagon
34
+ tiles.push(new Polygon([
35
+ vec2(x0 + radius, y0),
36
+ vec2(x0 + size - radius, y0),
37
+ vec2(x0 + size, y0 + radius),
38
+ vec2(x0 + size, y0 + size - radius),
39
+ vec2(x0 + size - radius, y0 + size),
40
+ vec2(x0 + radius, y0 + size),
41
+ vec2(x0, y0 + size - radius),
42
+ vec2(x0, y0 + radius),
43
+ ]));
44
+ }
45
+ }
46
+ for (const tile of tiles)
47
+ tile.rotate(rotation, shape.centroid());
48
+ return clip(tiles, shape);
49
+ }
@@ -0,0 +1,3 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ export declare function pythagoreanTiling(shape: Polygon | Hollowgon, rotation: number, ratio: number, resolution: number): Polygon[];
@@ -0,0 +1,40 @@
1
+ import { clip } from "../geometry/polygon-operations.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { vec2, Vec2 } from "../geometry/vec2.js";
4
+ export function pythagoreanTiling(shape, rotation, ratio, resolution) {
5
+ const centroid = shape.centroid();
6
+ const angle = Math.atan(ratio);
7
+ const { xMin, yMin, width, height, aspectRatio } = shape
8
+ .clone()
9
+ .rotate(-(angle + rotation), centroid)
10
+ .aabb();
11
+ let [columns, rows, size] = aspectRatio > 1 ?
12
+ [Math.round(aspectRatio * resolution), resolution, height / resolution] :
13
+ [resolution, Math.round(resolution / aspectRatio), width / resolution];
14
+ const bigSquare = [
15
+ vec2(0, 0),
16
+ vec2(size, 0),
17
+ vec2(size, size),
18
+ vec2(0, size)
19
+ ].map((v) => v.rotate(-angle));
20
+ const smallSquare = [
21
+ vec2((1 - ratio) * size, size),
22
+ vec2(size, size),
23
+ vec2(size, (1 + ratio) * size),
24
+ vec2((1 - ratio) * size, (1 + ratio) * size)
25
+ ].map((v) => v.rotate(-angle));
26
+ const step = size * Math.hypot(1, ratio);
27
+ const polygons = [];
28
+ for (let row = -0.5; row < rows; row++) {
29
+ const y0 = yMin + row * step;
30
+ for (let column = -0.5; column < columns; column++) {
31
+ const x0 = xMin + column * step;
32
+ const o = vec2(x0, y0);
33
+ polygons.push(new Polygon(bigSquare.map((v) => Vec2.add(v, o))));
34
+ polygons.push(new Polygon(smallSquare.map((v) => Vec2.add(v, o))));
35
+ }
36
+ }
37
+ for (const polygon of polygons)
38
+ polygon.rotate(angle + rotation, centroid);
39
+ return clip(polygons, shape);
40
+ }
@@ -0,0 +1,6 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { OperationShape } from "../geometry/polygon-operations.js";
3
+ import { Polygon } from "../geometry/polygon.js";
4
+ import { RNG } from "../utilities/rng.js";
5
+ export declare function randomCuts(shape: Polygon, rotation: number, cutCount: number, rng: RNG): Array<Polygon>;
6
+ export declare function randomCuts(shape: Hollowgon, rotation: number, cutCount: number, rng: RNG): Array<OperationShape>;
@@ -0,0 +1,16 @@
1
+ import { Line } from "../geometry/line.js";
2
+ import { subdivide } from "../geometry/polygon-operations.js";
3
+ import { Vec2 } from "../geometry/vec2.js";
4
+ export function randomCuts(shape, rotation, cutCount, rng) {
5
+ let polygons = [shape];
6
+ // const centroid = polygon.centroid();
7
+ // const spreadRadius = spread * Math.sqrt(polygon.vertices.reduce((distanceSqr, v) => Math.max(distanceSqr, v.distanceSquared(centroid)), 0));
8
+ for (let i = 0; i < cutCount; i++) {
9
+ // const point = Vec2.add(centroid, Vec2.fromPolar(0.2, Math.PI * rng()));
10
+ // const point = rng.samplePointInDisk(centroid, spreadRadius);
11
+ const point = rng.pointInPolygon(shape);
12
+ const cutLine = new Line(point, Vec2.fromPolar(1, rotation + Math.PI * rng()));
13
+ polygons = subdivide(polygons, cutLine);
14
+ }
15
+ return polygons;
16
+ }
@@ -0,0 +1,5 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { OperationShape } from "../geometry/polygon-operations.js";
3
+ import { Polygon } from "../geometry/polygon.js";
4
+ export declare function recursiveCuts(shape: Polygon, rotation: number, iterations: number): Array<Polygon>;
5
+ export declare function recursiveCuts(shape: Hollowgon, rotation: number, iterations: number): Array<OperationShape>;
@@ -0,0 +1,11 @@
1
+ import { Line } from "../geometry/line.js";
2
+ import { subdivide } from "../geometry/polygon-operations.js";
3
+ import { Vec2 } from "../geometry/vec2.js";
4
+ export function recursiveCuts(shape, rotation, iterations) {
5
+ let polygons = [shape];
6
+ for (let i = 0; i < iterations; i++) {
7
+ const direction = Vec2.fromPolar(1, rotation + (i % 2 === 0 ? 0 : Math.PI / 2));
8
+ polygons = subdivide(polygons, (p) => new Line(p.centroid(), direction));
9
+ }
10
+ return polygons;
11
+ }
@@ -0,0 +1,3 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ export declare function rhombilleTiling(shape: Polygon | Hollowgon, rotation: number, resolution: number): Polygon[];
@@ -0,0 +1,16 @@
1
+ import { clip } from "../geometry/polygon-operations.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { hexagonalTileHelper } from "./hexagononal.js";
4
+ export function rhombilleTiling(shape, rotation, resolution) {
5
+ const hexagons = hexagonalTileHelper(shape, rotation, Math.floor(resolution / 2.0));
6
+ const triangles = [];
7
+ for (const hexagon of hexagons) {
8
+ const center = hexagon.centroid();
9
+ const { vertices } = hexagon;
10
+ triangles.push(new Polygon([vertices[0].clone(), vertices[1].clone(), vertices[2].clone(), center.clone()]), new Polygon([vertices[2].clone(), vertices[3].clone(), vertices[4].clone(), center.clone()]), new Polygon([vertices[4].clone(), vertices[5].clone(), vertices[0].clone(), center.clone()]));
11
+ }
12
+ for (const triangle of triangles)
13
+ triangle.rotate(rotation, shape.centroid());
14
+ // return triangles;
15
+ return clip(triangles, shape);
16
+ }
@@ -0,0 +1,3 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ export declare function rightangledTriangleTiling(shape: Polygon | Hollowgon, rotation: number, resolution: number): Polygon[];
@@ -0,0 +1,29 @@
1
+ import { clip } from "../geometry/polygon-operations.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { vec2 } from "../geometry/vec2.js";
4
+ // TODO is equivalent to isometric tiling down to a transformation
5
+ export function rightangledTriangleTiling(shape, rotation, resolution) {
6
+ const centroid = shape.centroid();
7
+ const { xMin, yMin, width, height, aspectRatio } = shape
8
+ .clone()
9
+ .rotate(-rotation, centroid)
10
+ .aabb();
11
+ let [columns, rows, size] = aspectRatio > 1 ?
12
+ [Math.round(aspectRatio * resolution), resolution, height / resolution] :
13
+ [resolution, Math.round(resolution / aspectRatio), width / resolution];
14
+ let polygons = [];
15
+ for (let row = 0; row < rows; row++) {
16
+ let y0 = yMin + row * size;
17
+ for (let column = 0; column < columns; column++) {
18
+ let x0 = xMin + column * size;
19
+ polygons.push(new Polygon([
20
+ vec2(x0, y0), vec2(x0 + size, y0), vec2(x0, y0 + size),
21
+ ]), new Polygon([
22
+ vec2(x0 + size, y0), vec2(x0 + size, y0 + size), vec2(x0, y0 + size),
23
+ ]));
24
+ }
25
+ }
26
+ for (const polygon of polygons)
27
+ polygon.rotate(rotation, centroid);
28
+ return clip(polygons, shape);
29
+ }
@@ -0,0 +1,3 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ export declare function triangleTiling(shape: Polygon | Hollowgon, rotation: number, resolution: number): Polygon[];
@@ -0,0 +1,17 @@
1
+ import { clip } from "../geometry/polygon-operations.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { hexagonalTileHelper } from "./hexagononal.js";
4
+ export function triangleTiling(shape, rotation, resolution) {
5
+ const hexagons = hexagonalTileHelper(shape, rotation, Math.floor(resolution / 2.0));
6
+ const triangles = [];
7
+ for (const hexagon of hexagons) {
8
+ const center = hexagon.centroid();
9
+ const { vertices } = hexagon;
10
+ for (let i = 0, j = 5; i < 6; j = i++) {
11
+ triangles.push(new Polygon([vertices[j].clone(), vertices[i].clone(), center.clone()]));
12
+ }
13
+ }
14
+ for (const triangle of triangles)
15
+ triangle.rotate(rotation, shape.centroid());
16
+ return clip(triangles, shape);
17
+ }
@@ -0,0 +1,11 @@
1
+ import { Polygon } from "../geometry/polygon.js";
2
+ import { RNG } from "../utilities/rng.js";
3
+ import { PointSamplerStrategy } from "../utilities/point-sampler.js";
4
+ import { Hollowgon } from "../geometry/hollowgon.js";
5
+ export type VoronoiSubdivisionOptions = {
6
+ shape: Polygon | Hollowgon;
7
+ numPoints: number;
8
+ rng: RNG;
9
+ strategy?: PointSamplerStrategy;
10
+ };
11
+ export declare function voronoiSubdivision(options: VoronoiSubdivisionOptions): Polygon[];
@@ -0,0 +1,29 @@
1
+ import { Delaunay } from "d3-delaunay";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { vec2 } from "../geometry/vec2.js";
4
+ import { pointSampler } from "../utilities/point-sampler.js";
5
+ import { Hollowgon } from "../geometry/hollowgon.js";
6
+ import { clip } from "../geometry/polygon-operations.js";
7
+ export function voronoiSubdivision(options) {
8
+ const { shape, numPoints, rng, strategy = "poisson" } = options;
9
+ const { xMin, xMax, yMin, yMax } = shape.aabb();
10
+ const pointBuffer = [];
11
+ for (const { x, y } of pointSampler({ shape, size: numPoints, strategy, rng })) {
12
+ pointBuffer.push(x, y);
13
+ }
14
+ const vertices = shape instanceof Hollowgon ? shape.boundary.vertices : shape.vertices;
15
+ for (const { x, y } of vertices)
16
+ pointBuffer.push(x, y);
17
+ const delaunay = new Delaunay(pointBuffer);
18
+ const voronoi = delaunay.voronoi([xMin, yMin, xMax, yMax]);
19
+ const cells = voronoi.cellPolygons();
20
+ const polygons = [];
21
+ for (const triangle of cells) {
22
+ const vertices = [];
23
+ for (const vertex of triangle) {
24
+ vertices.push(vec2(vertex[0], vertex[1]));
25
+ }
26
+ polygons.push(new Polygon(vertices));
27
+ }
28
+ return clip(polygons, shape);
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export {};
2
+ // function weavingTiling(polygon: Polygon, rotation: number, size: number) {
3
+ // // const centroid = polygon.centroid();
4
+ // // const { xMin, xMax, yMin, yMax, width, height } = polygon
5
+ // // .clone()
6
+ // // .rotate(-rotation, centroid)
7
+ // // .aabb();
8
+ // }
@@ -0,0 +1,32 @@
1
+ import { AABB } from "../../geometry/aabb.js";
2
+ import { Ray3 } from "../../geometry/ray3.js";
3
+ import { Vec2 } from "../../geometry/vec2.js";
4
+ import { Vec3 } from "../../geometry/vec3.js";
5
+ import { Resolution } from "../../utilities/resolution.js";
6
+ export type CameraOptions = {
7
+ position: Vec3;
8
+ lookAt?: Vec3;
9
+ direction?: Vec3;
10
+ rotation?: number;
11
+ resolution: Resolution;
12
+ };
13
+ export declare abstract class Camera {
14
+ position: Vec3;
15
+ lookAt: Vec3;
16
+ rotation: number;
17
+ resolution: Resolution;
18
+ viewbox: AABB;
19
+ matrix: DOMMatrix;
20
+ direction: Vec3;
21
+ viewBasis: [Vec3, Vec3, Vec3];
22
+ constructor(options: CameraOptions);
23
+ computeMatrix(): DOMMatrix;
24
+ worldVectorToView(worldVector: Vec3): Vec3;
25
+ worldPositionToView(worldPosition: Vec3): Vec3;
26
+ worldVectorToScreen(worldVector: Vec3): Vec3;
27
+ worldPositionToScreen(worldPosition: Vec3): Vec3;
28
+ mapScreenToXYPlane(screenPosition: Vec2, z?: number): Vec3;
29
+ abstract projectViewToScreen(viewPosition: Vec3): Vec3;
30
+ abstract unprojectScreenToView(screenPosition: Vec3): Vec3;
31
+ abstract getRayAtScreenPosition(screenPosition: Vec2): Ray3;
32
+ }
@@ -0,0 +1,60 @@
1
+ import { AABB } from "../../geometry/aabb.js";
2
+ import { create2DBasis } from "../../geometry/transformations.js";
3
+ import { Vec3, vec3 } from "../../geometry/vec3.js";
4
+ import { toDegrees } from "../../math/units.js";
5
+ export class Camera {
6
+ constructor(options) {
7
+ let { position, lookAt, direction, rotation = 0, resolution } = options;
8
+ if (!lookAt && !direction)
9
+ throw new Error("At least one of lookAt and direction must be specified");
10
+ if (lookAt && direction)
11
+ throw new Error("Only one of lookAt and direction can be specified");
12
+ direction ?? (direction = Vec3.subtract(lookAt, position).normalize());
13
+ this.position = position;
14
+ this.lookAt = lookAt ?? Vec3.add(position, direction);
15
+ this.rotation = rotation;
16
+ this.resolution = resolution;
17
+ const aspectRatio = resolution.width / resolution.height;
18
+ this.viewbox = aspectRatio > 1 ? new AABB(-aspectRatio, aspectRatio, -1, 1) : new AABB(-1, 1, -1 / aspectRatio, 1 / aspectRatio);
19
+ const [i, j] = create2DBasis(direction);
20
+ this.viewBasis = [i, j, direction];
21
+ this.direction = direction;
22
+ this.matrix = this.computeMatrix();
23
+ }
24
+ computeMatrix() {
25
+ const { resolution: { width, height }, rotation } = this;
26
+ const minDimension = Math.min(width, height);
27
+ // Read backwards, starting on last comment and moving updwards
28
+ return new DOMMatrix()
29
+ // Finally, translate position to give [0, width] x [0, height]
30
+ .translateSelf(width / 2, height / 2)
31
+ // Since the position comes from a normalized coordinate system with correct aspect ratio,
32
+ // multiplying by the smaller dimension will give [-width/2, width/2] x [-height/2, height/2]
33
+ .scaleSelf(minDimension / 2)
34
+ // Rotates clockwise (when camera rotates, rendered content rotates the opposite direction)
35
+ // Important: rotateSelf expects degrees, not radians
36
+ .rotateSelf(-toDegrees(rotation));
37
+ // Here position is in aspect ratio-corrected screen space
38
+ // [-1, 1] x [-1/asp, 1/asp] if asp < 1
39
+ // [-asp, asp] x [-1, 1] if asp > 1
40
+ }
41
+ worldVectorToView(worldVector) {
42
+ const [i, j, k] = this.viewBasis;
43
+ return vec3(i.dot(worldVector), j.dot(worldVector), k.dot(worldVector));
44
+ }
45
+ worldPositionToView(worldPosition) {
46
+ return this.worldVectorToView(Vec3.subtract(worldPosition, this.position));
47
+ }
48
+ worldVectorToScreen(worldVector) {
49
+ return this.projectViewToScreen(this.worldVectorToView(worldVector));
50
+ }
51
+ worldPositionToScreen(worldPosition) {
52
+ return this.projectViewToScreen(this.worldPositionToView(worldPosition));
53
+ }
54
+ // Idea: determine ray that corresponds to screenPosition and compute its intersection with plane at z
55
+ mapScreenToXYPlane(screenPosition, z = 0) {
56
+ const ray = this.getRayAtScreenPosition(screenPosition);
57
+ const timeOfIntersection = (z - ray.point.z) / ray.direction.z;
58
+ return ray.interpolate(timeOfIntersection);
59
+ }
60
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./camera.js";
2
+ export * from "./perspective.js";
3
+ export * from "./orthographic.js";
@@ -0,0 +1,3 @@
1
+ export * from "./camera.js";
2
+ export * from "./perspective.js";
3
+ export * from "./orthographic.js";
@@ -0,0 +1,15 @@
1
+ import { Ray3 } from "../../geometry/ray3.js";
2
+ import { Vec2 } from "../../geometry/vec2.js";
3
+ import { Vec3 } from "../../geometry/vec3.js";
4
+ import { CameraOptions, Camera } from "./camera.js";
5
+ export type OrthographicCameraOptions = CameraOptions & {
6
+ viewport: number;
7
+ };
8
+ export declare class OrthographicCamera extends Camera {
9
+ viewport: number;
10
+ planarBasis: [Vec2, Vec2];
11
+ constructor(options: OrthographicCameraOptions);
12
+ projectViewToScreen(viewPosition: Vec3): Vec3;
13
+ unprojectScreenToView(screenPosition: Vec3): Vec3;
14
+ getRayAtScreenPosition(screenPosition: Vec2): Ray3;
15
+ }
@@ -0,0 +1,31 @@
1
+ import { Ray3 } from "../../geometry/ray3.js";
2
+ import { vec2 } from "../../geometry/vec2.js";
3
+ import { Vec3, vec3 } from "../../geometry/vec3.js";
4
+ import { Camera } from "./camera.js";
5
+ export class OrthographicCamera extends Camera {
6
+ constructor(options) {
7
+ super(options);
8
+ this.viewport = options.viewport;
9
+ const [i, j, k] = this.viewBasis;
10
+ const xInv = vec2(i.x - k.x / k.z * i.z, j.x - k.x / k.z * j.z);
11
+ const yInv = vec2(i.y - k.y / k.z * i.z, j.y - k.y / k.z * j.z);
12
+ this.planarBasis = [xInv, yInv];
13
+ }
14
+ projectViewToScreen(viewPosition) {
15
+ const { viewport } = this;
16
+ const { x, y, z } = viewPosition;
17
+ const coeff = 2 / viewport;
18
+ return vec3(coeff * x, coeff * y, z);
19
+ }
20
+ unprojectScreenToView(screenPosition) {
21
+ const { position, viewport } = this;
22
+ const [i, j, k] = this.viewBasis;
23
+ const coeff = viewport / 2;
24
+ return Vec3.add(position, Vec3.multiply(i, coeff * screenPosition.x), Vec3.multiply(j, coeff * screenPosition.y), Vec3.multiply(k, screenPosition.z));
25
+ }
26
+ getRayAtScreenPosition(screenPosition) {
27
+ const position = this.unprojectScreenToView(screenPosition.toVec3(0));
28
+ const direction = this.viewBasis[2];
29
+ return new Ray3(position, direction);
30
+ }
31
+ }
@@ -0,0 +1,16 @@
1
+ import { Ray3 } from "../../geometry/ray3.js";
2
+ import { Vec2 } from "../../geometry/vec2.js";
3
+ import { Vec3 } from "../../geometry/vec3.js";
4
+ import { CameraOptions, Camera } from "./camera.js";
5
+ export type PerspectiveCameraOptions = CameraOptions & {
6
+ viewport?: number;
7
+ fov?: number;
8
+ };
9
+ export declare class PerspectiveCamera extends Camera {
10
+ private coefficient;
11
+ fov: number;
12
+ constructor(options: PerspectiveCameraOptions);
13
+ projectViewToScreen(viewPosition: Vec3): Vec3;
14
+ unprojectScreenToView(screenPosition: Vec3): Vec3;
15
+ getRayAtScreenPosition(screenPosition: Vec2): Ray3;
16
+ }
@@ -0,0 +1,40 @@
1
+ import { Ray3 } from "../../geometry/ray3.js";
2
+ import { Vec3, vec3 } from "../../geometry/vec3.js";
3
+ import { Camera } from "./camera.js";
4
+ export class PerspectiveCamera extends Camera {
5
+ constructor(options) {
6
+ super(options);
7
+ const { viewport, fov } = options;
8
+ if (viewport !== undefined && fov !== undefined) {
9
+ throw new Error("Only one of fov and viewport must be specified");
10
+ }
11
+ else if (viewport !== undefined) {
12
+ const distanceToLookAt = Vec3.distance(this.position, this.lookAt);
13
+ this.coefficient = 2 * distanceToLookAt / viewport;
14
+ this.fov = 2 * Math.atan(1 / this.coefficient);
15
+ }
16
+ else if (fov !== undefined) {
17
+ this.fov = fov;
18
+ this.coefficient = 1 / Math.tan(fov / 2);
19
+ }
20
+ else {
21
+ throw new Error("Either fov or viewport must be specified");
22
+ }
23
+ }
24
+ projectViewToScreen(viewPosition) {
25
+ const { coefficient } = this;
26
+ const { x, y, z } = viewPosition;
27
+ return vec3(coefficient * x / z, coefficient * y / z, z);
28
+ }
29
+ unprojectScreenToView(screenPosition) {
30
+ const { position, coefficient } = this;
31
+ const [i, j, k] = this.viewBasis;
32
+ return Vec3.add(position, Vec3.multiply(i, screenPosition.x / coefficient), Vec3.multiply(j, screenPosition.y / coefficient), Vec3.multiply(k, screenPosition.z));
33
+ }
34
+ getRayAtScreenPosition(screenPosition) {
35
+ const { position } = this;
36
+ const offsetPosition = this.unprojectScreenToView(screenPosition.toVec3(1));
37
+ const direction = Vec3.subtract(offsetPosition, position).normalize();
38
+ return new Ray3(position, direction);
39
+ }
40
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./camera/index.js";
2
+ export * from "./normalize-transform.js";
@@ -0,0 +1,2 @@
1
+ export * from "./camera/index.js";
2
+ export * from "./normalize-transform.js";
@@ -0,0 +1,12 @@
1
+ import { Vec2 } from "../geometry/vec2.js";
2
+ import { Resolution } from "../utilities/resolution.js";
3
+ export type NormalizeTransformOptions = {
4
+ center?: Vec2;
5
+ viewport?: number;
6
+ resolution: Resolution;
7
+ };
8
+ export declare function normalizeTransform(options: NormalizeTransformOptions): {
9
+ matrix: DOMMatrix;
10
+ toPixel: (worldUnits: number) => number;
11
+ fromPixel: (pixelUnits: number) => number;
12
+ };
@@ -0,0 +1,20 @@
1
+ import { vec2 } from "../geometry/vec2.js";
2
+ export function normalizeTransform(options) {
3
+ const { center = vec2(0), viewport = 2, resolution } = options;
4
+ const { width, height } = resolution;
5
+ const aspectRatio = width / height;
6
+ const [scaleX, scaleY] = (aspectRatio > 1 ? [aspectRatio * viewport, viewport] : [viewport, viewport / aspectRatio]);
7
+ const matrix = new DOMMatrix();
8
+ matrix
9
+ .translateSelf(width / 2, height / 2)
10
+ .scaleSelf(width / scaleX, height / scaleY)
11
+ .translateSelf(-center.x, -center.y);
12
+ const scale = width / scaleX;
13
+ const scaleToPixel = (worldUnits) => scale * worldUnits;
14
+ const scaleFromPixel = (pixelUnits) => pixelUnits / scale;
15
+ return {
16
+ matrix,
17
+ toPixel: scaleToPixel,
18
+ fromPixel: scaleFromPixel
19
+ };
20
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { AABB } from "../geometry/aabb.js";
2
+ export declare function createFrame(extent: AABB, margin: number): AABB;
@@ -0,0 +1,6 @@
1
+ export function createFrame(extent, margin) {
2
+ const { width, height } = extent;
3
+ const minDimension = Math.min(width, height);
4
+ const marginSize = 0.5 * margin * minDimension;
5
+ return extent.clone().grow(-marginSize);
6
+ }
@@ -0,0 +1 @@
1
+ export declare function ensureArray<T>(value: T | Array<T>): T[];
@@ -0,0 +1,3 @@
1
+ export function ensureArray(value) {
2
+ return Array.isArray(value) ? value : [value];
3
+ }
@@ -0,0 +1,9 @@
1
+ import { Vec2 } from "../geometry/vec2.js";
2
+ export type CreateIDWInterpolatorOptions = {
3
+ data: Array<{
4
+ position: Vec2;
5
+ value: number;
6
+ }>;
7
+ power?: number;
8
+ };
9
+ export declare function createIDWInterpolator(options: CreateIDWInterpolatorOptions): (v: Vec2, power?: number) => number;
@@ -0,0 +1,18 @@
1
+ const { pow } = Math;
2
+ export function createIDWInterpolator(options) {
3
+ const { data, power: globalPower = 2 } = options;
4
+ return (v, power = globalPower) => {
5
+ let sum = 0;
6
+ let weightSum = 0;
7
+ const effectivePower = -0.5 * power;
8
+ for (const { position, value } of data) {
9
+ const distanceSquared = v.distanceSquared(position);
10
+ const weight = pow(distanceSquared, effectivePower);
11
+ if (!isFinite(weight))
12
+ return value;
13
+ sum += weight * value;
14
+ weightSum += weight;
15
+ }
16
+ return sum / weightSum;
17
+ };
18
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./marching-squares.js";
2
+ export { type RNG, createRNG } from "./rng.js";
3
+ export { Poissonnier, type PoissonnierOptions, type PointData, type GenerateFixedSizeSampleOptions } from "./poisson/poissonnier.js";
4
+ export * from "./resolution.js";
5
+ export * from "./idw-interpolator.js";
6
+ export * from "./create-frame.js";
7
+ export * from "./point-sampler.js";
8
+ export * from "./ensure-array.js";
@@ -0,0 +1,8 @@
1
+ export * from "./marching-squares.js";
2
+ export { createRNG } from "./rng.js";
3
+ export { Poissonnier } from "./poisson/poissonnier.js";
4
+ export * from "./resolution.js";
5
+ export * from "./idw-interpolator.js";
6
+ export * from "./create-frame.js";
7
+ export * from "./point-sampler.js";
8
+ export * from "./ensure-array.js";