abstract-3d 2.9.2 → 2.10.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/lib/abstract-3d.d.ts +4 -1
- package/lib/abstract-3d.d.ts.map +1 -1
- package/lib/abstract-3d.js +4 -2
- package/lib/abstract-3d.js.map +1 -1
- package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.d.ts.map +1 -1
- package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.js +15 -21
- package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.js.map +1 -1
- package/lib/renderers/react/react-mesh.d.ts.map +1 -1
- package/lib/renderers/react/react-mesh.js +51 -21
- package/lib/renderers/react/react-mesh.js.map +1 -1
- package/lib/renderers/step/step-geometries/step-cone.d.ts.map +1 -1
- package/lib/renderers/step/step-geometries/step-cone.js +1 -9
- package/lib/renderers/step/step-geometries/step-cone.js.map +1 -1
- package/lib/renderers/step/step-geometries/step-cylinder.d.ts +1 -1
- package/lib/renderers/step/step-geometries/step-cylinder.d.ts.map +1 -1
- package/lib/renderers/step/step-geometries/step-cylinder.js +2 -2
- package/lib/renderers/step/step-geometries/step-cylinder.js.map +1 -1
- package/lib/renderers/stl/stl-geometries/stl-cylinder.d.ts +1 -1
- package/lib/renderers/stl/stl-geometries/stl-cylinder.d.ts.map +1 -1
- package/lib/renderers/stl/stl-geometries/stl-cylinder.js +9 -17
- package/lib/renderers/stl/stl-geometries/stl-cylinder.js.map +1 -1
- package/lib/renderers/svg/svg-geometries/svg-cylinder.d.ts.map +1 -1
- package/lib/renderers/svg/svg-geometries/svg-cylinder.js +11 -9
- package/lib/renderers/svg/svg-geometries/svg-cylinder.js.map +1 -1
- package/package.json +4 -4
- package/src/abstract-3d.ts +8 -2
- package/src/renderers/dxf/dxf-geometries/dxf-cylinder.ts +15 -22
- package/src/renderers/react/react-mesh.tsx +76 -64
- package/src/renderers/step/step-geometries/step-cone.ts +2 -10
- package/src/renderers/step/step-geometries/step-cylinder.ts +2 -2
- package/src/renderers/stl/stl-geometries/stl-cylinder.ts +9 -17
- package/src/renderers/svg/svg-geometries/svg-cylinder.ts +11 -9
|
@@ -34,8 +34,9 @@ import type {
|
|
|
34
34
|
Tube as A3dTube,
|
|
35
35
|
CircleCurve as A3dCircleCurve,
|
|
36
36
|
Hole,
|
|
37
|
+
Vec3,
|
|
37
38
|
} from "../../abstract-3d.js";
|
|
38
|
-
import { vec2Scale, vec2Sub, vec2Add, isZero,
|
|
39
|
+
import { vec2Scale, vec2Sub, vec2Add, isZero, vec3, equals } from "../../abstract-3d.js";
|
|
39
40
|
import { planeGeometry } from "./react-image-material.js";
|
|
40
41
|
|
|
41
42
|
extend({
|
|
@@ -57,8 +58,7 @@ extend({
|
|
|
57
58
|
|
|
58
59
|
const CYLINDER_SEGMENTS = 40;
|
|
59
60
|
const boxGeometry = new BoxGeometry();
|
|
60
|
-
const
|
|
61
|
-
const cylinderGeometryOpen = new CylinderGeometry(1, 1, 1, CYLINDER_SEGMENTS, 1, true);
|
|
61
|
+
const cylinderGeometries = new Map<string, BufferGeometry>();
|
|
62
62
|
const coneGeometry = new ConeGeometry(1, 1, 16, 1);
|
|
63
63
|
const sphereGeometry = new SphereGeometry(1, 12, 12);
|
|
64
64
|
export const euler = new Euler();
|
|
@@ -114,70 +114,36 @@ export function ReactMesh({ mesh, children }: { readonly mesh: Mesh; readonly ch
|
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
116
|
case "Cylinder": {
|
|
117
|
-
const { pos, radius, rot, length, holes, open, angleStart, angleLength } = mesh.geometry;
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
if (isWhole) {
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
117
|
+
const { pos, radius, radiusEnd = radius, rot, length, holes, open, angleStart = 0, angleLength = Math.PI * 2 } = mesh.geometry;
|
|
118
|
+
const isWhole = isZero(Math.PI * 2 - angleLength);
|
|
119
|
+
// Holes are extruded along the length, which can't taper
|
|
120
|
+
const filteredHoles = radiusEnd === radius ? holes?.filter((h) => !holeIsZero(h)) : undefined;
|
|
121
|
+
if (isWhole && filteredHoles && filteredHoles.length > 0) {
|
|
122
|
+
return <ExcrudeCylinder cyl={mesh.geometry}>{children}</ExcrudeCylinder>;
|
|
123
|
+
}
|
|
124
|
+
// Unit geometry scaled by the largest radius, so only the radius ratio needs its own geometry
|
|
125
|
+
const maxRadius = Math.max(radius, radiusEnd);
|
|
126
|
+
const unitTop = radiusEnd / (maxRadius || 1);
|
|
127
|
+
const unitBottom = radius / (maxRadius || 1);
|
|
128
|
+
const transform = {
|
|
129
|
+
scale: [maxRadius, length, maxRadius],
|
|
130
|
+
position: [pos.x, pos.y, pos.z],
|
|
131
|
+
rotation: [rot?.x ?? 0, rot?.y ?? 0, rot?.z ?? 0],
|
|
132
|
+
} as const;
|
|
133
|
+
return isWhole ? (
|
|
134
|
+
<mesh geometry={getCylinderGeometry(unitTop, unitBottom, open ?? false, 0, Math.PI * 2)} {...transform} castShadow receiveShadow>
|
|
135
|
+
{children}
|
|
136
|
+
</mesh>
|
|
137
|
+
) : (
|
|
138
|
+
<mesh {...transform}>
|
|
139
|
+
<mesh geometry={getCylinderGeometry(unitTop, unitBottom, false, angleStart, angleLength)} castShadow receiveShadow>
|
|
131
140
|
{children}
|
|
132
141
|
</mesh>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
);
|
|
136
|
-
} else {
|
|
137
|
-
const angledCylinder = new CylinderGeometry(1, 1, 1, CYLINDER_SEGMENTS, 1, false, angleStart, angleLength);
|
|
138
|
-
const angleEnd = angleStart + angleLength;
|
|
139
|
-
const halfRadius = radius / 2;
|
|
140
|
-
const aStart = angleStart - Math.PI / 2;
|
|
141
|
-
const aEnd = angleEnd - Math.PI / 2;
|
|
142
|
-
const plane1Rot = vec3RotCombine(rot ?? vec3Zero, vec3(0, aStart, 0));
|
|
143
|
-
const plane2Rot = vec3RotCombine(rot ?? vec3Zero, vec3(0, aEnd, 0));
|
|
144
|
-
const plane1Pos = vec3Add(vec3Rot(vec3Scale(vec3(Math.cos(aStart), 0, -Math.sin(aStart)), halfRadius), vec3Zero, rot ?? vec3Zero), pos);
|
|
145
|
-
const plane2Pos = vec3Add(vec3Rot(vec3Scale(vec3(Math.cos(aEnd), 0, -Math.sin(aEnd)), halfRadius), vec3Zero, rot ?? vec3Zero), pos);
|
|
146
|
-
return (
|
|
147
|
-
<mesh>
|
|
148
|
-
<mesh
|
|
149
|
-
geometry={angledCylinder}
|
|
150
|
-
scale={[radius, length, radius]}
|
|
151
|
-
position={[pos.x, pos.y, pos.z]}
|
|
152
|
-
rotation={[rot?.x ?? 0, rot?.y ?? 0, rot?.z ?? 0]}
|
|
153
|
-
castShadow
|
|
154
|
-
receiveShadow
|
|
155
|
-
>
|
|
156
|
-
{children}
|
|
157
|
-
</mesh>
|
|
158
|
-
<mesh
|
|
159
|
-
geometry={planeGeometry}
|
|
160
|
-
scale={[radius, length, 1]}
|
|
161
|
-
position={[plane1Pos.x, plane1Pos.y, plane1Pos.z]}
|
|
162
|
-
rotation={[plane1Rot.x, plane1Rot.y, plane1Rot.z]}
|
|
163
|
-
castShadow
|
|
164
|
-
receiveShadow
|
|
165
|
-
>
|
|
166
|
-
{children}
|
|
167
|
-
</mesh>
|
|
168
|
-
<mesh
|
|
169
|
-
geometry={planeGeometry}
|
|
170
|
-
scale={[radius, length, 1]}
|
|
171
|
-
position={[plane2Pos.x, plane2Pos.y, plane2Pos.z]}
|
|
172
|
-
rotation={[plane2Rot.x, plane2Rot.y, plane2Rot.z]}
|
|
173
|
-
castShadow
|
|
174
|
-
receiveShadow
|
|
175
|
-
>
|
|
176
|
-
{children}
|
|
177
|
-
</mesh>
|
|
142
|
+
<mesh geometry={getCylinderCutGeometry(unitTop, unitBottom, angleStart, angleLength)} castShadow receiveShadow>
|
|
143
|
+
{children}
|
|
178
144
|
</mesh>
|
|
179
|
-
|
|
180
|
-
|
|
145
|
+
</mesh>
|
|
146
|
+
);
|
|
181
147
|
}
|
|
182
148
|
case "Image":
|
|
183
149
|
return (
|
|
@@ -347,6 +313,52 @@ function ExcrudeShape({ s, children }: { readonly s: Shape_1; readonly children?
|
|
|
347
313
|
);
|
|
348
314
|
}
|
|
349
315
|
|
|
316
|
+
function cachedCylinderGeometry(key: string, create: () => BufferGeometry): BufferGeometry {
|
|
317
|
+
const cached = cylinderGeometries.get(key);
|
|
318
|
+
if (cached) {
|
|
319
|
+
return cached;
|
|
320
|
+
}
|
|
321
|
+
const geometry = create();
|
|
322
|
+
cylinderGeometries.set(key, geometry);
|
|
323
|
+
return geometry;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function getCylinderGeometry(top: number, bottom: number, open: boolean, angleStart: number, angleLength: number): BufferGeometry {
|
|
327
|
+
return cachedCylinderGeometry(
|
|
328
|
+
`cyl_${top}_${bottom}_${open}_${angleStart}_${angleLength}`,
|
|
329
|
+
() => new CylinderGeometry(top, bottom, 1, CYLINDER_SEGMENTS, 1, open, angleStart, angleLength)
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const rimPoint = (radius: number, y: number, angle: number): Vec3 => vec3(radius * Math.sin(angle), y, radius * Math.cos(angle));
|
|
334
|
+
|
|
335
|
+
/** The two walls closing an angled cylinder, from the axis out to the rim at angleStart and angleEnd */
|
|
336
|
+
function getCylinderCutGeometry(top: number, bottom: number, angleStart: number, angleLength: number): BufferGeometry {
|
|
337
|
+
return cachedCylinderGeometry(`cut_${top}_${bottom}_${angleStart}_${angleLength}`, () => {
|
|
338
|
+
const [c0, c1] = [vec3(0, -0.5, 0), vec3(0, 0.5, 0)];
|
|
339
|
+
const angleEnd = angleStart + angleLength;
|
|
340
|
+
const [b0, t0] = [rimPoint(bottom, -0.5, angleStart), rimPoint(top, 0.5, angleStart)];
|
|
341
|
+
const [b1, t1] = [rimPoint(bottom, -0.5, angleEnd), rimPoint(top, 0.5, angleEnd)];
|
|
342
|
+
// Unshared vertices so each wall gets its own flat normal, wound opposite so both face outwards
|
|
343
|
+
const triangles = [
|
|
344
|
+
[c0, b0, t0],
|
|
345
|
+
[c0, t0, c1],
|
|
346
|
+
[c0, c1, t1],
|
|
347
|
+
[c0, t1, b1],
|
|
348
|
+
];
|
|
349
|
+
const g = new BufferGeometry();
|
|
350
|
+
g.setAttribute(
|
|
351
|
+
"position",
|
|
352
|
+
new Float32BufferAttribute(
|
|
353
|
+
triangles.flat().flatMap((v) => [v.x, v.y, v.z]),
|
|
354
|
+
3
|
|
355
|
+
)
|
|
356
|
+
);
|
|
357
|
+
g.computeVertexNormals();
|
|
358
|
+
return g;
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
350
362
|
function ExcrudeCylinder({ cyl, children }: { readonly cyl: Cylinder; readonly children?: React.JSX.Element }): React.JSX.Element {
|
|
351
363
|
const excrudeGeometry = React.useMemo(() => {
|
|
352
364
|
const shape = new Shape();
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import type { Material, Vec3, Cone
|
|
1
|
+
import type { Material, Vec3, Cone } from "../../../abstract-3d.js";
|
|
2
2
|
import type { MutableStep } from "../step-encoding.js";
|
|
3
3
|
import { stepCylinder } from "./step-cylinder.js";
|
|
4
4
|
|
|
5
5
|
export function stepCone(c: Cone, mat: Material, parentPos: Vec3, parentRot: Vec3, m: MutableStep): void {
|
|
6
|
-
|
|
7
|
-
const cylinder: Cylinder = {
|
|
8
|
-
type: "Cylinder",
|
|
9
|
-
pos: c.pos,
|
|
10
|
-
rot: c.rot,
|
|
11
|
-
length: c.length,
|
|
12
|
-
radius: c.radius,
|
|
13
|
-
};
|
|
14
|
-
stepCylinder(cylinder, mat, parentPos, parentRot, m, 0.0);
|
|
6
|
+
stepCylinder({ type: "Cylinder", pos: c.pos, rot: c.rot, length: c.length, radius: c.radius, radiusEnd: 0 }, mat, parentPos, parentRot, m);
|
|
15
7
|
}
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
const SMALLEST_RADIUS = 1e-4;
|
|
46
46
|
const GEOMETRY_EPSILON = 1e-12;
|
|
47
47
|
|
|
48
|
-
export function stepCylinder(c: Cylinder, mat: Material, parentPos: Vec3, parentRot: Vec3, m: MutableStep
|
|
48
|
+
export function stepCylinder(c: Cylinder, mat: Material, parentPos: Vec3, parentRot: Vec3, m: MutableStep): void {
|
|
49
49
|
const h = c.length;
|
|
50
50
|
|
|
51
51
|
if (h <= GEOMETRY_EPSILON) {
|
|
@@ -53,7 +53,7 @@ export function stepCylinder(c: Cylinder, mat: Material, parentPos: Vec3, parent
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
const bottomRadius = Math.max(c.radius, SMALLEST_RADIUS);
|
|
56
|
-
const requestedTopRadius = Math.max(
|
|
56
|
+
const requestedTopRadius = Math.max(c.radiusEnd ?? c.radius, SMALLEST_RADIUS);
|
|
57
57
|
|
|
58
58
|
const radiusTolerance = GEOMETRY_EPSILON * Math.max(1, bottomRadius, requestedTopRadius);
|
|
59
59
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Cylinder, Material, Vec3 } from "../../../abstract-3d.js";
|
|
2
|
-
import { vec3TransRot, vec3RotCombine, vec3Zero, vec3, equals
|
|
2
|
+
import { vec3TransRot, vec3RotCombine, vec3Zero, vec3, equals } from "../../../abstract-3d.js";
|
|
3
3
|
import { stlPlaneOfVertices } from "../stl-encoding.js";
|
|
4
|
-
import { stlPlane } from "./stl-plane.js";
|
|
5
4
|
|
|
6
|
-
export function stlCylinder(c: Cylinder,
|
|
5
|
+
export function stlCylinder(c: Cylinder, _m: Material, sides: number, parentPos: Vec3, parentRot: Vec3): string {
|
|
7
6
|
let stlString = "";
|
|
8
7
|
const pos = vec3TransRot(c.pos, parentPos, parentRot);
|
|
9
8
|
const rot = vec3RotCombine(parentRot, c.rot ?? vec3Zero);
|
|
@@ -16,6 +15,7 @@ export function stlCylinder(c: Cylinder, m: Material, sides: number, parentPos:
|
|
|
16
15
|
let currentAngle = angleStart;
|
|
17
16
|
|
|
18
17
|
const half = c.length / 2;
|
|
18
|
+
const radiusEnd = c.radiusEnd ?? c.radius;
|
|
19
19
|
const topPos = vec3tr(0, half, 0);
|
|
20
20
|
const botPos = vec3tr(0, -half, 0);
|
|
21
21
|
|
|
@@ -23,10 +23,10 @@ export function stlCylinder(c: Cylinder, m: Material, sides: number, parentPos:
|
|
|
23
23
|
const topVec3Array = Array<Vec3>();
|
|
24
24
|
|
|
25
25
|
for (let i = 0; i <= sides; i++) {
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const currBot = vec3tr(
|
|
29
|
-
const currTop = vec3tr(
|
|
26
|
+
const sin = Math.sin(currentAngle);
|
|
27
|
+
const cos = Math.cos(currentAngle);
|
|
28
|
+
const currBot = vec3tr(sin * c.radius, -half, cos * c.radius);
|
|
29
|
+
const currTop = vec3tr(sin * radiusEnd, half, cos * radiusEnd);
|
|
30
30
|
botVec3Array.push(currBot);
|
|
31
31
|
topVec3Array.push(currTop);
|
|
32
32
|
if (i !== 0) {
|
|
@@ -41,16 +41,8 @@ export function stlCylinder(c: Cylinder, m: Material, sides: number, parentPos:
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
if (!equals(angleStart, angleEnd - Math.PI * 2) && angleLength > 0.0) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const halfRadius = c.radius / 2;
|
|
47
|
-
const plane1Rot = vec3(0, aStart, 0);
|
|
48
|
-
const plane2Rot = vec3(0, aEnd, 0);
|
|
49
|
-
const plane1Pos = vec3Scale(vec3(Math.cos(aStart), 0, -Math.sin(aStart)), halfRadius);
|
|
50
|
-
const plane2Pos = vec3Scale(vec3(Math.cos(aEnd), 0, -Math.sin(aEnd)), halfRadius);
|
|
51
|
-
const planeSize = vec3(c.radius, c.length, 1);
|
|
52
|
-
stlString += stlPlane({ type: "Plane", pos: plane1Pos, size: planeSize, rot: plane1Rot }, m, pos, rot);
|
|
53
|
-
stlString += stlPlane({ type: "Plane", pos: plane2Pos, size: planeSize, rot: plane2Rot }, m, pos, rot);
|
|
44
|
+
stlString += stlPlaneOfVertices(botPos, botVec3Array[0]!, topVec3Array[0]!, topPos);
|
|
45
|
+
stlString += stlPlaneOfVertices(botPos, topPos, topVec3Array[sides]!, botVec3Array[sides]!);
|
|
54
46
|
}
|
|
55
47
|
|
|
56
48
|
return stlString;
|
|
@@ -13,7 +13,8 @@ export function cylinder(
|
|
|
13
13
|
parentPos: Vec3,
|
|
14
14
|
parentRot: Vec3
|
|
15
15
|
): ReadonlyArray<zOrderElement> {
|
|
16
|
-
const half =
|
|
16
|
+
const half = c.length / 2;
|
|
17
|
+
const radiusEnd = c.radiusEnd ?? c.radius;
|
|
17
18
|
const pos = vec3TransRot(c.pos, parentPos, parentRot);
|
|
18
19
|
const rot = vec3RotCombine(parentRot, c.rot ?? vec3Zero);
|
|
19
20
|
const vec3tr = (p: Vec3): Vec3 => vec3TransRot(p, pos, rot);
|
|
@@ -32,10 +33,10 @@ export function cylinder(
|
|
|
32
33
|
const botVec3Array = Array<Vec3>();
|
|
33
34
|
const topVec3Array = Array<Vec3>();
|
|
34
35
|
for (let i = 0; i <= sides; i++) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const currBot = vec3tr(vec3(
|
|
38
|
-
const currTop = vec3tr(vec3(
|
|
36
|
+
const sin = Math.sin(currentAngle);
|
|
37
|
+
const cos = Math.cos(currentAngle);
|
|
38
|
+
const currBot = vec3tr(vec3(sin * c.radius, -half, cos * c.radius));
|
|
39
|
+
const currTop = vec3tr(vec3(sin * radiusEnd, half, cos * radiusEnd));
|
|
39
40
|
botVec3Array.push(currBot);
|
|
40
41
|
topVec3Array.push(currTop);
|
|
41
42
|
if (i !== 0) {
|
|
@@ -49,11 +50,12 @@ export function cylinder(
|
|
|
49
50
|
}
|
|
50
51
|
if (!c.open) {
|
|
51
52
|
// Add circle if direcly facing camera
|
|
52
|
-
const circleTop = vec3tr(vec3(0, half
|
|
53
|
-
const circleBottom = vec3tr(vec3(0, -half
|
|
53
|
+
const circleTop = vec3tr(vec3(0, half, 0));
|
|
54
|
+
const circleBottom = vec3tr(vec3(0, -half, 0));
|
|
54
55
|
if (equals(circleTop.x, circleBottom.x, 0.1) && equals(circleTop.y, circleBottom.y, 0.1)) {
|
|
55
|
-
const circlePos = circleTop.z > circleBottom.z ? circleTop : circleBottom;
|
|
56
|
-
|
|
56
|
+
const [circlePos, circleRadius] = circleTop.z > circleBottom.z ? [circleTop, radiusEnd] : [circleBottom, c.radius];
|
|
57
|
+
const holes = radiusEnd === c.radius ? c.holes : undefined;
|
|
58
|
+
zOrderComponents.push(zElem(svgCircle(circleRadius, rot, point(circlePos.x, circlePos.y), fill, opacity, stroke, stBW, holes), circlePos.z));
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
return zOrderComponents;
|