@richardmcquiston01/more-open-scad 0.2.0
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.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/csg/boolean.d.ts +22 -0
- package/dist/csg/boolean.d.ts.map +1 -0
- package/dist/csg/bsp-tree.d.ts +70 -0
- package/dist/csg/bsp-tree.d.ts.map +1 -0
- package/dist/csg/split-polygon.d.ts +62 -0
- package/dist/csg/split-polygon.d.ts.map +1 -0
- package/dist/geometry/plane.d.ts +31 -0
- package/dist/geometry/plane.d.ts.map +1 -0
- package/dist/geometry/polygon.d.ts +24 -0
- package/dist/geometry/polygon.d.ts.map +1 -0
- package/dist/geometry/solid.d.ts +41 -0
- package/dist/geometry/solid.d.ts.map +1 -0
- package/dist/geometry/triangulate.d.ts +16 -0
- package/dist/geometry/triangulate.d.ts.map +1 -0
- package/dist/geometry/vertex.d.ts +20 -0
- package/dist/geometry/vertex.d.ts.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1016 -0
- package/dist/io/manifold-check.d.ts +20 -0
- package/dist/io/manifold-check.d.ts.map +1 -0
- package/dist/io/stl-ascii.d.ts +14 -0
- package/dist/io/stl-ascii.d.ts.map +1 -0
- package/dist/io/stl-binary.d.ts +13 -0
- package/dist/io/stl-binary.d.ts.map +1 -0
- package/dist/io/triangulate-solid.d.ts +25 -0
- package/dist/io/triangulate-solid.d.ts.map +1 -0
- package/dist/math/epsilon.d.ts +10 -0
- package/dist/math/epsilon.d.ts.map +1 -0
- package/dist/math/mat4.d.ts +75 -0
- package/dist/math/mat4.d.ts.map +1 -0
- package/dist/math/vec3.d.ts +43 -0
- package/dist/math/vec3.d.ts.map +1 -0
- package/dist/primitives/cube.d.ts +21 -0
- package/dist/primitives/cube.d.ts.map +1 -0
- package/dist/primitives/cylinder.d.ts +32 -0
- package/dist/primitives/cylinder.d.ts.map +1 -0
- package/dist/primitives/polyhedron.d.ts +36 -0
- package/dist/primitives/polyhedron.d.ts.map +1 -0
- package/dist/primitives/sphere.d.ts +35 -0
- package/dist/primitives/sphere.d.ts.map +1 -0
- package/package.json +62 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [0.2.0] - 2026-09-23
|
|
8
|
+
|
|
9
|
+
The first version actually published to npm.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- CSG plane/polygon splitting (`src/csg/split-polygon.ts`): `splitPolygon`, the geometric core of the BSP-tree boolean operations below. Classifies a polygon against a plane (coplanar/front/back/spanning) and clips spanning polygons into front/back pieces, preserving winding. Not part of the public API.
|
|
14
|
+
- CSG BSP tree (`src/csg/bsp-tree.ts`): the classic Naylor/Thibault BSP-CSG tree (as popularized by csg.js), built on `splitPolygon` and adapted to this codebase's immutable conventions — `build`, `clipPolygons`, `clipTo`, `invert`, and `allPolygons` all return new trees rather than mutating one. Not part of the public API; `src/csg/boolean.ts` is the only consumer.
|
|
15
|
+
- CSG boolean operations: `union`, `difference`, and `intersect`, matching OpenSCAD's `union()`/`difference()`/`intersection()`. Each takes two `Solid`s and returns a new one; chain calls to combine more than two (`union(union(a, b), c)`).
|
|
16
|
+
- A tag-triggered npm publish workflow (`.github/workflows/publish.yml`): pushing a `v*.*.*` tag on `main` re-verifies typecheck/lint/test/build, then publishes.
|
|
17
|
+
- The standard "Buy Me a Coffee" donate section in the README.
|
|
18
|
+
|
|
19
|
+
## [0.1.0] - 2026-07-24
|
|
20
|
+
|
|
21
|
+
Primitives, transforms, and STL export. Never published to npm — superseded by 0.2.0 before a release was cut.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Primitives: `cube`, `sphere`, `cylinder`, and `polyhedron` (the arbitrary-mesh escape hatch), matching OpenSCAD's semantics — see each function's docs for its options.
|
|
26
|
+
- Chainable transforms on `Solid`: `translate`, `rotate` (Euler angles), `rotateAxisAngle`, `scale` (uniform or per-axis), `mirror`, and `multmatrix` (arbitrary 4x4 transform). Normals transform correctly under non-uniform scale, and winding is automatically corrected for any handedness-flipping transform (e.g. `mirror`).
|
|
27
|
+
- STL export: `toBinarySTL` and `toASCIISTL`, plus `isManifold` for checking a solid is watertight before exporting, and `triangulateSolid` for consumers who want raw per-facet triangle data directly (e.g. to feed a WebGL renderer).
|
|
28
|
+
- The full `Vec3`/`Mat4` math toolkit and the underlying `Vertex`/`Polygon`/`Plane`/`Solid` geometry types, for consumers who want to inspect or hand-build geometry beyond what the primitives above cover.
|
|
29
|
+
- Project scaffolding: TypeScript build/typecheck/lint/test pipeline (`bun`-based) and GitHub Actions CI.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Removed `"sideEffects": false` from `package.json` — it was causing `bun build` to silently tree-shake away the entire bundled implementation behind the public barrel export (`src/index.ts`), shipping an empty package. Caught before publishing via an end-to-end smoke test against the actual built `dist/index.js`.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- Pinned `prettier` to the exact installed version (`3.9.6`, was `^3.4.2`) so `bun run format` no longer produces unrelated diffs from version drift.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Richard McQuiston
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# MoreOpenSCAD
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Framework agnostic TypeScript based package for generating STL files using commands similar to OpenSCAD. Distributable via NPM for inclusion in TypeScript projects.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- [Node.js](https://nodejs.org/) 18+ or [Bun](https://bun.sh/) 1.0+
|
|
10
|
+
- TypeScript 5+ (for consuming projects that want type checking)
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @richardmcquiston01/more-open-scad
|
|
16
|
+
# or
|
|
17
|
+
npm install @richardmcquiston01/more-open-scad
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Build a shape with a primitive, chain transforms onto it, then export it to STL.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { cube, Vec3, toBinarySTL } from '@richardmcquiston01/more-open-scad';
|
|
26
|
+
|
|
27
|
+
const shape = cube(20, { center: true })
|
|
28
|
+
.translate(Vec3.vec3(0, 0, 10))
|
|
29
|
+
.rotateAxisAngle(Vec3.vec3(0, 0, 1), Math.PI / 4);
|
|
30
|
+
|
|
31
|
+
const stl = toBinarySTL(shape); // Uint8Array
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Primitives
|
|
35
|
+
|
|
36
|
+
`cube(size, options?)`, `sphere(r, options?)`, `cylinder(h, options?)`, and `polyhedron(points, faces)` (the arbitrary-mesh escape hatch) each build a `Solid`, matching OpenSCAD's semantics for the same primitive. See each function's JSDoc for its options (`center`, `fn`, `r`/`r1`/`r2`, etc.).
|
|
37
|
+
|
|
38
|
+
### Transforms
|
|
39
|
+
|
|
40
|
+
Every `Solid` has chainable, immutable transform methods: `translate`, `rotate` (Euler angles), `rotateAxisAngle`, `scale` (uniform or per-axis), `mirror`, and `multmatrix` (an arbitrary 4x4 transform, for anything the named methods don't cover). Each call returns a new `Solid` — none of them mutate the original.
|
|
41
|
+
|
|
42
|
+
### Boolean operations
|
|
43
|
+
|
|
44
|
+
`union(a, b)`, `difference(a, b)`, and `intersect(a, b)` combine two solids into a new one, matching OpenSCAD's `union()`/`difference()`/`intersection()`:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { cube, difference, Vec3 } from '@richardmcquiston01/more-open-scad';
|
|
48
|
+
|
|
49
|
+
const block = cube(20, { center: true });
|
|
50
|
+
const hole = cube(8, { center: true }).translate(Vec3.vec3(0, 0, 6));
|
|
51
|
+
|
|
52
|
+
const blockWithHole = difference(block, hole);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Neither input `Solid` is mutated; each call returns a new one. Combine more than two solids by chaining calls, e.g. `union(union(a, b), c)`.
|
|
56
|
+
|
|
57
|
+
### Exporting to STL
|
|
58
|
+
|
|
59
|
+
`toBinarySTL(solid)` returns a `Uint8Array` (the binary STL format); `toASCIISTL(solid, name?)` returns a `string` (the ASCII STL format). Neither writes to disk — this package stays framework-agnostic by handing back bytes/text and leaving file I/O to you:
|
|
60
|
+
|
|
61
|
+
**Node.js:**
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { writeFileSync } from 'node:fs';
|
|
65
|
+
import { cube, toBinarySTL } from '@richardmcquiston01/more-open-scad';
|
|
66
|
+
|
|
67
|
+
writeFileSync('cube.stl', toBinarySTL(cube(20, { center: true })));
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Browser (trigger a download):**
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { cube, toBinarySTL } from '@richardmcquiston01/more-open-scad';
|
|
74
|
+
|
|
75
|
+
const stl = toBinarySTL(cube(20, { center: true }));
|
|
76
|
+
const url = URL.createObjectURL(new Blob([stl], { type: 'model/stl' }));
|
|
77
|
+
|
|
78
|
+
const link = document.createElement('a');
|
|
79
|
+
link.href = url;
|
|
80
|
+
link.download = 'cube.stl';
|
|
81
|
+
link.click();
|
|
82
|
+
URL.revokeObjectURL(url);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Before exporting, `isManifold(solid)` checks whether a `Solid` is watertight (every edge shared by exactly two triangles wound in opposite directions) — useful as a sanity check that geometry is 3D-print-ready.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
[MIT](LICENSE)
|
|
90
|
+
|
|
91
|
+
## Copyright
|
|
92
|
+
|
|
93
|
+
(c) 2026 Richard McQuiston.
|
|
94
|
+
|
|
95
|
+
## Buy Me a Coffee
|
|
96
|
+
|
|
97
|
+
If this app, code, or repository has helped you or someone you know, please consider donating. I appreciate any help to offset the costs of development and/or AI Credits.
|
|
98
|
+
|
|
99
|
+
[**Donate via Stripe**](https://donate.stripe.com/00w5kD3Gj1Xo9v7gVOcs800), or scan:
|
|
100
|
+
|
|
101
|
+
[](https://donate.stripe.com/00w5kD3Gj1Xo9v7gVOcs800)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Solid } from '../geometry/solid';
|
|
2
|
+
/**
|
|
3
|
+
* The three boolean operations below are the classic BSP-CSG algorithm
|
|
4
|
+
* (Naylor/Thibault, as popularized by csg.js), expressed with this
|
|
5
|
+
* codebase's immutable `Bsp` functions in place of the original's
|
|
6
|
+
* in-place `Node` mutations. Each op builds a tree per input solid, uses
|
|
7
|
+
* `clipTo`/`invert` to cut away the region that should not survive, then
|
|
8
|
+
* merges what's left of one tree into the other with `build` and reads
|
|
9
|
+
* the result back out with `allPolygons`.
|
|
10
|
+
*
|
|
11
|
+
* `difference`/`intersect` reduce to the same shape as `union` by
|
|
12
|
+
* inverting one or both solids first — inside-out, "the part of A not in
|
|
13
|
+
* B" is "the union of (inside-out A) and B, inside-out" — which is why
|
|
14
|
+
* every op ends by inverting back if it inverted going in.
|
|
15
|
+
*/
|
|
16
|
+
/** The union of `a` and `b`: every point inside either solid. */
|
|
17
|
+
export declare function union(a: Solid, b: Solid): Solid;
|
|
18
|
+
/** `a` with the part it shares with `b` removed. */
|
|
19
|
+
export declare function difference(a: Solid, b: Solid): Solid;
|
|
20
|
+
/** The intersection of `a` and `b`: only the region inside both solids. */
|
|
21
|
+
export declare function intersect(a: Solid, b: Solid): Solid;
|
|
22
|
+
//# sourceMappingURL=boolean.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boolean.d.ts","sourceRoot":"","sources":["../../src/csg/boolean.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAI1C;;;;;;;;;;;;;GAaG;AAEH,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAY/C;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAcpD;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAanD"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Plane as PlaneType } from '../geometry/plane';
|
|
2
|
+
import type { Polygon as PolygonType } from '../geometry/polygon';
|
|
3
|
+
/**
|
|
4
|
+
* A node in a BSP (binary space partitioning) tree, à la the classic
|
|
5
|
+
* BSP-CSG algorithm (Naylor/Thibault, as popularized by csg.js), adapted
|
|
6
|
+
* to this codebase's immutable value-type conventions: every function
|
|
7
|
+
* below returns a new tree rather than mutating an existing one.
|
|
8
|
+
*
|
|
9
|
+
* `polygons` holds every polygon found to be exactly coplanar with `plane`
|
|
10
|
+
* while building the tree — both those facing the same direction as
|
|
11
|
+
* `plane.normal` and those facing the opposite way (the classic algorithm
|
|
12
|
+
* keeps both in one list; nothing downstream needs them told apart).
|
|
13
|
+
* Everything else lives in `front`/`back`, which partition the remaining
|
|
14
|
+
* space on either side of `plane`. `null` (used for `front`/`back`, and as
|
|
15
|
+
* the whole-tree result of building from zero polygons) represents an
|
|
16
|
+
* empty subtree — "no polygons, no constraint on this side of the plane".
|
|
17
|
+
*/
|
|
18
|
+
export interface BspNode {
|
|
19
|
+
readonly plane: PlaneType;
|
|
20
|
+
readonly polygons: readonly PolygonType[];
|
|
21
|
+
readonly front: BspNode | null;
|
|
22
|
+
readonly back: BspNode | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Builds a BSP tree from `polygons`, optionally inserting them into an
|
|
26
|
+
* already-built `node` instead of starting fresh (the classic algorithm's
|
|
27
|
+
* `Node.build` serves both roles too: the first call establishes each
|
|
28
|
+
* node's splitting plane from its first polygon, and later calls partition
|
|
29
|
+
* new polygons through the existing planes, recursing into — or lazily
|
|
30
|
+
* creating — the `front`/`back` subtrees as needed).
|
|
31
|
+
*
|
|
32
|
+
* The splitting plane for a fresh node is `polygons[0]`'s own plane, so
|
|
33
|
+
* that polygon always lands in the returned node's `polygons` (as a
|
|
34
|
+
* `coplanarFront`, since a plane never disagrees with itself) rather than
|
|
35
|
+
* being recursed into a subtree.
|
|
36
|
+
*/
|
|
37
|
+
export declare function build(polygons: readonly PolygonType[], node?: BspNode | null): BspNode | null;
|
|
38
|
+
/**
|
|
39
|
+
* Clips `polygons` against the solid volume `node` represents: every part
|
|
40
|
+
* of every polygon that lies in front of `node`'s planes survives (kept
|
|
41
|
+
* whole where possible, split where a polygon straddles a plane), and
|
|
42
|
+
* every part behind all of them — i.e. inside the volume — is discarded.
|
|
43
|
+
* A `null` node clips nothing away (there is no volume to be in front of),
|
|
44
|
+
* so every polygon survives unchanged.
|
|
45
|
+
*
|
|
46
|
+
* A polygon exactly coplanar with a node's plane is treated as `front` or
|
|
47
|
+
* `back` according to which way it's coplanar (matching `splitPolygon`'s
|
|
48
|
+
* `coplanarFront`/`coplanarBack` split), rather than being kept at that
|
|
49
|
+
* node the way `build` does — clipping only ever keeps or discards, it
|
|
50
|
+
* never needs to *store* a polygon at a particular node.
|
|
51
|
+
*/
|
|
52
|
+
export declare function clipPolygons(node: BspNode | null, polygons: readonly PolygonType[]): PolygonType[];
|
|
53
|
+
/**
|
|
54
|
+
* Clips every polygon stored in `node` (at every level of the tree)
|
|
55
|
+
* against the solid volume `other` represents, returning the resulting
|
|
56
|
+
* tree. Used to remove the part of one solid that lies inside another,
|
|
57
|
+
* without discarding `node`'s own plane structure.
|
|
58
|
+
*/
|
|
59
|
+
export declare function clipTo(node: BspNode | null, other: BspNode | null): BspNode | null;
|
|
60
|
+
/**
|
|
61
|
+
* Turns `node`'s solid inside-out: every plane and polygon is flipped
|
|
62
|
+
* (`Plane.flip`/`Polygon.flip`), and `front`/`back` are swapped, so the
|
|
63
|
+
* region the tree used to consider "inside" is now "outside" and vice
|
|
64
|
+
* versa. Boolean ops use this to re-express subtraction/intersection in
|
|
65
|
+
* terms of union (see `../csg/boolean.ts`).
|
|
66
|
+
*/
|
|
67
|
+
export declare function invert(node: BspNode | null): BspNode | null;
|
|
68
|
+
/** Collects every polygon stored anywhere in `node`'s tree. */
|
|
69
|
+
export declare function allPolygons(node: BspNode | null): PolygonType[];
|
|
70
|
+
//# sourceMappingURL=bsp-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsp-tree.d.ts","sourceRoot":"","sources":["../../src/csg/bsp-tree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CACnB,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,IAAI,GAAE,OAAO,GAAG,IAAW,GAC1B,OAAO,GAAG,IAAI,CAqBhB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC/B,WAAW,EAAE,CAiBf;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,KAAK,EAAE,OAAO,GAAG,IAAI,GACpB,OAAO,GAAG,IAAI,CAQhB;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAQ3D;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,WAAW,EAAE,CAO/D"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Plane as PlaneType } from '../geometry/plane';
|
|
2
|
+
import type { Polygon as PolygonType } from '../geometry/polygon';
|
|
3
|
+
/** Exactly on the plane, within `EPSILON`. */
|
|
4
|
+
export declare const COPLANAR = 0;
|
|
5
|
+
/** Strictly on the side the plane's normal points toward. */
|
|
6
|
+
export declare const FRONT = 1;
|
|
7
|
+
/** Strictly on the opposite side from the plane's normal. */
|
|
8
|
+
export declare const BACK = 2;
|
|
9
|
+
/** Both `Front` and `Back` — the polygon crosses the plane. */
|
|
10
|
+
export declare const SPANNING = 3;
|
|
11
|
+
/**
|
|
12
|
+
* How a vertex (or, bitwise-OR'd together, a whole polygon) sits relative
|
|
13
|
+
* to a splitting plane. `Spanning` is `Front | Back`: a polygon spans the
|
|
14
|
+
* plane exactly when it has at least one strictly-front and one
|
|
15
|
+
* strictly-back vertex.
|
|
16
|
+
*/
|
|
17
|
+
export type Classification = typeof COPLANAR | typeof FRONT | typeof BACK | typeof SPANNING;
|
|
18
|
+
/**
|
|
19
|
+
* The result of splitting one polygon against one plane. A polygon lands
|
|
20
|
+
* in exactly one of the four buckets, except a `Spanning` polygon, which
|
|
21
|
+
* contributes one clipped piece to both `front` and `back` (or is dropped
|
|
22
|
+
* from a side entirely if clipping leaves fewer than 3 vertices on that
|
|
23
|
+
* side — see `splitPolygon`). Every field is an array purely for uniform,
|
|
24
|
+
* concatenation-friendly call sites (the BSP tree in later stages will
|
|
25
|
+
* accumulate many of these); for this library's always-convex `Polygon`,
|
|
26
|
+
* each field holds at most one polygon per call.
|
|
27
|
+
*/
|
|
28
|
+
export interface SplitResult {
|
|
29
|
+
/** Coplanar with the plane, facing the same direction as its normal. */
|
|
30
|
+
readonly coplanarFront: readonly PolygonType[];
|
|
31
|
+
/** Coplanar with the plane, facing the opposite direction. */
|
|
32
|
+
readonly coplanarBack: readonly PolygonType[];
|
|
33
|
+
/** Strictly in front of the plane (or the front piece of a split). */
|
|
34
|
+
readonly front: readonly PolygonType[];
|
|
35
|
+
/** Strictly behind the plane (or the back piece of a split). */
|
|
36
|
+
readonly back: readonly PolygonType[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Classifies `polygon` against `plane` and splits it if it spans the
|
|
40
|
+
* plane, à la the classic BSP-CSG algorithm (Naylor/Thibault, as
|
|
41
|
+
* popularized by csg.js).
|
|
42
|
+
*
|
|
43
|
+
* Each vertex is classified `Front`/`Back`/`Coplanar` by its signed
|
|
44
|
+
* distance to the plane (within `EPSILON`); the polygon's overall
|
|
45
|
+
* classification is the bitwise OR of its vertices' classifications.
|
|
46
|
+
* `Coplanar` polygons are further split into `coplanarFront`/
|
|
47
|
+
* `coplanarBack` by comparing their own plane's normal to the splitting
|
|
48
|
+
* plane's normal. A `Spanning` polygon is walked edge by edge: each
|
|
49
|
+
* vertex joins the front chain (if not strictly `Back`), the back chain
|
|
50
|
+
* (if not strictly `Front`) — so a `Coplanar` vertex joins both, forming
|
|
51
|
+
* the shared boundary — and any edge that strictly crosses the plane
|
|
52
|
+
* contributes one new vertex, interpolated at the crossing point, to
|
|
53
|
+
* both chains. A resulting chain becomes an output polygon only if it
|
|
54
|
+
* has at least 3 vertices (matching `Polygon`'s minimum).
|
|
55
|
+
*
|
|
56
|
+
* Because interpolated points are affine combinations of two points on
|
|
57
|
+
* the source polygon's plane, they remain exactly on that same plane, so
|
|
58
|
+
* each output polygon's freshly-derived plane matches the source
|
|
59
|
+
* polygon's orientation.
|
|
60
|
+
*/
|
|
61
|
+
export declare function splitPolygon(plane: PlaneType, polygon: PolygonType): SplitResult;
|
|
62
|
+
//# sourceMappingURL=split-polygon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-polygon.d.ts","sourceRoot":"","sources":["../../src/csg/split-polygon.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIlE,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,6DAA6D;AAC7D,eAAO,MAAM,KAAK,IAAI,CAAC;AACvB,6DAA6D;AAC7D,eAAO,MAAM,IAAI,IAAI,CAAC;AACtB,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,IAAI,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACtB,OAAO,QAAQ,GACf,OAAO,KAAK,GACZ,OAAO,IAAI,GACX,OAAO,QAAQ,CAAC;AAEpB;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,aAAa,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/C,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9C,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IACvC,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC;AASD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,WAAW,CAyDhF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Vec3 as Vec3Type } from '../math/vec3';
|
|
2
|
+
/**
|
|
3
|
+
* An infinite plane, represented in Hessian normal form: a unit `normal`
|
|
4
|
+
* and the offset `w` such that a point `p` lies on the plane when
|
|
5
|
+
* `dot(normal, p) === w`.
|
|
6
|
+
*/
|
|
7
|
+
export interface Plane {
|
|
8
|
+
readonly normal: Vec3Type;
|
|
9
|
+
readonly w: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Builds the plane through `a`, `b`, `c`. The three points must be ordered
|
|
13
|
+
* counter-clockwise when viewed from the side the resulting normal points
|
|
14
|
+
* toward (right-hand rule) — this matches the outward-facing winding
|
|
15
|
+
* convention used by primitives and STL export.
|
|
16
|
+
*
|
|
17
|
+
* If `a`, `b`, `c` are collinear or coincident, the cross product degenerates
|
|
18
|
+
* to the zero vector; per `Vec3.normalize`, this yields a plane with a zero
|
|
19
|
+
* normal rather than throwing or producing `NaN`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function fromPoints(a: Vec3Type, b: Vec3Type, c: Vec3Type): Plane;
|
|
22
|
+
/**
|
|
23
|
+
* The signed distance from `point` to `plane`: positive on the side the
|
|
24
|
+
* normal points toward, negative on the opposite side, zero on the plane.
|
|
25
|
+
*/
|
|
26
|
+
export declare function signedDistance(plane: Plane, point: Vec3Type): number;
|
|
27
|
+
/** The plane with its normal (and therefore orientation) reversed. */
|
|
28
|
+
export declare function flip(plane: Plane): Plane;
|
|
29
|
+
/** Whether `a` and `b` represent the same plane within `tolerance`. */
|
|
30
|
+
export declare function equals(a: Plane, b: Plane, tolerance?: number): boolean;
|
|
31
|
+
//# sourceMappingURL=plane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plane.d.ts","sourceRoot":"","sources":["../../src/geometry/plane.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,KAAK,CAGvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,CAEpE;AAED,sEAAsE;AACtE,wBAAgB,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAExC;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,SAAU,GAAG,OAAO,CAKvE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Plane as PlaneType } from './plane';
|
|
2
|
+
import type { Vertex as VertexType } from './vertex';
|
|
3
|
+
/**
|
|
4
|
+
* A planar, convex polygon with an arbitrary number of vertices (3+),
|
|
5
|
+
* wound counter-clockwise when viewed from the side its plane's normal
|
|
6
|
+
* points toward. Polygons are kept as-is (not pre-triangulated) so they
|
|
7
|
+
* can be split cleanly by the future BSP-tree CSG engine; triangulation
|
|
8
|
+
* happens only at STL-export time via `triangulate`.
|
|
9
|
+
*/
|
|
10
|
+
export interface Polygon {
|
|
11
|
+
readonly vertices: readonly VertexType[];
|
|
12
|
+
readonly plane: PlaneType;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates a `Polygon` from `vertices`, deriving its plane from the first
|
|
16
|
+
* three. Throws if fewer than 3 vertices are given.
|
|
17
|
+
*/
|
|
18
|
+
export declare function polygon(vertices: readonly VertexType[]): Polygon;
|
|
19
|
+
/**
|
|
20
|
+
* The polygon with its winding order reversed and its plane/vertex
|
|
21
|
+
* normals flipped to match — turns an outward-facing polygon inside out.
|
|
22
|
+
*/
|
|
23
|
+
export declare function flip(p: Polygon): Polygon;
|
|
24
|
+
//# sourceMappingURL=polygon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon.d.ts","sourceRoot":"","sources":["../../src/geometry/polygon.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAQhE;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAKxC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Mat4 as Mat4Type } from '../math/mat4';
|
|
2
|
+
import type { Vec3 as Vec3Type } from '../math/vec3';
|
|
3
|
+
import type { Polygon as PolygonType } from './polygon';
|
|
4
|
+
/**
|
|
5
|
+
* A solid 3D shape: an immutable collection of polygons.
|
|
6
|
+
*
|
|
7
|
+
* `Solid` is the primary value type primitives (Stage 3) produce and
|
|
8
|
+
* transforms (Stage 4) operate on. Unlike the rest of the geometry kernel
|
|
9
|
+
* (which favors plain interfaces + free functions), `Solid` is a class so
|
|
10
|
+
* that transforms can be chained as instance methods, e.g.
|
|
11
|
+
* `cube(10).translate(vec3(5, 0, 0)).rotate(vec3(0, 0, Math.PI / 4))`.
|
|
12
|
+
* Every transform method returns a new `Solid`; none mutate `this`.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Solid {
|
|
15
|
+
readonly polygons: readonly PolygonType[];
|
|
16
|
+
constructor(polygons: readonly PolygonType[]);
|
|
17
|
+
/** Translates every point of the solid by `offset`. */
|
|
18
|
+
translate(offset: Vec3Type): Solid;
|
|
19
|
+
/**
|
|
20
|
+
* Rotates the solid by Euler angles (in radians), applied in OpenSCAD's
|
|
21
|
+
* order: first around X, then Y, then Z.
|
|
22
|
+
*/
|
|
23
|
+
rotate(radians: Vec3Type): Solid;
|
|
24
|
+
/** Rotates the solid by `radians` around `axis` (right-hand rule). */
|
|
25
|
+
rotateAxisAngle(axis: Vec3Type, radians: number): Solid;
|
|
26
|
+
/**
|
|
27
|
+
* Scales the solid. A single `number` scales all three axes uniformly;
|
|
28
|
+
* a `Vec3` scales each axis independently. A negative or zero factor on
|
|
29
|
+
* an odd number of axes flips handedness/degenerates the shape — winding
|
|
30
|
+
* is corrected automatically for the flip case, per `applyMatrix`.
|
|
31
|
+
*/
|
|
32
|
+
scale(factor: number | Vec3Type): Solid;
|
|
33
|
+
/**
|
|
34
|
+
* Reflects the solid across the plane through the origin with normal
|
|
35
|
+
* `normal` (need not be pre-normalized).
|
|
36
|
+
*/
|
|
37
|
+
mirror(normal: Vec3Type): Solid;
|
|
38
|
+
/** Applies an arbitrary 4x4 transform matrix to the solid. */
|
|
39
|
+
multmatrix(matrix: Mat4Type): Solid;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=solid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../../src/geometry/solid.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AA4CxD;;;;;;;;;GASG;AACH,qBAAa,KAAK;IAChB,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;gBAE9B,QAAQ,EAAE,SAAS,WAAW,EAAE;IAI5C,uDAAuD;IACvD,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK;IAIlC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,KAAK;IAIhC,sEAAsE;IACtE,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK;IAIvD;;;;;OAKG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK;IAMvC;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK;IAI/B,8DAA8D;IAC9D,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK;CAGpC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Polygon } from './polygon';
|
|
2
|
+
import type { Vertex } from './vertex';
|
|
3
|
+
/** Three vertices forming a triangle, wound the same way as their source. */
|
|
4
|
+
export type Triangle = readonly [Vertex, Vertex, Vertex];
|
|
5
|
+
/**
|
|
6
|
+
* Fan-triangulates a convex `Polygon` into `n - 2` triangles (for an
|
|
7
|
+
* `n`-vertex polygon), all sharing the first vertex. Winding is preserved:
|
|
8
|
+
* each triangle keeps the same vertex order as the source polygon, so its
|
|
9
|
+
* implied normal matches the polygon's plane.
|
|
10
|
+
*
|
|
11
|
+
* Triangulation happens only at STL-export time — `Polygon`/`Solid` keep
|
|
12
|
+
* their original (non-triangulated) vertices so the future CSG engine can
|
|
13
|
+
* split them cleanly.
|
|
14
|
+
*/
|
|
15
|
+
export declare function triangulate(polygon: Polygon): Triangle[];
|
|
16
|
+
//# sourceMappingURL=triangulate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triangulate.d.ts","sourceRoot":"","sources":["../../src/geometry/triangulate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE,CAQxD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Vec3 as Vec3Type } from '../math/vec3';
|
|
2
|
+
/** A polygon vertex: a position plus its shading normal. */
|
|
3
|
+
export interface Vertex {
|
|
4
|
+
readonly pos: Vec3Type;
|
|
5
|
+
readonly normal: Vec3Type;
|
|
6
|
+
}
|
|
7
|
+
/** Creates a `Vertex` from a position and normal. */
|
|
8
|
+
export declare function vertex(pos: Vec3Type, normal: Vec3Type): Vertex;
|
|
9
|
+
/**
|
|
10
|
+
* Linearly interpolates from `a` to `b` by `t` (0 = `a`, 1 = `b`),
|
|
11
|
+
* interpolating both position and normal. The interpolated normal is
|
|
12
|
+
* re-normalized, since a linear blend of two unit vectors is not itself
|
|
13
|
+
* unit length in general.
|
|
14
|
+
*/
|
|
15
|
+
export declare function lerp(a: Vertex, b: Vertex, t: number): Vertex;
|
|
16
|
+
/** The vertex with its normal reversed, position unchanged. */
|
|
17
|
+
export declare function flip(v: Vertex): Vertex;
|
|
18
|
+
/** Whether `a` and `b` are equal within `tolerance` on both fields. */
|
|
19
|
+
export declare function equals(a: Vertex, b: Vertex, tolerance?: number): boolean;
|
|
20
|
+
//# sourceMappingURL=vertex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vertex.d.ts","sourceRoot":"","sources":["../../src/geometry/vertex.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD,4DAA4D;AAC5D,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B;AAED,qDAAqD;AACrD,wBAAgB,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,MAAM,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,+DAA+D;AAC/D,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAKxE"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export { cube } from './primitives/cube';
|
|
2
|
+
export type { CubeOptions } from './primitives/cube';
|
|
3
|
+
export { sphere } from './primitives/sphere';
|
|
4
|
+
export type { SphereOptions } from './primitives/sphere';
|
|
5
|
+
export { cylinder } from './primitives/cylinder';
|
|
6
|
+
export type { CylinderOptions } from './primitives/cylinder';
|
|
7
|
+
export { polyhedron } from './primitives/polyhedron';
|
|
8
|
+
export { Solid } from './geometry/solid';
|
|
9
|
+
export * as Vertex from './geometry/vertex';
|
|
10
|
+
export * as Polygon from './geometry/polygon';
|
|
11
|
+
export * as Plane from './geometry/plane';
|
|
12
|
+
export { union, difference, intersect } from './csg/boolean';
|
|
13
|
+
export * as Vec3 from './math/vec3';
|
|
14
|
+
export * as Mat4 from './math/mat4';
|
|
15
|
+
export { toBinarySTL } from './io/stl-binary';
|
|
16
|
+
export { toASCIISTL } from './io/stl-ascii';
|
|
17
|
+
export { isManifold } from './io/manifold-check';
|
|
18
|
+
export { triangulateSolid } from './io/triangulate-solid';
|
|
19
|
+
export type { StlTriangle } from './io/triangulate-solid';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAKrD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAI1C,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI7D,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}
|