abstract-3d 0.1.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 (219) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +7 -0
  4. package/lib/abstract-3d.d.ts +317 -0
  5. package/lib/abstract-3d.d.ts.map +1 -0
  6. package/lib/abstract-3d.js +333 -0
  7. package/lib/abstract-3d.js.map +1 -0
  8. package/lib/index.d.ts +3 -0
  9. package/lib/index.d.ts.map +1 -0
  10. package/lib/index.js +19 -0
  11. package/lib/index.js.map +1 -0
  12. package/lib/renderers/dxf/dxf-encoding.d.ts +7 -0
  13. package/lib/renderers/dxf/dxf-encoding.d.ts.map +1 -0
  14. package/lib/renderers/dxf/dxf-encoding.js +343 -0
  15. package/lib/renderers/dxf/dxf-encoding.js.map +1 -0
  16. package/lib/renderers/dxf/dxf-geometries/dxf-box.d.ts +3 -0
  17. package/lib/renderers/dxf/dxf-geometries/dxf-box.d.ts.map +1 -0
  18. package/lib/renderers/dxf/dxf-geometries/dxf-box.js +52 -0
  19. package/lib/renderers/dxf/dxf-geometries/dxf-box.js.map +1 -0
  20. package/lib/renderers/dxf/dxf-geometries/dxf-cone.d.ts +3 -0
  21. package/lib/renderers/dxf/dxf-geometries/dxf-cone.d.ts.map +1 -0
  22. package/lib/renderers/dxf/dxf-geometries/dxf-cone.js +54 -0
  23. package/lib/renderers/dxf/dxf-geometries/dxf-cone.js.map +1 -0
  24. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.d.ts +3 -0
  25. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.d.ts.map +1 -0
  26. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.js +62 -0
  27. package/lib/renderers/dxf/dxf-geometries/dxf-cylinder.js.map +1 -0
  28. package/lib/renderers/dxf/dxf-geometries/dxf-plane.d.ts +3 -0
  29. package/lib/renderers/dxf/dxf-geometries/dxf-plane.d.ts.map +1 -0
  30. package/lib/renderers/dxf/dxf-geometries/dxf-plane.js +38 -0
  31. package/lib/renderers/dxf/dxf-geometries/dxf-plane.js.map +1 -0
  32. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.d.ts +3 -0
  33. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.d.ts.map +1 -0
  34. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.js +61 -0
  35. package/lib/renderers/dxf/dxf-geometries/dxf-polygon.js.map +1 -0
  36. package/lib/renderers/dxf/dxf-geometries/dxf-shape.d.ts +3 -0
  37. package/lib/renderers/dxf/dxf-geometries/dxf-shape.d.ts.map +1 -0
  38. package/lib/renderers/dxf/dxf-geometries/dxf-shape.js +61 -0
  39. package/lib/renderers/dxf/dxf-geometries/dxf-shape.js.map +1 -0
  40. package/lib/renderers/dxf/dxf.d.ts +3 -0
  41. package/lib/renderers/dxf/dxf.d.ts.map +1 -0
  42. package/lib/renderers/dxf/dxf.js +64 -0
  43. package/lib/renderers/dxf/dxf.js.map +1 -0
  44. package/lib/renderers/dxf/index.d.ts +2 -0
  45. package/lib/renderers/dxf/index.d.ts.map +1 -0
  46. package/lib/renderers/dxf/index.js +18 -0
  47. package/lib/renderers/dxf/index.js.map +1 -0
  48. package/lib/renderers/index.d.ts +5 -0
  49. package/lib/renderers/index.d.ts.map +1 -0
  50. package/lib/renderers/index.js +21 -0
  51. package/lib/renderers/index.js.map +1 -0
  52. package/lib/renderers/react/index.d.ts +6 -0
  53. package/lib/renderers/react/index.d.ts.map +1 -0
  54. package/lib/renderers/react/index.js +21 -0
  55. package/lib/renderers/react/index.js.map +1 -0
  56. package/lib/renderers/react/react-camera.d.ts +60 -0
  57. package/lib/renderers/react/react-camera.d.ts.map +1 -0
  58. package/lib/renderers/react/react-camera.js +132 -0
  59. package/lib/renderers/react/react-camera.js.map +1 -0
  60. package/lib/renderers/react/react-dimension.d.ts +12 -0
  61. package/lib/renderers/react/react-dimension.d.ts.map +1 -0
  62. package/lib/renderers/react/react-dimension.js +39 -0
  63. package/lib/renderers/react/react-dimension.js.map +1 -0
  64. package/lib/renderers/react/react-group.d.ts +18 -0
  65. package/lib/renderers/react/react-group.d.ts.map +1 -0
  66. package/lib/renderers/react/react-group.js +62 -0
  67. package/lib/renderers/react/react-group.js.map +1 -0
  68. package/lib/renderers/react/react-hotspot.d.ts +30 -0
  69. package/lib/renderers/react/react-hotspot.d.ts.map +1 -0
  70. package/lib/renderers/react/react-hotspot.js +71 -0
  71. package/lib/renderers/react/react-hotspot.js.map +1 -0
  72. package/lib/renderers/react/react-material.d.ts +13 -0
  73. package/lib/renderers/react/react-material.d.ts.map +1 -0
  74. package/lib/renderers/react/react-material.js +85 -0
  75. package/lib/renderers/react/react-material.js.map +1 -0
  76. package/lib/renderers/react/react-mesh.d.ts +10 -0
  77. package/lib/renderers/react/react-mesh.d.ts.map +1 -0
  78. package/lib/renderers/react/react-mesh.js +238 -0
  79. package/lib/renderers/react/react-mesh.js.map +1 -0
  80. package/lib/renderers/react/react-scene.d.ts +20 -0
  81. package/lib/renderers/react/react-scene.d.ts.map +1 -0
  82. package/lib/renderers/react/react-scene.js +44 -0
  83. package/lib/renderers/react/react-scene.js.map +1 -0
  84. package/lib/renderers/react/react.d.ts +30 -0
  85. package/lib/renderers/react/react.d.ts.map +1 -0
  86. package/lib/renderers/react/react.js +48 -0
  87. package/lib/renderers/react/react.js.map +1 -0
  88. package/lib/renderers/shared.d.ts +6 -0
  89. package/lib/renderers/shared.d.ts.map +1 -0
  90. package/lib/renderers/shared.js +93 -0
  91. package/lib/renderers/shared.js.map +1 -0
  92. package/lib/renderers/stl/index.d.ts +2 -0
  93. package/lib/renderers/stl/index.d.ts.map +1 -0
  94. package/lib/renderers/stl/index.js +18 -0
  95. package/lib/renderers/stl/index.js.map +1 -0
  96. package/lib/renderers/stl/stl-encoding.d.ts +4 -0
  97. package/lib/renderers/stl/stl-encoding.d.ts.map +1 -0
  98. package/lib/renderers/stl/stl-encoding.js +26 -0
  99. package/lib/renderers/stl/stl-encoding.js.map +1 -0
  100. package/lib/renderers/stl/stl-geometries/stl-box.d.ts +3 -0
  101. package/lib/renderers/stl/stl-geometries/stl-box.d.ts.map +1 -0
  102. package/lib/renderers/stl/stl-geometries/stl-box.js +57 -0
  103. package/lib/renderers/stl/stl-geometries/stl-box.js.map +1 -0
  104. package/lib/renderers/stl/stl-geometries/stl-cone.d.ts +3 -0
  105. package/lib/renderers/stl/stl-geometries/stl-cone.d.ts.map +1 -0
  106. package/lib/renderers/stl/stl-geometries/stl-cone.js +54 -0
  107. package/lib/renderers/stl/stl-geometries/stl-cone.js.map +1 -0
  108. package/lib/renderers/stl/stl-geometries/stl-cylinder.d.ts +3 -0
  109. package/lib/renderers/stl/stl-geometries/stl-cylinder.d.ts.map +1 -0
  110. package/lib/renderers/stl/stl-geometries/stl-cylinder.js +62 -0
  111. package/lib/renderers/stl/stl-geometries/stl-cylinder.js.map +1 -0
  112. package/lib/renderers/stl/stl-geometries/stl-plane.d.ts +3 -0
  113. package/lib/renderers/stl/stl-geometries/stl-plane.d.ts.map +1 -0
  114. package/lib/renderers/stl/stl-geometries/stl-plane.js +44 -0
  115. package/lib/renderers/stl/stl-geometries/stl-plane.js.map +1 -0
  116. package/lib/renderers/stl/stl-geometries/stl-polygon.d.ts +3 -0
  117. package/lib/renderers/stl/stl-geometries/stl-polygon.d.ts.map +1 -0
  118. package/lib/renderers/stl/stl-geometries/stl-polygon.js +59 -0
  119. package/lib/renderers/stl/stl-geometries/stl-polygon.js.map +1 -0
  120. package/lib/renderers/stl/stl-geometries/stl-shape.d.ts +3 -0
  121. package/lib/renderers/stl/stl-geometries/stl-shape.d.ts.map +1 -0
  122. package/lib/renderers/stl/stl-geometries/stl-shape.js +59 -0
  123. package/lib/renderers/stl/stl-geometries/stl-shape.js.map +1 -0
  124. package/lib/renderers/stl/stl.d.ts +3 -0
  125. package/lib/renderers/stl/stl.d.ts.map +1 -0
  126. package/lib/renderers/stl/stl.js +57 -0
  127. package/lib/renderers/stl/stl.js.map +1 -0
  128. package/lib/renderers/svg/index.d.ts +3 -0
  129. package/lib/renderers/svg/index.d.ts.map +1 -0
  130. package/lib/renderers/svg/index.js +18 -0
  131. package/lib/renderers/svg/index.js.map +1 -0
  132. package/lib/renderers/svg/svg-encoding.d.ts +14 -0
  133. package/lib/renderers/svg/svg-encoding.d.ts.map +1 -0
  134. package/lib/renderers/svg/svg-encoding.js +27 -0
  135. package/lib/renderers/svg/svg-encoding.js.map +1 -0
  136. package/lib/renderers/svg/svg-geometries/shared.d.ts +12 -0
  137. package/lib/renderers/svg/svg-geometries/shared.d.ts.map +1 -0
  138. package/lib/renderers/svg/svg-geometries/shared.js +12 -0
  139. package/lib/renderers/svg/svg-geometries/shared.js.map +1 -0
  140. package/lib/renderers/svg/svg-geometries/svg-box.d.ts +4 -0
  141. package/lib/renderers/svg/svg-geometries/svg-box.d.ts.map +1 -0
  142. package/lib/renderers/svg/svg-geometries/svg-box.js +70 -0
  143. package/lib/renderers/svg/svg-geometries/svg-box.js.map +1 -0
  144. package/lib/renderers/svg/svg-geometries/svg-cone.d.ts +4 -0
  145. package/lib/renderers/svg/svg-geometries/svg-cone.d.ts.map +1 -0
  146. package/lib/renderers/svg/svg-geometries/svg-cone.js +64 -0
  147. package/lib/renderers/svg/svg-geometries/svg-cone.js.map +1 -0
  148. package/lib/renderers/svg/svg-geometries/svg-cylinder.d.ts +4 -0
  149. package/lib/renderers/svg/svg-geometries/svg-cylinder.d.ts.map +1 -0
  150. package/lib/renderers/svg/svg-geometries/svg-cylinder.js +69 -0
  151. package/lib/renderers/svg/svg-geometries/svg-cylinder.js.map +1 -0
  152. package/lib/renderers/svg/svg-geometries/svg-line.d.ts +4 -0
  153. package/lib/renderers/svg/svg-geometries/svg-line.d.ts.map +1 -0
  154. package/lib/renderers/svg/svg-geometries/svg-line.js +39 -0
  155. package/lib/renderers/svg/svg-geometries/svg-line.js.map +1 -0
  156. package/lib/renderers/svg/svg-geometries/svg-plane.d.ts +5 -0
  157. package/lib/renderers/svg/svg-geometries/svg-plane.d.ts.map +1 -0
  158. package/lib/renderers/svg/svg-geometries/svg-plane.js +57 -0
  159. package/lib/renderers/svg/svg-geometries/svg-plane.js.map +1 -0
  160. package/lib/renderers/svg/svg-geometries/svg-polygon.d.ts +4 -0
  161. package/lib/renderers/svg/svg-geometries/svg-polygon.d.ts.map +1 -0
  162. package/lib/renderers/svg/svg-geometries/svg-polygon.js +20 -0
  163. package/lib/renderers/svg/svg-geometries/svg-polygon.js.map +1 -0
  164. package/lib/renderers/svg/svg-geometries/svg-shape.d.ts +4 -0
  165. package/lib/renderers/svg/svg-geometries/svg-shape.d.ts.map +1 -0
  166. package/lib/renderers/svg/svg-geometries/svg-shape.js +20 -0
  167. package/lib/renderers/svg/svg-geometries/svg-shape.js.map +1 -0
  168. package/lib/renderers/svg/svg-geometries/svg-text.d.ts +4 -0
  169. package/lib/renderers/svg/svg-geometries/svg-text.d.ts.map +1 -0
  170. package/lib/renderers/svg/svg-geometries/svg-text.js +46 -0
  171. package/lib/renderers/svg/svg-geometries/svg-text.js.map +1 -0
  172. package/lib/renderers/svg/svg.d.ts +10 -0
  173. package/lib/renderers/svg/svg.d.ts.map +1 -0
  174. package/lib/renderers/svg/svg.js +98 -0
  175. package/lib/renderers/svg/svg.js.map +1 -0
  176. package/package.json +31 -0
  177. package/src/abstract-3d.ts +578 -0
  178. package/src/index.ts +2 -0
  179. package/src/renderers/dxf/dxf-encoding.ts +348 -0
  180. package/src/renderers/dxf/dxf-geometries/dxf-box.ts +27 -0
  181. package/src/renderers/dxf/dxf-geometries/dxf-cone.ts +31 -0
  182. package/src/renderers/dxf/dxf-geometries/dxf-cylinder.ts +45 -0
  183. package/src/renderers/dxf/dxf-geometries/dxf-plane.ts +16 -0
  184. package/src/renderers/dxf/dxf-geometries/dxf-polygon.ts +36 -0
  185. package/src/renderers/dxf/dxf-geometries/dxf-shape.ts +36 -0
  186. package/src/renderers/dxf/dxf.ts +38 -0
  187. package/src/renderers/dxf/index.ts +1 -0
  188. package/src/renderers/index.ts +4 -0
  189. package/src/renderers/react/index.ts +5 -0
  190. package/src/renderers/react/react-camera.tsx +208 -0
  191. package/src/renderers/react/react-dimension.tsx +76 -0
  192. package/src/renderers/react/react-group.tsx +133 -0
  193. package/src/renderers/react/react-hotspot.tsx +116 -0
  194. package/src/renderers/react/react-material.tsx +159 -0
  195. package/src/renderers/react/react-mesh.tsx +380 -0
  196. package/src/renderers/react/react-scene.tsx +137 -0
  197. package/src/renderers/react/react.tsx +118 -0
  198. package/src/renderers/shared.ts +111 -0
  199. package/src/renderers/stl/index.ts +1 -0
  200. package/src/renderers/stl/stl-encoding.ts +22 -0
  201. package/src/renderers/stl/stl-geometries/stl-box.ts +33 -0
  202. package/src/renderers/stl/stl-geometries/stl-cone.ts +37 -0
  203. package/src/renderers/stl/stl-geometries/stl-cylinder.ts +45 -0
  204. package/src/renderers/stl/stl-geometries/stl-plane.ts +16 -0
  205. package/src/renderers/stl/stl-geometries/stl-polygon.ts +35 -0
  206. package/src/renderers/stl/stl-geometries/stl-shape.ts +35 -0
  207. package/src/renderers/stl/stl.ts +33 -0
  208. package/src/renderers/svg/index.ts +2 -0
  209. package/src/renderers/svg/svg-encoding.ts +46 -0
  210. package/src/renderers/svg/svg-geometries/shared.ts +10 -0
  211. package/src/renderers/svg/svg-geometries/svg-box.ts +61 -0
  212. package/src/renderers/svg/svg-geometries/svg-cone.ts +52 -0
  213. package/src/renderers/svg/svg-geometries/svg-cylinder.ts +58 -0
  214. package/src/renderers/svg/svg-geometries/svg-line.ts +20 -0
  215. package/src/renderers/svg/svg-geometries/svg-plane.ts +44 -0
  216. package/src/renderers/svg/svg-geometries/svg-polygon.ts +25 -0
  217. package/src/renderers/svg/svg-geometries/svg-shape.ts +25 -0
  218. package/src/renderers/svg/svg-geometries/svg-text.ts +28 -0
  219. package/src/renderers/svg/svg.ts +201 -0
@@ -0,0 +1,208 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ import React, { useEffect, useRef, useState } from "react";
4
+ // import { OrbitControls, OrbitControlsProps } from "@react-three/drei/core/OrbitControls";
5
+ // import { GizmoHelper, GizmoHelperProps } from "@react-three/drei/core/GizmoHelper";
6
+ // import { GizmoViewcube } from "@react-three/drei/core/GizmoViewcube";
7
+ // import { OrthographicCamera } from "@react-three/drei/core/OrthographicCamera";
8
+ // import { PerspectiveCamera } from "@react-three/drei/core/PerspectiveCamera";
9
+ // import { GizmoViewport } from "@react-three/drei/core/GizmoViewport";
10
+ import {
11
+ GizmoHelperProps,
12
+ PerspectiveCamera,
13
+ OrthographicCamera,
14
+ OrbitControlsProps,
15
+ OrbitControls,
16
+ GizmoHelper,
17
+ GizmoViewcube,
18
+ GizmoViewport,
19
+ } from "@react-three/drei";
20
+ import { Vector3 } from "three";
21
+ import { ThreeEvent, useFrame, useThree } from "@react-three/fiber";
22
+ import { exhaustiveCheck } from "ts-exhaustive-check";
23
+ import { View, Scene, Vec3, vec3 } from "../../abstract-3d";
24
+
25
+ export type Camera = A3dPerspectiveCamera | A3dOrthographicCamera;
26
+ export type CameraType = Camera["type"];
27
+
28
+ export type A3dPerspectiveCamera = {
29
+ readonly type: "Perspective";
30
+ readonly near?: number;
31
+ readonly far?: number;
32
+ readonly fov?: number;
33
+ };
34
+ export type A3dOrthographicCamera = { readonly type: "Orthographic"; readonly near?: number; readonly far?: number };
35
+
36
+ export type ControlsHelper = (Viewcube | Viewport) & { readonly props: Pick<GizmoHelperProps, "alignment" | "margin"> };
37
+ type Viewcube = { readonly type: "Viewcube"; readonly viewcubeProps: GenericProps };
38
+ type Viewport = { readonly type: "Viewport"; readonly viewportProps: GizmoViewportProps };
39
+
40
+ const ControlsWrapper = (
41
+ props: OrbitControlsProps & { readonly setControls: (r: React.MutableRefObject<any>) => void }
42
+ ): JSX.Element => {
43
+ const ref = useRef<any>();
44
+
45
+ useEffect(() => {
46
+ if (!ref.current) {
47
+ return;
48
+ }
49
+ props.setControls(ref.current);
50
+ }, [ref.current]);
51
+ return <OrbitControls {...props} makeDefault ref={ref} />;
52
+ };
53
+
54
+ export function ReactCamera({
55
+ useAnimations,
56
+ camera,
57
+ view,
58
+ scene,
59
+ controlsHelper,
60
+ orbitContolsProps,
61
+ }: {
62
+ readonly useAnimations: boolean;
63
+ readonly camera: Camera;
64
+ readonly view: View;
65
+ readonly scene: Scene;
66
+ readonly controlsHelper?: ControlsHelper;
67
+ readonly orbitContolsProps?: OrbitControlsProps;
68
+ }): JSX.Element {
69
+ const [controls, setControls] = useState<any | null>(null);
70
+ const perspectiveRef = useRef<any | undefined>(undefined);
71
+ const orthographicRef = useRef<any | undefined>(undefined);
72
+ const viewPortAspect = useThree(({ viewport: { aspect } }) => aspect);
73
+
74
+ useEffect(() => {
75
+ const [posX, posY, posZ, size, sceneAspect] = (() => {
76
+ switch (view) {
77
+ case "front":
78
+ return [0, 0, 1, scene.size, scene.size.x / scene.size.y];
79
+ case "back":
80
+ return [0, 0, -1, scene.size, scene.size.x / scene.size.y];
81
+ case "top":
82
+ return [0, 1, 0, vec3(scene.size.x, scene.size.z, scene.size.y), scene.size.x / scene.size.z];
83
+ case "bottom":
84
+ return [0, -1, 0, vec3(scene.size.x, scene.size.z, scene.size.y), scene.size.x / scene.size.z];
85
+ case "right":
86
+ return [1, 0, 0, vec3(scene.size.z, scene.size.y, scene.size.x), scene.size.z / scene.size.y];
87
+ case "left":
88
+ return [-1, 0, 0, vec3(scene.size.z, scene.size.y, scene.size.x), scene.size.z / scene.size.y];
89
+ default:
90
+ return exhaustiveCheck(view);
91
+ }
92
+ })();
93
+
94
+ const dist = cameraDist(size, camera.type === "Perspective" ? camera.fov ?? 45 : 45);
95
+
96
+ if (camera.type === "Orthographic" && orthographicRef.current) {
97
+ const [left, right, top, bottom] =
98
+ sceneAspect > viewPortAspect
99
+ ? [-size.x / 2, size.x / 2, size.x / 2 / viewPortAspect, -size.x / 2 / viewPortAspect]
100
+ : [(-viewPortAspect * size.y) / 2, (viewPortAspect * size.y) / 2, size.y / 2, -size.y / 2];
101
+ orthographicRef.current.position.setX(posX * dist);
102
+ orthographicRef.current.position.setY(posY * dist);
103
+ orthographicRef.current.position.setZ(posZ * dist);
104
+ orthographicRef.current.left = left;
105
+ orthographicRef.current.right = right;
106
+ orthographicRef.current.bottom = bottom;
107
+ orthographicRef.current.top = top;
108
+ orthographicRef.current.updateProjectionMatrix();
109
+ } else if (camera.type === "Perspective" && perspectiveRef.current) {
110
+ perspectiveRef.current.position.setX(posX * dist);
111
+ perspectiveRef.current.position.setY(posY * dist);
112
+ perspectiveRef.current.position.setZ(posZ * dist);
113
+ perspectiveRef.current.updateProjectionMatrix();
114
+ }
115
+ }, [camera, viewPortAspect]);
116
+ // const prevScene = React.useRef(scene)
117
+ // useEffect(() => {
118
+ // prevScene.current = scene;
119
+ // }, [scene]);
120
+
121
+ useFrame(() => {
122
+ // if (useAnimations && camera && prevScene.current !== scene) {
123
+ // const [, , z] = cameraDist(scene);
124
+ // vector3.set(camera.position.x, camera.position.y, z);
125
+ // camera.position.lerp(vector3, 0.12);
126
+ // ref.current.enabled = false;
127
+ // invalidate();
128
+ // } else {
129
+ // ref.current.enabled = true;
130
+ // }
131
+ });
132
+ return (
133
+ <>
134
+ <PerspectiveCamera
135
+ ref={perspectiveRef}
136
+ near={camera.near}
137
+ far={camera.far}
138
+ fov={camera.type === "Perspective" ? camera.fov : 75}
139
+ aspect={viewPortAspect}
140
+ manual={true}
141
+ makeDefault={camera.type === "Perspective"}
142
+ />
143
+ <OrthographicCamera
144
+ ref={orthographicRef}
145
+ up={[0, 1, 0]}
146
+ near={camera.near}
147
+ far={camera.far}
148
+ manual={true}
149
+ makeDefault={camera.type === "Orthographic"}
150
+ />
151
+ <ControlsWrapper {...orbitContolsProps} setControls={(c) => setControls(c.current)} />
152
+ {(() => {
153
+ switch (controlsHelper?.type) {
154
+ case "Viewcube":
155
+ return (
156
+ <GizmoHelper
157
+ {...controlsHelper.props}
158
+ onTarget={() => controls?.target as Vector3}
159
+ onUpdate={() => controls?.update?.()}
160
+ >
161
+ <GizmoViewcube {...(controlsHelper.viewcubeProps as any)} />
162
+ </GizmoHelper>
163
+ );
164
+ case "Viewport":
165
+ return (
166
+ <GizmoHelper
167
+ {...controlsHelper.props}
168
+ onTarget={() => controls?.target as Vector3}
169
+ onUpdate={() => controls?.update?.()}
170
+ >
171
+ <GizmoViewport {...(controlsHelper.viewportProps as any)} />
172
+ </GizmoHelper>
173
+ );
174
+ case undefined:
175
+ default:
176
+ return <></>;
177
+ }
178
+ })()}
179
+ </>
180
+ );
181
+ }
182
+
183
+ type GizmoViewportProps = JSX.IntrinsicElements["group"] & {
184
+ readonly axisColors?: readonly [string, string, string];
185
+ readonly axisScale?: readonly [number, number, number];
186
+ readonly labels?: readonly [string, string, string];
187
+ readonly axisHeadScale?: number;
188
+ readonly labelColor?: string;
189
+ readonly hideNegativeAxes?: boolean;
190
+ readonly hideAxisHeads?: boolean;
191
+ readonly disabled?: boolean;
192
+ readonly font?: string;
193
+ readonly onClick?: (e: ThreeEvent<MouseEvent>) => null;
194
+ };
195
+
196
+ type GenericProps = {
197
+ readonly font?: string;
198
+ readonly opacity?: number;
199
+ readonly color?: string;
200
+ readonly hoverColor?: string;
201
+ readonly textColor?: string;
202
+ readonly strokeColor?: string;
203
+ readonly onClick?: (e: ThreeEvent<MouseEvent>) => null;
204
+ readonly faces?: ReadonlyArray<string>;
205
+ };
206
+
207
+ export const cameraDist = (size: Vec3, fov: number): number =>
208
+ size.z * 0.5 + (size.x > size.y ? size.x : size.y) / (1 / 2 / Math.tan((Math.PI * fov) / 180 / 2));
@@ -0,0 +1,76 @@
1
+ import { useFrame } from "@react-three/fiber";
2
+ import React from "react";
3
+ import { Group } from "three";
4
+ import * as A3d from "../../abstract-3d";
5
+ import { ReactMaterial } from "./react-material";
6
+ import { ReactMesh } from "./react-mesh";
7
+
8
+ export const ReactDimensions = React.memo(
9
+ ({
10
+ dimensions,
11
+ showDimensions,
12
+ }: {
13
+ readonly dimensions: A3d.Dimensions | undefined;
14
+ readonly showDimensions: boolean;
15
+ }): JSX.Element => {
16
+ const dimensionMaterial = React.useMemo(
17
+ () => (dimensions?.material ? <ReactMaterial material={dimensions?.material} /> : <></>),
18
+ []
19
+ );
20
+ return (
21
+ <>
22
+ {dimensions?.dimensions.map((dimension, i) => (
23
+ <ReactDimension key={i} d={dimension} visible={showDimensions}>
24
+ {dimensionMaterial}
25
+ </ReactDimension>
26
+ ))}
27
+ </>
28
+ );
29
+ }
30
+ );
31
+
32
+ export function ReactDimension({
33
+ d,
34
+ visible,
35
+ children,
36
+ }: {
37
+ readonly d: A3d.Dimension;
38
+ readonly visible: boolean;
39
+ readonly children: JSX.Element;
40
+ }): JSX.Element {
41
+ const ref = React.useRef<Group>(undefined!);
42
+ useFrame(({ camera }) => {
43
+ ref.current.visible =
44
+ visible &&
45
+ ((): boolean => {
46
+ const cameraPositions = {
47
+ [camera.position.x >= 0 ? "right" : "left"]: true,
48
+ [camera.position.y >= 0 ? "top" : "bottom"]: true,
49
+ [camera.position.z >= 0 ? "front" : "back"]: true,
50
+ };
51
+ if (d.views.every((cp) => cameraPositions[cp])) {
52
+ ref.current.position.set(d.pos.x, d.pos.y, d.pos.z);
53
+ ref.current.rotation.set(d.rot.x, d.rot.y, d.rot.z);
54
+ return true;
55
+ }
56
+ return false;
57
+ })();
58
+ });
59
+ return (
60
+ <group ref={ref}>
61
+ <DimensionMeshes meshes={d.meshes}>{children}</DimensionMeshes>
62
+ </group>
63
+ );
64
+ }
65
+
66
+ const DimensionMeshes = React.memo(
67
+ ({ meshes, children }: { readonly meshes: ReadonlyArray<A3d.Mesh>; readonly children: JSX.Element }): JSX.Element => (
68
+ <>
69
+ {meshes.map((m, i) => (
70
+ <ReactMesh key={i} mesh={m}>
71
+ {children}
72
+ </ReactMesh>
73
+ ))}
74
+ </>
75
+ )
76
+ );
@@ -0,0 +1,133 @@
1
+ import React from "react";
2
+ import { Group } from "three";
3
+ import { useFrame } from "@react-three/fiber";
4
+ import * as A3d from "../../abstract-3d";
5
+ import { MaterialState, ReactMaterial } from "./react-material";
6
+ import { ReactMesh } from "./react-mesh";
7
+
8
+ export function ReactGroup({
9
+ g,
10
+ materialStateImages,
11
+ hoveredId,
12
+ hoveredIdExternal,
13
+ selectedId,
14
+ hotSpotsActive,
15
+ activeComponents,
16
+ id,
17
+ rootData,
18
+ onClickGroup,
19
+ onContextMenuGroup,
20
+ setHoveredId,
21
+ createGroupKey,
22
+ }: {
23
+ readonly g: A3d.Group;
24
+ readonly materialStateImages?: Record<string, string>;
25
+ readonly hoveredId: string | undefined;
26
+ readonly hoveredIdExternal: string | undefined;
27
+ readonly selectedId: string | undefined;
28
+ readonly hotSpotsActive: boolean;
29
+ readonly activeComponents: Record<string, MaterialState> | undefined;
30
+ readonly id: string | undefined;
31
+ readonly rootData: Record<string, string> | undefined;
32
+ readonly onClickGroup?: (
33
+ id: string | undefined,
34
+ rootData: Record<string, string> | undefined,
35
+ data: Record<string, string> | undefined
36
+ ) => void;
37
+ readonly onContextMenuGroup?: (
38
+ id: string,
39
+ rootData: Record<string, string> | undefined,
40
+ data: Record<string, string> | undefined,
41
+ left: number,
42
+ top: number
43
+ ) => void;
44
+ readonly setHoveredId: (id: string | undefined) => void;
45
+ readonly createGroupKey?: (
46
+ g: A3d.Group,
47
+ idx: number,
48
+ rootData: Record<string, string> | undefined,
49
+ id: string
50
+ ) => string;
51
+ }): JSX.Element {
52
+ const ref = React.useRef<Group>(undefined!);
53
+ useFrame(({ invalidate }, delta) => {
54
+ if (g.animation) {
55
+ invalidate();
56
+ ref.current.rotation.x += (g.animation.transform.rot.x / g.animation.duration) * 1000 * delta;
57
+ ref.current.rotation.y += (g.animation.transform.rot.y / g.animation.duration) * 1000 * delta;
58
+ ref.current.rotation.z += (g.animation.transform.rot.z / g.animation.duration) * 1000 * delta;
59
+ } else {
60
+ ref.current.rotation.x = g.rot?.x ?? 0;
61
+ ref.current.rotation.y = g.rot?.y ?? 0;
62
+ ref.current.rotation.z = g.rot?.z ?? 0;
63
+ ref.current.position.x = g.pos.x;
64
+ ref.current.position.y = g.pos.y;
65
+ ref.current.position.z = g.pos.z;
66
+ }
67
+ });
68
+ const materialState = activeComponents?.[id ?? ""];
69
+ const disabled = hotSpotsActive && materialState !== "Accept";
70
+ return (
71
+ <group
72
+ rotation={[g.rot?.x ?? 0, g.rot?.y ?? 0, g.rot?.z ?? 0]}
73
+ position={[g.pos.x, g.pos.y, g.pos.z]}
74
+ ref={ref}
75
+ {...(id &&
76
+ !disabled && {
77
+ onClick: (e) => {
78
+ if (onClickGroup) {
79
+ e.stopPropagation();
80
+ onClickGroup(id, rootData, g.data);
81
+ }
82
+ },
83
+ onPointerOver: (e) => {
84
+ e.stopPropagation();
85
+ document.body.style.cursor = "pointer";
86
+ setHoveredId(id);
87
+ },
88
+ onPointerOut: (_e) => {
89
+ document.body.style.cursor = "auto";
90
+ setHoveredId(undefined);
91
+ },
92
+ onContextMenu: (e) => {
93
+ if (onContextMenuGroup) {
94
+ e.stopPropagation();
95
+ onContextMenuGroup(id, rootData, g.data, e.nativeEvent.x, e.nativeEvent.y);
96
+ }
97
+ },
98
+ })}
99
+ >
100
+ {g.groups?.map((g, i) => (
101
+ <ReactGroup
102
+ key={createGroupKey ? createGroupKey(g, i, rootData, id ?? "") : i}
103
+ g={g}
104
+ selectedId={selectedId}
105
+ hotSpotsActive={hotSpotsActive}
106
+ activeComponents={activeComponents}
107
+ materialStateImages={materialStateImages}
108
+ hoveredId={hoveredId}
109
+ hoveredIdExternal={hoveredIdExternal}
110
+ onClickGroup={onClickGroup}
111
+ onContextMenuGroup={onContextMenuGroup}
112
+ setHoveredId={setHoveredId}
113
+ id={id}
114
+ rootData={rootData}
115
+ createGroupKey={createGroupKey}
116
+ />
117
+ ))}
118
+ {g.meshes?.map((m, i) => (
119
+ <ReactMesh key={`mesh_${i}`} mesh={m}>
120
+ <ReactMaterial
121
+ material={m.material}
122
+ id={id}
123
+ selectedId={selectedId}
124
+ hoveredId={hoveredId || hoveredIdExternal}
125
+ materialStateImages={materialStateImages}
126
+ disabled={disabled}
127
+ state={materialState}
128
+ />
129
+ </ReactMesh>
130
+ ))}
131
+ </group>
132
+ );
133
+ }
@@ -0,0 +1,116 @@
1
+ import React from "react";
2
+ // import { Html } from "@react-three/drei/web/Html";
3
+ import { Html } from "@react-three/drei";
4
+ import * as A3d from "../../abstract-3d";
5
+ import { ReactMesh } from "./react-mesh";
6
+ import { ReactMaterial } from "./react-material";
7
+
8
+ export interface HotSpotInfo {
9
+ readonly replaceId: string;
10
+ readonly replaceFromId: string;
11
+ readonly replaceOutlet: string;
12
+ readonly replaceToId: string;
13
+ readonly replaceInlet: string;
14
+ }
15
+
16
+ export const ReactHotSpots = React.memo(
17
+ ({
18
+ hotSpots,
19
+ showHotSpotTexts,
20
+ hotSpotTexts,
21
+ hotSpotZAdjPos,
22
+ activeHotSpots,
23
+ hoveredId,
24
+ onClickHotSpot,
25
+ setHoveredId,
26
+ }: {
27
+ readonly hotSpots?: ReadonlyArray<A3d.HotSpot>;
28
+ readonly showHotSpotTexts: boolean;
29
+ readonly hotSpotZAdjPos: number;
30
+ readonly hotSpotTexts?: Record<string, string>;
31
+ readonly activeHotSpots: Record<string, HotSpotInfo> | undefined;
32
+ readonly hoveredId: string | undefined;
33
+ readonly onClickHotSpot?: (hotSpot: HotSpotInfo) => void;
34
+ readonly setHoveredId: (id: string | undefined) => void;
35
+ }): JSX.Element => {
36
+ return (
37
+ <>
38
+ {hotSpots?.map((h) => (
39
+ <ReactHotSpot
40
+ key={h.id}
41
+ h={h}
42
+ hotSpotZAdjPos={hotSpotZAdjPos}
43
+ activeHotSpots={activeHotSpots}
44
+ hotSpotTexts={hotSpotTexts}
45
+ hoveredId={hoveredId}
46
+ onClickHotSpot={onClickHotSpot}
47
+ setHoveredId={setHoveredId}
48
+ showHotSpotTexts={showHotSpotTexts}
49
+ />
50
+ ))}
51
+ </>
52
+ );
53
+ }
54
+ );
55
+
56
+ export function ReactHotSpot({
57
+ h,
58
+ hotSpotZAdjPos,
59
+ showHotSpotTexts,
60
+ hotSpotTexts,
61
+ activeHotSpots,
62
+ hoveredId,
63
+ onClickHotSpot,
64
+ setHoveredId,
65
+ }: {
66
+ readonly h: A3d.HotSpot;
67
+ readonly hotSpotZAdjPos: number;
68
+ readonly showHotSpotTexts: boolean;
69
+ readonly hotSpotTexts?: Record<string, string>;
70
+ readonly activeHotSpots: Record<string, HotSpotInfo> | undefined;
71
+ readonly hoveredId: string | undefined;
72
+ readonly onClickHotSpot?: (hotSpot: HotSpotInfo) => void;
73
+ readonly setHoveredId: (id: string | undefined) => void;
74
+ }): JSX.Element {
75
+ const hotSpot = activeHotSpots ? activeHotSpots[h.id] : undefined;
76
+ const hsPos = h.mesh.geometry.type === "Box" ? h.mesh.geometry.pos : A3d.vec3Zero;
77
+ const text = hotSpotTexts?.[h.id];
78
+ return (
79
+ <>
80
+ <group
81
+ visible={hotSpot !== undefined}
82
+ {...(hotSpot && {
83
+ onClick: (e) => {
84
+ if (onClickHotSpot) {
85
+ e.stopPropagation();
86
+ onClickHotSpot(hotSpot);
87
+ }
88
+ },
89
+ onPointerOver: (e) => {
90
+ e.stopPropagation();
91
+ document.body.style.cursor = "pointer";
92
+ setHoveredId(h.id);
93
+ },
94
+ onPointerOut: (_e) => {
95
+ document.body.style.cursor = "auto";
96
+ setHoveredId(undefined);
97
+ },
98
+ onContextMenu: (e) => {
99
+ e.stopPropagation();
100
+ },
101
+ })}
102
+ >
103
+ <ReactMesh mesh={h.mesh}>
104
+ <ReactMaterial id={h.id} material={h.mesh.material} hoveredId={hoveredId} />
105
+ </ReactMesh>
106
+ </group>
107
+ {hotSpotTexts && text && (
108
+ <Html position={[hsPos.x, hsPos.y, hotSpotZAdjPos]} center>
109
+ <div className={`air-states-container ${showHotSpotTexts ? "" : "air-states-container-hidden"}`}>
110
+ <span className="air-states-text">{text}</span>
111
+ </div>
112
+ </Html>
113
+ )}
114
+ </>
115
+ );
116
+ }
@@ -0,0 +1,159 @@
1
+ import React from "react";
2
+ import { Color, DoubleSide, MaterialParameters, SRGBColorSpace, Texture, TextureLoader } from "three";
3
+ import { suspend } from "suspend-react";
4
+ import * as A3d from "../../abstract-3d";
5
+
6
+ const decreasedOpacity = 0.2;
7
+
8
+ export type MaterialState = "Accept" | "Error" | "Warning";
9
+ export const ERROR_IMG_KEY = "error";
10
+
11
+ export function ReactMaterial({
12
+ material,
13
+ id = "",
14
+ selectedId,
15
+ hoveredId,
16
+ disabled,
17
+ materialStateImages,
18
+ state,
19
+ }: {
20
+ readonly material: A3d.Material;
21
+ readonly id?: string;
22
+ readonly hoveredId?: string | undefined;
23
+ readonly selectedId?: string | undefined;
24
+ readonly disabled?: boolean;
25
+ readonly materialStateImages?: Record<string, string>;
26
+ readonly state?: MaterialState | undefined;
27
+ }): JSX.Element {
28
+ const mat =
29
+ !state || material.image?.type === "UrlImage"
30
+ ? material
31
+ : state === "Accept"
32
+ ? acceptMaterial
33
+ : state === "Error"
34
+ ? errorMaterial
35
+ : warningMaterial;
36
+ const color = selectedId === id ? mat.selected : hoveredId === id ? mat.hover : mat.normal;
37
+ const opacity = material.opacity !== undefined ? material.opacity : materialDefaults.opacity!;
38
+ if (material.image?.type === "UrlImage") {
39
+ return (
40
+ <TextureMaterial
41
+ url={state === "Error" ? materialStateImages?.[ERROR_IMG_KEY] ?? material.image.url : material.image.url}
42
+ color={color}
43
+ material={mat}
44
+ />
45
+ );
46
+ }
47
+
48
+ switch (mat.type) {
49
+ case "Basic":
50
+ return (
51
+ <meshBasicMaterial
52
+ color={color}
53
+ side={DoubleSide}
54
+ transparent
55
+ {...(opacity < 1 ? { opacity } : materialDefaults)}
56
+ />
57
+ );
58
+ case "Phong":
59
+ return (
60
+ <meshPhongMaterial
61
+ color={color}
62
+ shininess={(mat.shininess ?? 70) * 2}
63
+ side={DoubleSide}
64
+ {...(opacity < 1 || disabled
65
+ ? { transparent: true, opacity: disabled ? opacity * decreasedOpacity : opacity }
66
+ : materialDefaults)}
67
+ />
68
+ );
69
+ // return (
70
+ // <meshStandardMaterial
71
+ // color={color}
72
+ // roughness={0.45}
73
+ // metalness={0.55}
74
+ // side={DoubleSide}
75
+ // {...(mat.opacity < 1 || disabled
76
+ // ? { transparent: true, opacity: disabled ? mat.opacity * decreasedOpacity : mat.opacity }
77
+ // : materialDefaults)}
78
+ // />
79
+ // );
80
+ case "Lambert":
81
+ default:
82
+ return (
83
+ <meshLambertMaterial
84
+ color={color}
85
+ side={DoubleSide}
86
+ {...(opacity < 1 || disabled
87
+ ? { transparent: true, opacity: disabled ? opacity * decreasedOpacity : opacity }
88
+ : materialDefaults)}
89
+ />
90
+ );
91
+ }
92
+ }
93
+
94
+ function TextureMaterial({
95
+ url,
96
+ color,
97
+ material,
98
+ }: {
99
+ readonly url: string;
100
+ readonly color: string | Color | undefined;
101
+ readonly material: A3d.Material;
102
+ }): JSX.Element {
103
+ const texture = suspend(
104
+ new Promise((res) =>
105
+ textureLoader.load(
106
+ url,
107
+ (data) => {
108
+ data.colorSpace = SRGBColorSpace;
109
+ res(data);
110
+ },
111
+ undefined,
112
+ () => res(null)
113
+ )
114
+ ),
115
+ [url]
116
+ ) as Texture | null;
117
+
118
+ return (
119
+ <meshBasicMaterial
120
+ color={color}
121
+ side={DoubleSide}
122
+ alphaTest={0.8}
123
+ map={texture}
124
+ {...(material.opacity !== undefined && material.opacity < 1 ? { opacity: material.opacity } : materialDefaults)}
125
+ transparent
126
+ />
127
+ );
128
+ }
129
+
130
+ const textureLoader = new TextureLoader();
131
+
132
+ const materialDefaults: MaterialParameters = { transparent: false, opacity: 1.0, depthWrite: true, depthTest: true };
133
+
134
+ const acceptMaterial: A3d.Material = {
135
+ type: "Phong",
136
+ normal: "rgb(0,148,91)",
137
+ hover: "rgb(1,88,55)",
138
+ selected: "rgb(1,88,55)",
139
+ opacity: 1.0,
140
+ shininess: 50,
141
+ };
142
+
143
+ const errorMaterial: A3d.Material = {
144
+ type: "Phong",
145
+ normal: "#b82f3a",
146
+ hover: "#991c31",
147
+ selected: "#991c31",
148
+ opacity: 1.0,
149
+ shininess: 50,
150
+ };
151
+
152
+ const warningMaterial: A3d.Material = {
153
+ type: "Phong",
154
+ normal: "rgb(240, 197, 48)",
155
+ hover: "rgb(221, 181, 38)",
156
+ selected: "rgb(182, 147, 20)",
157
+ opacity: 1.0,
158
+ shininess: 50,
159
+ };