abstract-3d 0.6.1 → 0.6.2

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 (83) hide show
  1. package/lib/abstract-3d.d.ts +4 -0
  2. package/lib/abstract-3d.d.ts.map +1 -1
  3. package/lib/abstract-3d.js +10 -8
  4. package/lib/abstract-3d.js.map +1 -1
  5. package/lib/index.js +1 -0
  6. package/lib/index.js.map +1 -1
  7. package/lib/renderers/dxf/color.d.ts +3 -1
  8. package/lib/renderers/dxf/color.d.ts.map +1 -1
  9. package/lib/renderers/dxf/color.js +299 -1
  10. package/lib/renderers/dxf/color.js.map +1 -1
  11. package/lib/renderers/dxf/dxf-encoding.d.ts +12 -4
  12. package/lib/renderers/dxf/dxf-encoding.d.ts.map +1 -1
  13. package/lib/renderers/dxf/dxf-encoding.js +18323 -223
  14. package/lib/renderers/dxf/dxf-encoding.js.map +1 -1
  15. package/lib/renderers/dxf/dxf-geometries/dxf-box.d.ts +3 -1
  16. package/lib/renderers/dxf/dxf-geometries/dxf-box.d.ts.map +1 -1
  17. package/lib/renderers/dxf/dxf-geometries/dxf-box.js +7 -7
  18. package/lib/renderers/dxf/dxf-geometries/dxf-box.js.map +1 -1
  19. package/lib/renderers/dxf/dxf-geometries/dxf-cone.d.ts +3 -1
  20. package/lib/renderers/dxf/dxf-geometries/dxf-cone.d.ts.map +1 -1
  21. package/lib/renderers/dxf/dxf-geometries/dxf-cone.js +2 -2
  22. package/lib/renderers/dxf/dxf-geometries/dxf-cone.js.map +1 -1
  23. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.d.ts +3 -1
  24. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.d.ts.map +1 -1
  25. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.js +3 -3
  26. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.js.map +1 -1
  27. package/lib/renderers/dxf/dxf-geometries/dxf-plane.d.ts +3 -1
  28. package/lib/renderers/dxf/dxf-geometries/dxf-plane.d.ts.map +1 -1
  29. package/lib/renderers/dxf/dxf-geometries/dxf-plane.js +2 -2
  30. package/lib/renderers/dxf/dxf-geometries/dxf-plane.js.map +1 -1
  31. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.d.ts +3 -1
  32. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.d.ts.map +1 -1
  33. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.js +5 -5
  34. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.js.map +1 -1
  35. package/lib/renderers/dxf/dxf-geometries/dxf-shape.d.ts +3 -1
  36. package/lib/renderers/dxf/dxf-geometries/dxf-shape.d.ts.map +1 -1
  37. package/lib/renderers/dxf/dxf-geometries/dxf-shape.js +5 -5
  38. package/lib/renderers/dxf/dxf-geometries/dxf-shape.js.map +1 -1
  39. package/lib/renderers/dxf/dxf.d.ts.map +1 -1
  40. package/lib/renderers/dxf/dxf.js +22 -14
  41. package/lib/renderers/dxf/dxf.js.map +1 -1
  42. package/lib/renderers/react/react-camera.d.ts.map +1 -1
  43. package/lib/renderers/react/react-camera.js +24 -24
  44. package/lib/renderers/react/react-camera.js.map +1 -1
  45. package/lib/renderers/react/react-hotspot.js +1 -1
  46. package/lib/renderers/react/react-hotspot.js.map +1 -1
  47. package/lib/renderers/react/react-material.d.ts +2 -1
  48. package/lib/renderers/react/react-material.d.ts.map +1 -1
  49. package/lib/renderers/react/react-material.js +10 -3
  50. package/lib/renderers/react/react-material.js.map +1 -1
  51. package/lib/renderers/react/react-scene.d.ts.map +1 -1
  52. package/lib/renderers/react/react-scene.js +1 -2
  53. package/lib/renderers/react/react-scene.js.map +1 -1
  54. package/lib/renderers/step/step-encoding.d.ts.map +1 -1
  55. package/lib/renderers/step/step.d.ts.map +1 -1
  56. package/lib/renderers/stl/stl-encoding.d.ts.map +1 -1
  57. package/lib/renderers/stl/stl.d.ts.map +1 -1
  58. package/lib/renderers/svg/svg-encoding.d.ts.map +1 -1
  59. package/lib/renderers/svg/svg-encoding.js +13 -4
  60. package/lib/renderers/svg/svg-encoding.js.map +1 -1
  61. package/lib/renderers/svg/svg-geometries/shared.d.ts.map +1 -1
  62. package/lib/renderers/svg/svg.d.ts +1 -1
  63. package/lib/renderers/svg/svg.d.ts.map +1 -1
  64. package/lib/renderers/svg/svg.js +4 -2
  65. package/lib/renderers/svg/svg.js.map +1 -1
  66. package/package.json +6 -6
  67. package/src/abstract-3d.ts +18 -9
  68. package/src/index.ts +1 -0
  69. package/src/renderers/dxf/color.ts +304 -1
  70. package/src/renderers/dxf/dxf-encoding.ts +18331 -226
  71. package/src/renderers/dxf/dxf-geometries/dxf-box.ts +7 -7
  72. package/src/renderers/dxf/dxf-geometries/dxf-cone.ts +2 -2
  73. package/src/renderers/dxf/dxf-geometries/dxf-cylinder.ts +3 -3
  74. package/src/renderers/dxf/dxf-geometries/dxf-plane.ts +3 -2
  75. package/src/renderers/dxf/dxf-geometries/dxf-polygon.ts +5 -5
  76. package/src/renderers/dxf/dxf-geometries/dxf-shape.ts +5 -5
  77. package/src/renderers/dxf/dxf.ts +23 -15
  78. package/src/renderers/react/react-camera.tsx +28 -28
  79. package/src/renderers/react/react-hotspot.tsx +1 -1
  80. package/src/renderers/react/react-material.tsx +12 -2
  81. package/src/renderers/react/react-scene.tsx +1 -3
  82. package/src/renderers/svg/svg-encoding.ts +14 -12
  83. package/src/renderers/svg/svg.ts +7 -2
@@ -2,7 +2,7 @@ import { Box, Material, Vec3, vec3TransRot, vec3RotCombine, vec3Zero, vec3Scale,
2
2
  import { color } from "../color.js";
3
3
  import { dxf3DFACE } from "../dxf-encoding.js";
4
4
 
5
- export function dxfBox(b: Box, m: Material, parentPos: Vec3, parentRot: Vec3): string {
5
+ export function dxfBox(b: Box, m: Material, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
6
6
  const pos = vec3TransRot(b.pos, parentPos, parentRot);
7
7
  const rot = vec3RotCombine(parentRot, b.rot ?? vec3Zero);
8
8
  const half = vec3Scale(b.size, 0.5);
@@ -18,11 +18,11 @@ export function dxfBox(b: Box, m: Material, parentPos: Vec3, parentRot: Vec3): s
18
18
  const v8 = vec3tr3(-half.x, half.y, -half.z);
19
19
  const mat = color(m.normal);
20
20
  return (
21
- dxf3DFACE(v1, v2, v3, v4, mat) + // front
22
- dxf3DFACE(v5, v6, v7, v8, mat) + // Back
23
- dxf3DFACE(v5, v1, v4, v8, mat) + // Left
24
- dxf3DFACE(v6, v2, v3, v7, mat) + // Right
25
- dxf3DFACE(v8, v7, v3, v4, mat) + // Top
26
- dxf3DFACE(v5, v6, v2, v1, mat) // Bottom
21
+ dxf3DFACE(v1, v2, v3, v4, mat, handleRef) + // front
22
+ dxf3DFACE(v5, v6, v7, v8, mat, handleRef) + // Back
23
+ dxf3DFACE(v5, v1, v4, v8, mat, handleRef) + // Left
24
+ dxf3DFACE(v6, v2, v3, v7, mat, handleRef) + // Right
25
+ dxf3DFACE(v8, v7, v3, v4, mat, handleRef) + // Top
26
+ dxf3DFACE(v5, v6, v2, v1, mat, handleRef) // Bottom
27
27
  );
28
28
  }
@@ -2,7 +2,7 @@ import { Cone, Material, Vec3, vec3TransRot, vec3RotCombine, vec3Zero, vec3 } fr
2
2
  import { color } from "../color.js";
3
3
  import { dxf3DFACE } from "../dxf-encoding.js";
4
4
 
5
- export function dxfCone(c: Cone, m: Material, sides: number, parentPos: Vec3, parentRot: Vec3): string {
5
+ export function dxfCone(c: Cone, m: Material, sides: number, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
6
6
  let dxfString = "";
7
7
  const pos = vec3TransRot(c.pos, parentPos, parentRot);
8
8
  const rot = vec3RotCombine(parentRot, c.rot ?? vec3Zero);
@@ -22,7 +22,7 @@ export function dxfCone(c: Cone, m: Material, sides: number, parentPos: Vec3, pa
22
22
 
23
23
  if (i !== 0) {
24
24
  const prevBot = botVec3Array[i - 1]!;
25
- dxfString += dxf3DFACE(botPos, prevBot, currBot, currBot, mat) + dxf3DFACE(currBot, prevBot, topPos, topPos, mat);
25
+ dxfString += dxf3DFACE(botPos, prevBot, currBot, currBot, mat, handleRef) + dxf3DFACE(currBot, prevBot, topPos, topPos, mat, handleRef);
26
26
  }
27
27
  currentAngle += angleStep;
28
28
  }
@@ -2,7 +2,7 @@ import { Cylinder, Material, Vec3, vec3TransRot, vec3RotCombine, vec3Zero, vec3
2
2
  import { color } from "../color.js";
3
3
  import { dxf3DFACE } from "../dxf-encoding.js";
4
4
 
5
- export function dxfCylinder(c: Cylinder, m: Material, sides: number, parentPos: Vec3, parentRot: Vec3): string {
5
+ export function dxfCylinder(c: Cylinder, m: Material, sides: number, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
6
6
  let dxfString = "";
7
7
  const pos = vec3TransRot(c.pos, parentPos, parentRot);
8
8
  const rot = vec3RotCombine(parentRot, c.rot ?? vec3Zero);
@@ -30,9 +30,9 @@ export function dxfCylinder(c: Cylinder, m: Material, sides: number, parentPos:
30
30
  const prevTop = topVec3Array[i - 1]!;
31
31
  if (!c.open) {
32
32
  dxfString +=
33
- dxf3DFACE(botPos, prevBot, currBot, currBot, mat) + dxf3DFACE(topPos, prevTop, currTop, currTop, mat);
33
+ dxf3DFACE(botPos, prevBot, currBot, currBot, mat, handleRef) + dxf3DFACE(topPos, prevTop, currTop, currTop, mat, handleRef);
34
34
  }
35
- dxfString += dxf3DFACE(currBot, prevBot, prevTop, currTop, mat);
35
+ dxfString += dxf3DFACE(currBot, prevBot, prevTop, currTop, mat, handleRef);
36
36
  }
37
37
  currentAngle += angleStep;
38
38
  }
@@ -11,7 +11,7 @@ import {
11
11
  import { color } from "../color.js";
12
12
  import { dxf3DFACE } from "../dxf-encoding.js";
13
13
 
14
- export function dxfPlane(p: Plane, m: Material, parentPos: Vec3, parentRot: Vec3): string {
14
+ export function dxfPlane(p: Plane, m: Material, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
15
15
  const half = vec2Scale(p.size, 0.5);
16
16
  const pos = vec3TransRot(p.pos, parentPos, parentRot);
17
17
  const rot = vec3RotCombine(parentRot, p.rot ?? vec3Zero);
@@ -21,6 +21,7 @@ export function dxfPlane(p: Plane, m: Material, parentPos: Vec3, parentRot: Vec3
21
21
  vec3tr(half.x, -half.y),
22
22
  vec3tr(half.x, half.y),
23
23
  vec3tr(-half.x, half.y),
24
- color(m.normal)
24
+ color(m.normal),
25
+ handleRef
25
26
  );
26
27
  }
@@ -4,7 +4,7 @@ import { dxf3DFACE } from "../dxf-encoding.js";
4
4
 
5
5
  const chunkSize = 4;
6
6
 
7
- export function dxfPolygon(p: Polygon, m: Material, parentPos: Vec3, parentRot: Vec3): string {
7
+ export function dxfPolygon(p: Polygon, m: Material, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
8
8
  let polygonString = "";
9
9
  const pos = vec3TransRot(p.pos, parentPos, parentRot);
10
10
  const rot = vec3RotCombine(parentRot, p.rot ?? vec3Zero);
@@ -12,7 +12,7 @@ export function dxfPolygon(p: Polygon, m: Material, parentPos: Vec3, parentRot:
12
12
  let i = 0;
13
13
  if (points.length >= chunkSize) {
14
14
  for (i; i < points.length; i += chunkSize) {
15
- polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, color(m.normal));
15
+ polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, color(m.normal), handleRef);
16
16
  }
17
17
  }
18
18
 
@@ -20,13 +20,13 @@ export function dxfPolygon(p: Polygon, m: Material, parentPos: Vec3, parentRot:
20
20
  const lastArrayLength = points.length - i;
21
21
  switch (lastArrayLength) {
22
22
  case 1:
23
- polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, color(m.normal));
23
+ polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, color(m.normal), handleRef);
24
24
  break;
25
25
  case 2:
26
- polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, color(m.normal));
26
+ polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, color(m.normal), handleRef);
27
27
  break;
28
28
  case 3:
29
- polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, color(m.normal));
29
+ polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, color(m.normal), handleRef);
30
30
  break;
31
31
  default:
32
32
  break;
@@ -4,7 +4,7 @@ import { dxf3DFACE } from "../dxf-encoding.js";
4
4
 
5
5
  const chunkSize = 4;
6
6
 
7
- export function dxfPolygon(s: Shape, m: Material, parentPos: Vec3, parentRot: Vec3): string {
7
+ export function dxfPolygon(s: Shape, m: Material, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
8
8
  let polygonString = "";
9
9
  const pos = vec3TransRot(s.pos, parentPos, parentRot);
10
10
  const rot = vec3RotCombine(parentRot, s.rot ?? vec3Zero);
@@ -13,7 +13,7 @@ export function dxfPolygon(s: Shape, m: Material, parentPos: Vec3, parentRot: Ve
13
13
  let i = 0;
14
14
  if (points.length >= chunkSize) {
15
15
  for (i; i < points.length; i += chunkSize) {
16
- polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, mat);
16
+ polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 3]!, mat, handleRef);
17
17
  }
18
18
  }
19
19
 
@@ -21,13 +21,13 @@ export function dxfPolygon(s: Shape, m: Material, parentPos: Vec3, parentRot: Ve
21
21
  const lastArrayLength = points.length - i;
22
22
  switch (lastArrayLength) {
23
23
  case 1:
24
- polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, mat);
24
+ polygonString += dxf3DFACE(points[i - 2]!, points[i - 1]!, points[i]!, points[i]!, mat, handleRef);
25
25
  break;
26
26
  case 2:
27
- polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, mat);
27
+ polygonString += dxf3DFACE(points[i - 1]!, points[i]!, points[i + 1]!, points[i + 1]!, mat, handleRef);
28
28
  break;
29
29
  case 3:
30
- polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, mat);
30
+ polygonString += dxf3DFACE(points[i]!, points[i + 1]!, points[i + 2]!, points[i + 2]!, mat, handleRef);
31
31
  break;
32
32
  default:
33
33
  break;
@@ -11,28 +11,36 @@ export const toDxf = (scene: Scene, view: View): string => {
11
11
  const unitRot = vec3RotCombine(rotationForCameraPos(view), scene.rotation_deprecated ?? vec3Zero);
12
12
  const rotatedCenter = vec3Rot(scene.center_deprecated ?? vec3Zero, vec3Zero, scene.rotation_deprecated ?? vec3Zero);
13
13
  const [size, center] = sizeCenterForCameraPos(scene.size_deprecated, rotatedCenter, vec3Zero, 1);
14
- return dxfHeader(size, center) + scene.groups.reduce((a, c) => a + dxfGroup(c, center, unitRot), "") + dxfFooter;
14
+ const id = "D171D";
15
+ const handleRef = {handle: 0x1000}; //make sure we start with a value higher than any other handle id's used in the header
16
+ return dxfHeader(size, center, id) + scene.groups.reduce((a, c) => a + dxfGroup(c, center, unitRot, handleRef), "") + dxfFooter(id);
15
17
  };
16
18
 
17
- function dxfGroup(g: Group, parentPos: Vec3, parentRot: Vec3): string {
19
+ function dxfGroup(g: Group, parentPos: Vec3, parentRot: Vec3, handleRef: {handle: number}): string {
18
20
  const pos = vec3TransRot(g.pos, parentPos, parentRot);
19
21
  const rot = vec3RotCombine(parentRot, g.rot ?? vec3Zero);
20
22
  return (
21
23
  (g.meshes?.reduce((a, c) => {
22
24
  switch (c.geometry.type) {
23
- case "Plane":
24
- return a + dxfPlane(c.geometry, c.material, pos, rot);
25
- case "Box":
26
- return a + dxfBox(c.geometry, c.material, pos, rot);
27
- case "Cylinder":
28
- return a + dxfCylinder(c.geometry, c.material, 18, pos, rot);
29
- case "Cone":
30
- return a + dxfCone(c.geometry, c.material, 18, pos, rot);
31
- case "Polygon":
32
- return a + dxfPolygon(c.geometry, c.material, pos, rot);
33
- default:
25
+ case "Plane": {
26
+ return a + dxfPlane(c.geometry, c.material, pos, rot, handleRef);
27
+ }
28
+ case "Box": {
29
+ return a + dxfBox(c.geometry, c.material, pos, rot, handleRef);
30
+ }
31
+ case "Cylinder": {
32
+ return a + dxfCylinder(c.geometry, c.material, 18, pos, rot, handleRef);
33
+ }
34
+ case "Cone": {
35
+ return a + dxfCone(c.geometry, c.material, 18, pos, rot, handleRef);
36
+ }
37
+ case "Polygon": {
38
+ return a + dxfPolygon(c.geometry, c.material, pos, rot, handleRef);
39
+ }
40
+ default: {
34
41
  return a;
42
+ }
35
43
  }
36
- }, "") ?? "") + g.groups?.reduce((a, c) => a + dxfGroup(c, pos, rot), "")
44
+ }, "") ?? "") + g.groups?.reduce((a, c) => a + dxfGroup(c, pos, rot, handleRef), "")
37
45
  );
38
- }
46
+ }
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unused-vars */
3
- import React, { useEffect, useRef, useState } from "react";
3
+ import React, { useEffect, useLayoutEffect, useRef, useState } from "react";
4
4
  import {
5
5
  GizmoHelperProps,
6
6
  PerspectiveCamera,
@@ -11,7 +11,7 @@ import {
11
11
  GizmoViewcube,
12
12
  GizmoViewport,
13
13
  } from "@react-three/drei";
14
- import { ThreeEvent, useFrame, useThree } from "@react-three/fiber";
14
+ import { ThreeEvent, useThree } from "@react-three/fiber";
15
15
  import { exhaustiveCheck } from "ts-exhaustive-check";
16
16
  import { Vector3 } from "three/src/math/Vector3.js";
17
17
  import { View, Scene, Vec3, vec3 } from "../../abstract-3d.js";
@@ -31,20 +31,6 @@ export type ControlsHelper = (Viewcube | Viewport) & { readonly props: Pick<Gizm
31
31
  type Viewcube = { readonly type: "Viewcube"; readonly viewcubeProps: GenericProps };
32
32
  type Viewport = { readonly type: "Viewport"; readonly viewportProps: GizmoViewportProps };
33
33
 
34
- const ControlsWrapper = (
35
- props: OrbitControlsProps & { readonly setControls: (r: React.MutableRefObject<any>) => void }
36
- ): React.JSX.Element => {
37
- const ref = useRef<any>(undefined!);
38
-
39
- useEffect(() => {
40
- if (!ref.current) {
41
- return;
42
- }
43
- props.setControls(ref.current);
44
- }, [ref.current]);
45
- return <OrbitControls {...props} makeDefault ref={ref} />;
46
- };
47
-
48
34
  export function ReactCamera({
49
35
  useAnimations,
50
36
  camera,
@@ -65,7 +51,7 @@ export function ReactCamera({
65
51
  const orthographicRef = useRef<any | undefined>(undefined);
66
52
  const viewPortAspect = useThree(({ viewport: { aspect } }) => aspect);
67
53
 
68
- useEffect(() => {
54
+ useLayoutEffect(() => {
69
55
  const [posX, posY, posZ, size, sceneAspect] = (() => {
70
56
  switch (view) {
71
57
  case "front":
@@ -136,17 +122,17 @@ export function ReactCamera({
136
122
  // prevScene.current = scene;
137
123
  // }, [scene]);
138
124
 
139
- useFrame(() => {
140
- // if (useAnimations && camera && prevScene.current !== scene) {
141
- // const [, , z] = cameraDist(scene);
142
- // vector3.set(camera.position.x, camera.position.y, z);
143
- // camera.position.lerp(vector3, 0.12);
144
- // ref.current.enabled = false;
145
- // invalidate();
146
- // } else {
147
- // ref.current.enabled = true;
148
- // }
149
- });
125
+ // useFrame(() => {
126
+ // if (useAnimations && camera && prevScene.current !== scene) {
127
+ // const [, , z] = cameraDist(scene);
128
+ // vector3.set(camera.position.x, camera.position.y, z);
129
+ // camera.position.lerp(vector3, 0.12);
130
+ // ref.current.enabled = false;
131
+ // invalidate();
132
+ // } else {
133
+ // ref.current.enabled = true;
134
+ // }
135
+ // });
150
136
  return (
151
137
  <>
152
138
  <PerspectiveCamera
@@ -198,6 +184,20 @@ export function ReactCamera({
198
184
  );
199
185
  }
200
186
 
187
+ const ControlsWrapper = (
188
+ props: OrbitControlsProps & { readonly setControls: (r: React.MutableRefObject<any>) => void }
189
+ ): React.JSX.Element => {
190
+ const ref = useRef<any>(undefined!);
191
+
192
+ useLayoutEffect(() => {
193
+ if (!ref.current) {
194
+ return;
195
+ }
196
+ props.setControls(ref.current);
197
+ }, [ref.current]);
198
+ return <OrbitControls {...props} makeDefault ref={ref} />;
199
+ };
200
+
201
201
  type GizmoViewportProps = React.JSX.IntrinsicElements["group"] & {
202
202
  readonly axisColors?: readonly [string, string, string];
203
203
  readonly axisScale?: readonly [number, number, number];
@@ -100,7 +100,7 @@ export function ReactHotSpot({
100
100
  })}
101
101
  >
102
102
  <ReactMesh mesh={h.mesh}>
103
- <ReactMaterial id={h.id} isText={false} material={h.mesh.material} hoveredId={hoveredId} />
103
+ <ReactMaterial id={h.id} isText={false} isHotSpot={true} material={h.mesh.material} hoveredId={hoveredId} />
104
104
  </ReactMesh>
105
105
  </group>
106
106
  {hotSpotTexts && text && (
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { useEffect } from "react";
2
2
  import { suspend } from "suspend-react";
3
3
  import { Color, DoubleSide, MaterialParameters, SRGBColorSpace, Texture, TextureLoader } from "three";
4
4
  import { Material } from "../../abstract-3d.js";
@@ -18,6 +18,7 @@ export function ReactMaterial({
18
18
  materialStateImages,
19
19
  state,
20
20
  isText,
21
+ isHotSpot,
21
22
  }: {
22
23
  readonly material: Material;
23
24
  readonly id?: string;
@@ -27,6 +28,7 @@ export function ReactMaterial({
27
28
  readonly materialStateImages?: Record<string, string>;
28
29
  readonly state?: MaterialState | undefined;
29
30
  readonly isText: boolean;
31
+ readonly isHotSpot?: boolean;
30
32
  }): React.JSX.Element {
31
33
  const mat =
32
34
  !state || material.image?.type === "UrlImage"
@@ -70,7 +72,7 @@ export function ReactMaterial({
70
72
  roughness={mat.roughness}
71
73
  metalness={mat.metalness}
72
74
  side={DoubleSide}
73
- {...(opacity < 1 || disabled
75
+ {...((opacity < 1 || disabled) && !isHotSpot
74
76
  ? { transparent: true, opacity: disabled ? opacity * decreasedOpacity : opacity }
75
77
  : materialDefaults)}
76
78
  />
@@ -101,6 +103,14 @@ function TextureMaterial({
101
103
  [url]
102
104
  ) as Texture | null;
103
105
 
106
+ useEffect(() => {
107
+ return () => {
108
+ if (texture) {
109
+ texture.dispose();
110
+ }
111
+ };
112
+ }, [texture]);
113
+
104
114
  return (
105
115
  <meshBasicMaterial
106
116
  color={color}
@@ -5,8 +5,6 @@ import { ReactDimensions } from "./react-dimension.js";
5
5
  import { ReactGroup } from "./react-group.js";
6
6
  import { MaterialState } from "./react-material.js";
7
7
 
8
- // dummy 2
9
-
10
8
  export function ReactScene({
11
9
  scene,
12
10
  selectedId,
@@ -66,7 +64,7 @@ export function ReactScene({
66
64
  const id = createGroupId ? createGroupId(g) : "";
67
65
  return (
68
66
  <ReactGroup
69
- key={createGroupKey ? createGroupKey(g, i, g.data, id) : i}
67
+ key={createGroupKey ? createGroupKey(g, 0, g.data, id) : i}
70
68
  g={g}
71
69
  selectedId={selectedId}
72
70
  hotSpotsActive={activeHotSpots !== undefined}
@@ -1,9 +1,10 @@
1
- import { Vec2, vec2Add, vec2Scale } from "../../abstract-3d.js";
1
+ import { vec2, Vec2, vec2Add, vec2Scale } from "../../abstract-3d.js";
2
2
 
3
- export const svg = (width: number, height: number, children: string): string =>
4
- `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width.toFixed(0)} ${height.toFixed(
3
+ export const svg = (width: number, height: number, children: string): string => {
4
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width.toFixed(0)} ${height.toFixed(
5
5
  0
6
6
  )}" width="${width.toFixed(0)}px" height="${height.toFixed(0)}px">${children} </svg>`;
7
+ };
7
8
 
8
9
  export const svgLine = (p1: Vec2, p2: Vec2, stroke: string, strokeWidth: number): string =>
9
10
  `<line x1="${p1.x.toFixed(0)}" y1="${p1.y.toFixed(0)}" x2="${p2.x.toFixed(0)}" y2="${p2.y.toFixed(
@@ -30,16 +31,17 @@ export type EmbededImage =
30
31
  | { readonly type: "svg"; readonly svg: string };
31
32
 
32
33
  export const svgImage = (p: Vec2, size: Vec2, rot: number, data: EmbededImage): string => {
34
+ const rad = rot * (Math.PI / 180);
35
+ const cos = Math.abs(Math.cos(rad));
36
+ const sin = Math.abs(Math.sin(rad));
37
+ const newSize = vec2(size.x * cos + size.y * sin, size.x * sin + size.y * cos);
33
38
  const half = vec2Scale(size, 0.5);
39
+ const originalCenter = vec2(size.x / 2, size.y / 2);
40
+ const rotatedCenter = vec2(newSize.x / 2, newSize.y / 2);
41
+ const rotatatedTranslationDelta = vec2(originalCenter.x - rotatedCenter.x, originalCenter.y - rotatedCenter.y);
34
42
  return data.type === "url"
35
- ? `<image x="${p.x.toFixed(0)}" y="${p.y.toFixed(0)}" transform="${rotate(rot)}" ${transformOrigin(
36
- p,
37
- half
38
- )} width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" href="${data.url}" />`
39
- : `<svg width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" transform="${translate(
40
- vec2Add(p, half)
41
- )} ${rotate(rot)} ${translate(vec2Scale(half, -1))}">${data.svg}</svg>
42
-
43
+ ? `<image x="${p.x.toFixed(0)}" y="${p.y.toFixed(0)}" transform="${rotate(rot)}" ${transformOrigin(p, half)} width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" href="${data.url}" />`
44
+ : `<svg width="${newSize.x.toFixed(0)}" height="${newSize.y.toFixed(0)}" transform="${translate(p)} ${rotateAtPos(rot, half)} ${translate(rotatatedTranslationDelta)}">${data.svg}</svg>
43
45
  `;
44
46
  };
45
47
 
@@ -47,5 +49,5 @@ const transformOrigin = (p: Vec2, half: Vec2): string =>
47
49
  `transform-origin="${(p.x + half.x).toFixed(0)}px ${(p.y + half.y).toFixed(0)}px"`;
48
50
 
49
51
  const rotate = (rot: number): string => `rotate(${rot.toFixed(0)})`;
50
-
52
+ const rotateAtPos = (rot: number, p: Vec2): string => `rotate(${rot.toFixed(0)}, ${p.x.toFixed(0)}, ${p.y.toFixed(0)})`;
51
53
  const translate = (p: Vec2): string => `translate(${p.x.toFixed(0)}, ${p.y.toFixed(0)})`;
@@ -26,6 +26,8 @@ import { cone } from "./svg-geometries/svg-cone.js";
26
26
  import { rotationForCameraPos, sizeCenterForCameraPos } from "../shared.js";
27
27
  import { EmbededImage, svg } from "./svg-encoding.js";
28
28
 
29
+ // dummy
30
+
29
31
  export function toSvg(
30
32
  scene: Scene,
31
33
  view: View,
@@ -35,7 +37,8 @@ export function toSvg(
35
37
  grayScale?: boolean,
36
38
  onlyStrokeFill: string = "rgba(255,255,255,0)",
37
39
  font: string = "",
38
- buffers?: Record<string, string>
40
+ buffers?: Record<string, string>,
41
+ rotation?: number
39
42
  ): { readonly image: string; readonly width: number; readonly height: number } {
40
43
  const factor = scale
41
44
  ? scale.size /
@@ -47,7 +50,9 @@ export function toSvg(
47
50
  ? scene.size_deprecated.z
48
51
  : scene.size_deprecated.y)
49
52
  : 1;
50
- const unitRot = vec3RotCombine(rotationForCameraPos(view), scene.rotation_deprecated ?? vec3Zero);
53
+ const baseRot = vec3RotCombine(rotationForCameraPos(view), scene.rotation_deprecated ?? vec3Zero);
54
+ const unitRot = rotation ? vec3RotCombine(vec3(0, 0, (rotation * Math.PI) / 180), baseRot) : baseRot;
55
+
51
56
  const unitPos = vec3Rot(scene.center_deprecated ?? vec3Zero, vec3Zero, scene.rotation_deprecated ?? vec3Zero);
52
57
  const [size, center] = sizeCenterForCameraPos(scene.size_deprecated, unitPos, unitRot, factor);
53
58
  const unitHalfSize = vec3Scale(size, 0.5);