@wandelbots/wandelbots-js-react-components 4.6.0 → 4.7.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/dist/3d.cjs.js +1 -1
- package/dist/3d.es.js +1 -1
- package/dist/{LoadingCover-6gWr11KP.js → LoadingCover-B3UN1lnU.js} +12 -19
- package/dist/LoadingCover-B3UN1lnU.js.map +1 -0
- package/dist/LoadingCover-DXcsXWDy.cjs +2 -0
- package/dist/LoadingCover-DXcsXWDy.cjs.map +1 -0
- package/dist/MotionGroupVisualizer-D8_sA8PA.js +1347 -0
- package/dist/MotionGroupVisualizer-D8_sA8PA.js.map +1 -0
- package/dist/MotionGroupVisualizer-DcHXsQ4A.cjs +2 -0
- package/dist/MotionGroupVisualizer-DcHXsQ4A.cjs.map +1 -0
- package/dist/{WandelscriptEditor-D6_vS5Uk.cjs → WandelscriptEditor-6sAoniLC.cjs} +2 -2
- package/dist/{WandelscriptEditor-D6_vS5Uk.cjs.map → WandelscriptEditor-6sAoniLC.cjs.map} +1 -1
- package/dist/{WandelscriptEditor-7eN-Yw7m.js → WandelscriptEditor-kWC2VyG_.js} +3 -3
- package/dist/{WandelscriptEditor-7eN-Yw7m.js.map → WandelscriptEditor-kWC2VyG_.js.map} +1 -1
- package/dist/components/3d-viewport/SafetyZonesRenderer.d.ts +1 -1
- package/dist/components/3d-viewport/SafetyZonesRenderer.d.ts.map +1 -1
- package/dist/components/utils/converters.d.ts +9 -0
- package/dist/components/utils/converters.d.ts.map +1 -1
- package/dist/core.cjs.js +1 -1
- package/dist/core.es.js +4 -4
- package/dist/{externalizeComponent-CkVWk2F_.cjs → externalizeComponent-B98tgTPP.cjs} +6 -6
- package/dist/externalizeComponent-B98tgTPP.cjs.map +1 -0
- package/dist/{externalizeComponent-Dc3fViZA.js → externalizeComponent-BOqKMZMc.js} +167 -130
- package/dist/externalizeComponent-BOqKMZMc.js.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +6 -6
- package/dist/{interpolation-BxZtUOAs.js → interpolation-B8AcxfdD.js} +274 -274
- package/dist/interpolation-B8AcxfdD.js.map +1 -0
- package/dist/{interpolation-D4zTPZou.cjs → interpolation-SWzo5zr4.cjs} +4 -4
- package/dist/interpolation-SWzo5zr4.cjs.map +1 -0
- package/dist/{theming-3PEA0ksG.js → theming-BKpqgTRM.js} +4 -4
- package/dist/{theming-3PEA0ksG.js.map → theming-BKpqgTRM.js.map} +1 -1
- package/dist/{theming-U3LOZpcT.cjs → theming-CatQaIl_.cjs} +2 -2
- package/dist/{theming-U3LOZpcT.cjs.map → theming-CatQaIl_.cjs.map} +1 -1
- package/dist/wandelscript.cjs.js +1 -1
- package/dist/wandelscript.es.js +1 -1
- package/package.json +1 -1
- package/src/components/3d-viewport/SafetyZonesRenderer.tsx +139 -149
- package/src/components/utils/converters.ts +64 -0
- package/dist/LoadingCover-6gWr11KP.js.map +0 -1
- package/dist/LoadingCover-CukpS_aj.cjs +0 -2
- package/dist/LoadingCover-CukpS_aj.cjs.map +0 -1
- package/dist/MotionGroupVisualizer-BlWkdkaM.js +0 -1338
- package/dist/MotionGroupVisualizer-BlWkdkaM.js.map +0 -1
- package/dist/MotionGroupVisualizer-Bw-h3U_t.cjs +0 -2
- package/dist/MotionGroupVisualizer-Bw-h3U_t.cjs.map +0 -1
- package/dist/externalizeComponent-CkVWk2F_.cjs.map +0 -1
- package/dist/externalizeComponent-Dc3fViZA.js.map +0 -1
- package/dist/interpolation-BxZtUOAs.js.map +0 -1
- package/dist/interpolation-D4zTPZou.cjs.map +0 -1
package/dist/wandelscript.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./WandelscriptEditor-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./WandelscriptEditor-6sAoniLC.cjs");exports.WandelscriptEditor=t.WandelscriptEditor;
|
|
2
2
|
//# sourceMappingURL=wandelscript.cjs.js.map
|
package/dist/wandelscript.es.js
CHANGED
package/package.json
CHANGED
|
@@ -1,170 +1,165 @@
|
|
|
1
1
|
import { useEffect, useMemo } from "react"
|
|
2
2
|
import { type ThreeElements } from "@react-three/fiber"
|
|
3
|
-
import { type Collider, type ConvexHull, type DHParameter, type MotionGroupDescription } from "@wandelbots/nova-js/v2"
|
|
4
|
-
import type { Geometry, SafetySetupSafetyZone } from "@wandelbots/nova-js/v1"
|
|
5
3
|
import * as THREE from "three"
|
|
6
|
-
import { ConvexGeometry } from "three-stdlib"
|
|
7
|
-
|
|
4
|
+
import { ConvexGeometry, RoundedBoxGeometry } from "three-stdlib"
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
Collider,
|
|
8
|
+
ConvexHull,
|
|
9
|
+
DHParameter,
|
|
10
|
+
MotionGroupDescription,
|
|
11
|
+
Sphere,
|
|
12
|
+
Capsule,
|
|
13
|
+
RectangularCapsule,
|
|
14
|
+
} from "@wandelbots/nova-js/v2"
|
|
15
|
+
import type { Geometry, SafetySetupSafetyZone } from "@wandelbots/nova-js/v1"
|
|
16
|
+
|
|
17
|
+
import { dhParametersToPlaneSize, orientationToQuaternion, verticesToCoplanarity } from "../utils/converters"
|
|
8
18
|
|
|
9
19
|
export type SafetyZonesRendererProps = {
|
|
10
20
|
safetyZones: SafetySetupSafetyZone[] | MotionGroupDescription["safety_zones"]
|
|
11
21
|
dhParameters?: DHParameter[]
|
|
12
22
|
} & ThreeElements["group"]
|
|
13
23
|
|
|
14
|
-
interface CoplanarityResult {
|
|
15
|
-
isCoplanar: boolean
|
|
16
|
-
normal?: THREE.Vector3
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function areVerticesCoplanar(vertices: THREE.Vector3[]): CoplanarityResult {
|
|
20
|
-
if (vertices.length < 3) {
|
|
21
|
-
console.log("Not enough vertices to define a plane")
|
|
22
|
-
return { isCoplanar: false }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Convert Vector3d to THREE.Vector3
|
|
26
|
-
const v0 = new THREE.Vector3(vertices[0].x, vertices[0].y, vertices[0].z)
|
|
27
|
-
const v1 = new THREE.Vector3(vertices[1].x, vertices[1].y, vertices[1].z)
|
|
28
|
-
const v2 = new THREE.Vector3(vertices[2].x, vertices[2].y, vertices[2].z)
|
|
29
|
-
|
|
30
|
-
const vector1 = new THREE.Vector3().subVectors(v1, v0)
|
|
31
|
-
const vector2 = new THREE.Vector3().subVectors(v2, v0)
|
|
32
|
-
const normal = new THREE.Vector3().crossVectors(vector1, vector2).normalize()
|
|
33
|
-
|
|
34
|
-
// Check if all remaining vertices lie on the same plane
|
|
35
|
-
for (let i = 3; i < vertices.length; i++) {
|
|
36
|
-
const vi = new THREE.Vector3(vertices[i].x, vertices[i].y, vertices[i].z)
|
|
37
|
-
const vector = new THREE.Vector3().subVectors(vi, v0)
|
|
38
|
-
const dotProduct = normal.dot(vector)
|
|
39
|
-
if (Math.abs(dotProduct) > 1e-6) {
|
|
40
|
-
// Allowing a small tolerance
|
|
41
|
-
console.log("Vertices are not on the same plane")
|
|
42
|
-
return { isCoplanar: false }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { isCoplanar: true, normal }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
24
|
export function SafetyZonesRenderer({
|
|
50
25
|
safetyZones,
|
|
51
26
|
dhParameters,
|
|
52
27
|
...props
|
|
53
28
|
}: SafetyZonesRendererProps) {
|
|
29
|
+
/**
|
|
30
|
+
* Common material properties for safety zone meshes
|
|
31
|
+
*/
|
|
32
|
+
const safetyZoneMaterialProps = {
|
|
33
|
+
attach: "material" as const,
|
|
34
|
+
color: "#009f4d",
|
|
35
|
+
opacity: 0.2,
|
|
36
|
+
depthTest: false,
|
|
37
|
+
depthWrite: false,
|
|
38
|
+
transparent: true,
|
|
39
|
+
polygonOffset: true,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Plane size for the plane safety zones, returns the reach distance
|
|
44
|
+
* of the robot
|
|
45
|
+
*/
|
|
46
|
+
const planeSize = dhParametersToPlaneSize(dhParameters ?? [])
|
|
54
47
|
|
|
55
48
|
/**
|
|
56
49
|
* Warning during runtime stating the deprecation of the V1 safety zones
|
|
57
50
|
*/
|
|
58
51
|
useEffect(() => {
|
|
59
|
-
Array.isArray(safetyZones) &&
|
|
52
|
+
Array.isArray(safetyZones) &&
|
|
53
|
+
console.warn("SafetyZonesRenderer: The support of V1 safety zones is deprecated. Please migrate to V2 safety zones.")
|
|
60
54
|
}, [safetyZones])
|
|
61
55
|
|
|
62
56
|
/**
|
|
63
|
-
* Helper function to render
|
|
64
|
-
* @param vertices Vector3[]
|
|
57
|
+
* Helper function to render plane, sphere, and capsule meshes
|
|
65
58
|
* @param id number
|
|
59
|
+
* @param zone Collider
|
|
66
60
|
*/
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
// Algorithm has troubles with vertices that are on the same plane so we
|
|
70
|
-
// add a new vertex slightly moved along the normal direction
|
|
71
|
-
const coplanarityResult = areVerticesCoplanar(vertices)
|
|
72
|
-
|
|
73
|
-
if (coplanarityResult.isCoplanar && coplanarityResult.normal) {
|
|
74
|
-
// Add a new vertex slightly moved along the normal direction
|
|
75
|
-
const offset = 0.0001 // Adjust the offset as needed
|
|
76
|
-
const newVertex = new THREE.Vector3().addVectors(
|
|
77
|
-
vertices[0],
|
|
78
|
-
coplanarityResult.normal.multiplyScalar(offset),
|
|
79
|
-
)
|
|
80
|
-
vertices.push(newVertex)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let convexGeometry
|
|
84
|
-
try {
|
|
85
|
-
convexGeometry = new ConvexGeometry(vertices)
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.log("Error creating ConvexGeometry:", error)
|
|
61
|
+
const renderMesh = (id: number, zone: Collider) => {
|
|
62
|
+
if (!zone?.pose?.position || !zone?.pose?.orientation) {
|
|
88
63
|
return null
|
|
89
64
|
}
|
|
90
65
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
66
|
+
const position = new THREE.Vector3(zone.pose.position[0] / 1000, zone.pose.position[1] / 1000, zone.pose.position[2] / 1000)
|
|
67
|
+
const orientation = new THREE.Vector3(zone.pose.orientation[0], zone.pose.orientation[1], zone.pose.orientation[2])
|
|
68
|
+
|
|
69
|
+
let geometry: React.ReactElement | null
|
|
70
|
+
|
|
71
|
+
const materialProps = zone.shape.shape_type === "plane"
|
|
72
|
+
? { ...safetyZoneMaterialProps, side: THREE.DoubleSide }
|
|
73
|
+
: { ...safetyZoneMaterialProps, side: THREE.FrontSide }
|
|
74
|
+
|
|
75
|
+
switch (zone.shape.shape_type) {
|
|
76
|
+
/**
|
|
77
|
+
* Plane shape, uses DH parameters to calculate the size of the plane (reach distance of a robot)
|
|
78
|
+
*/
|
|
79
|
+
case "plane":
|
|
80
|
+
geometry = <planeGeometry args={[planeSize, planeSize]} />
|
|
81
|
+
break
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Sphere shape
|
|
85
|
+
*/
|
|
86
|
+
case "sphere": {
|
|
87
|
+
const radius = (zone?.shape as Sphere).radius / 1000
|
|
88
|
+
geometry = <sphereGeometry args={[radius]} />
|
|
89
|
+
break
|
|
90
|
+
}
|
|
107
91
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return sum + (Math.abs(p.a ?? 0) / 1000) + (Math.abs(p.d ?? 0) / 1000)
|
|
118
|
-
}, 0)
|
|
119
|
-
const size = reachRadiusM * 2
|
|
120
|
-
if (!Number.isFinite(size) || size <= 0) {
|
|
121
|
-
return defaultPlaneSize
|
|
122
|
-
}
|
|
123
|
-
return size
|
|
124
|
-
}, [dhParameters])
|
|
92
|
+
/**
|
|
93
|
+
* Capsule shape
|
|
94
|
+
*/
|
|
95
|
+
case "capsule": {
|
|
96
|
+
const capsuleRadius = (zone?.shape as Capsule).radius / 1000
|
|
97
|
+
const height = (zone?.shape as Capsule).cylinder_height / 1000
|
|
98
|
+
geometry = <capsuleGeometry args={[capsuleRadius, height]} />
|
|
99
|
+
break
|
|
100
|
+
}
|
|
125
101
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Convex hull, checks at first if the vertices are coplanar - if yes, adds a small offset for
|
|
104
|
+
* renderer to be able to visualize the convex hull.
|
|
105
|
+
*/
|
|
106
|
+
case "convex_hull": {
|
|
107
|
+
const vertices = (zone?.shape as ConvexHull).vertices.map(
|
|
108
|
+
(v) => new THREE.Vector3(v[0] / 1000, v[1] / 1000, v[2] / 1000),
|
|
109
|
+
)
|
|
110
|
+
// Check if the vertices are on the same plane
|
|
111
|
+
const coplanarityResult = verticesToCoplanarity(vertices)
|
|
112
|
+
if (coplanarityResult.isCoplanar && coplanarityResult.normal) {
|
|
113
|
+
const offset = 0.0001
|
|
114
|
+
const newVertex = new THREE.Vector3().addVectors(
|
|
115
|
+
vertices[0],
|
|
116
|
+
coplanarityResult.normal.multiplyScalar(offset),
|
|
117
|
+
)
|
|
118
|
+
vertices.push(newVertex)
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
geometry = <primitive object={new ConvexGeometry(vertices)} attach="geometry" />
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.log("Error creating ConvexGeometry:", error)
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Convex hull around four spheres. Sphere center points in x/y-plane,
|
|
131
|
+
* offset by either combination "+/- sizeX" or "+/- sizeY".
|
|
132
|
+
* Alternative description: Rectangle in x/y-plane with a 3D padding (source: nova-api docs)
|
|
133
|
+
*
|
|
134
|
+
* Basically a rounded box with a rectangular cross-section.
|
|
135
|
+
*/
|
|
136
|
+
case "rectangular_capsule": {
|
|
137
|
+
const shape = (zone.shape as RectangularCapsule)
|
|
138
|
+
const rcRadius = shape.radius / 1000
|
|
139
|
+
const width = shape.sphere_center_distance_x / 1000
|
|
140
|
+
const height = shape.sphere_center_distance_y / 1000
|
|
141
|
+
const depth = rcRadius * 2
|
|
142
|
+
|
|
143
|
+
geometry = <primitive object={new RoundedBoxGeometry(width, height, depth, 2, rcRadius)} attach="geometry" />
|
|
144
|
+
break
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
default: {
|
|
148
|
+
console.warn("Unsupported safety zone shape type:", zone.shape.shape_type)
|
|
149
|
+
geometry = null
|
|
150
|
+
}
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
return (
|
|
151
154
|
<mesh
|
|
152
|
-
key={`safety-zone
|
|
155
|
+
key={`safety-zone-${zone.shape.shape_type}-${id}`}
|
|
153
156
|
renderOrder={id}
|
|
154
157
|
position={position}
|
|
155
|
-
quaternion={
|
|
158
|
+
quaternion={orientationToQuaternion(orientation)}
|
|
156
159
|
>
|
|
157
|
-
|
|
160
|
+
{geometry}
|
|
158
161
|
<meshStandardMaterial
|
|
159
|
-
|
|
160
|
-
attach="material"
|
|
161
|
-
color="#009f4d"
|
|
162
|
-
opacity={0.2}
|
|
163
|
-
depthTest={false}
|
|
164
|
-
depthWrite={false}
|
|
165
|
-
transparent
|
|
166
|
-
side={THREE.DoubleSide}
|
|
167
|
-
polygonOffset
|
|
162
|
+
{...materialProps}
|
|
168
163
|
polygonOffsetFactor={-id}
|
|
169
164
|
/>
|
|
170
165
|
</mesh>
|
|
@@ -176,20 +171,7 @@ export function SafetyZonesRenderer({
|
|
|
176
171
|
*/
|
|
177
172
|
const renderV2SafetyZones = () => {
|
|
178
173
|
return Object.values(safetyZones ?? {}).map((zone: Collider, index: number) => {
|
|
179
|
-
|
|
180
|
-
case "convex_hull":
|
|
181
|
-
return renderHullMesh(
|
|
182
|
-
(zone.shape as ConvexHull).vertices
|
|
183
|
-
.map((vertex: number[]) => new THREE.Vector3(vertex[0] / 1000, vertex[1] / 1000, vertex[2] / 1000)), index,
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
case "plane":
|
|
187
|
-
return zone?.pose?.position && zone?.pose?.orientation && renderPlaneMesh(
|
|
188
|
-
new THREE.Vector3(zone.pose.position[0] / 1000, zone.pose.position[1] / 1000, zone.pose.position[2] / 1000),
|
|
189
|
-
new THREE.Vector3(zone.pose.orientation[0], zone.pose.orientation[1], zone.pose.orientation[2]),
|
|
190
|
-
index,
|
|
191
|
-
)
|
|
192
|
-
}
|
|
174
|
+
return renderMesh(index, zone)
|
|
193
175
|
})
|
|
194
176
|
}
|
|
195
177
|
|
|
@@ -213,12 +195,20 @@ export function SafetyZonesRenderer({
|
|
|
213
195
|
return geometries.map((geometry, i) => {
|
|
214
196
|
if (!geometry.convex_hull) return null
|
|
215
197
|
|
|
216
|
-
const vertices = geometry.convex_hull.vertices.map(
|
|
217
|
-
(v) => new THREE.Vector3(v.x / 1000, v.y / 1000, v.z / 1000),
|
|
218
|
-
)
|
|
219
|
-
|
|
220
198
|
// Use a per-geometry identifier derived from both zone index and geometry index
|
|
221
|
-
|
|
199
|
+
const id = index * 1000 + i
|
|
200
|
+
// Build a compatible zone object for renderMesh
|
|
201
|
+
const zone: Collider = {
|
|
202
|
+
pose: {
|
|
203
|
+
position: [0, 0, 0],
|
|
204
|
+
orientation: [0, 0, 0],
|
|
205
|
+
},
|
|
206
|
+
shape: {
|
|
207
|
+
shape_type: "convex_hull",
|
|
208
|
+
vertices: geometry.convex_hull.vertices.map((v) => [v.x, v.y, v.z]),
|
|
209
|
+
} as ConvexHull,
|
|
210
|
+
}
|
|
211
|
+
return renderMesh(id, zone)
|
|
222
212
|
})
|
|
223
213
|
})
|
|
224
214
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import * as THREE from "three"
|
|
2
|
+
import type { DHParameter } from "@wandelbots/nova-js/v2"
|
|
3
|
+
|
|
4
|
+
export interface CoplanarityResult {
|
|
5
|
+
isCoplanar: boolean
|
|
6
|
+
normal?: THREE.Vector3
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
export function radiansToDegree(radians: number): number {
|
|
2
10
|
return radians * (180 / Math.PI)
|
|
3
11
|
}
|
|
@@ -21,3 +29,59 @@ export function tryStringifyJson(json: unknown): string | undefined {
|
|
|
21
29
|
return undefined
|
|
22
30
|
}
|
|
23
31
|
}
|
|
32
|
+
|
|
33
|
+
export function orientationToQuaternion(orientation: THREE.Vector3): THREE.Quaternion {
|
|
34
|
+
const angle = orientation.length()
|
|
35
|
+
const quaternion = new THREE.Quaternion()
|
|
36
|
+
if (angle > 1e-6) {
|
|
37
|
+
const axis = orientation.clone().normalize()
|
|
38
|
+
quaternion.setFromAxisAngle(axis, angle)
|
|
39
|
+
}
|
|
40
|
+
return quaternion
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function dhParametersToPlaneSize(dhParameters: DHParameter[]) {
|
|
44
|
+
const defaultPlaneSize = 5
|
|
45
|
+
if (!dhParameters || dhParameters.length === 0) {
|
|
46
|
+
return defaultPlaneSize
|
|
47
|
+
}
|
|
48
|
+
const reachRadiusM = dhParameters.reduce((sum, p) => {
|
|
49
|
+
return sum + (Math.abs(p.a ?? 0) / 1000) + (Math.abs(p.d ?? 0) / 1000)
|
|
50
|
+
}, 0)
|
|
51
|
+
const size = reachRadiusM * 2
|
|
52
|
+
if (!Number.isFinite(size) || size <= 0) {
|
|
53
|
+
return defaultPlaneSize
|
|
54
|
+
}
|
|
55
|
+
return size
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
export function verticesToCoplanarity(vertices: THREE.Vector3[]): CoplanarityResult {
|
|
60
|
+
if (vertices.length < 3) {
|
|
61
|
+
console.log("Not enough vertices to define a plane")
|
|
62
|
+
return { isCoplanar: false }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Convert Vector3d to THREE.Vector3
|
|
66
|
+
const v0 = new THREE.Vector3(vertices[0].x, vertices[0].y, vertices[0].z)
|
|
67
|
+
const v1 = new THREE.Vector3(vertices[1].x, vertices[1].y, vertices[1].z)
|
|
68
|
+
const v2 = new THREE.Vector3(vertices[2].x, vertices[2].y, vertices[2].z)
|
|
69
|
+
|
|
70
|
+
const vector1 = new THREE.Vector3().subVectors(v1, v0)
|
|
71
|
+
const vector2 = new THREE.Vector3().subVectors(v2, v0)
|
|
72
|
+
const normal = new THREE.Vector3().crossVectors(vector1, vector2).normalize()
|
|
73
|
+
|
|
74
|
+
// Check if all remaining vertices lie on the same plane
|
|
75
|
+
for (let i = 3; i < vertices.length; i++) {
|
|
76
|
+
const vi = new THREE.Vector3(vertices[i].x, vertices[i].y, vertices[i].z)
|
|
77
|
+
const vector = new THREE.Vector3().subVectors(vi, v0)
|
|
78
|
+
const dotProduct = normal.dot(vector)
|
|
79
|
+
if (Math.abs(dotProduct) > 1e-6) {
|
|
80
|
+
// Allowing a small tolerance
|
|
81
|
+
console.log("Vertices are not on the same plane")
|
|
82
|
+
return { isCoplanar: false }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { isCoplanar: true, normal }
|
|
87
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingCover-6gWr11KP.js","sources":["../src/components/utils/converters.ts","../src/components/utils/errorHandling.ts","../src/components/LoadingCover.tsx"],"sourcesContent":["export function radiansToDegree(radians: number): number {\n return radians * (180 / Math.PI)\n}\n\nexport function degreesToRadians(degrees: number): number {\n return degrees * (Math.PI / 180)\n}\n\nexport function tryParseJson(json: unknown): any {\n try {\n return JSON.parse(json as string)\n } catch {\n return undefined\n }\n}\n\nexport function tryStringifyJson(json: unknown): string | undefined {\n try {\n return JSON.stringify(json)\n } catch {\n return undefined\n }\n}\n","import { AxiosError } from \"axios\"\nimport { tryStringifyJson } from \"./converters\"\n\n// Please note: These helper functions also exist in nova.js\n// (with slightly different formatting), and will be unified\n// at some point in the future.\n\nexport function delay(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function makeShortErrorMessage(err: unknown) {\n if (err instanceof AxiosError && err.code === \"ERR_NETWORK\") {\n return \"Failed to connect to the server. Please check your internet connection.\"\n } else if (err instanceof AxiosError && err.response) {\n return `${err.response?.status} ${err.response?.statusText}: ${JSON.stringify(err.response?.data)}`\n } else if (err instanceof Error) {\n return err.message\n } else {\n return `Unexpected error: ${err}`\n }\n}\n\nexport function assertUnreachable(x: never, msg: string): never {\n throw new Error(msg + ` ${JSON.stringify(x)}`)\n}\n\nexport function makeErrorMessage(err: unknown) {\n if (err instanceof AxiosError && err.code === \"ERR_NETWORK\") {\n return \"Failed to connect to the server. Please check your internet connection.\"\n } else if (err instanceof AxiosError && err.response) {\n return `${err.response?.status} ${err.response?.statusText} from ${err.response?.config.url}: ${JSON.stringify(err.response?.data)}`\n } else if (err instanceof Error) {\n return err.message\n } else {\n return `Unexpected error: ${tryStringifyJson(err) || err}`\n }\n}\n","import { capitalize, CircularProgress, Stack, useTheme } from \"@mui/material\"\nimport { lowerFirst } from \"lodash-es\"\nimport { useEffect, useState } from \"react\"\nimport { makeErrorMessage } from \"./utils/errorHandling\"\n\nexport const LoadingCover = (props: {\n message?: string\n error?: unknown\n softTimeout?: number\n}) => {\n const softTimeout = props.softTimeout || 3000\n\n const [showSlowLoadingMessage, setShowSlowLoadingMessage] = useState(false)\n const theme = useTheme()\n\n useEffect(() => {\n const timeout = setTimeout(() => {\n setShowSlowLoadingMessage(true)\n }, softTimeout)\n\n return () => clearTimeout(timeout)\n })\n\n return (\n <Stack\n width=\"100%\"\n height=\"100%\"\n alignItems=\"center\"\n justifyContent=\"center\"\n sx={{ color: theme.palette.text.primary }}\n >\n {props.error ? (\n <LoadingErrorMessage\n loadingMessage={props.message}\n error={props.error}\n />\n ) : (\n <>\n <CircularProgress sx={{ marginBottom: \"24px\" }} />\n {!!props.message && <div>{props.message}</div>}\n <Stack\n sx={{\n visibility: showSlowLoadingMessage ? \"visible\" : \"hidden\",\n marginTop: \"1rem\",\n color: theme.palette.text.secondary,\n }}\n >\n {\"This is taking longer than expected...\"}\n </Stack>\n </>\n )}\n </Stack>\n )\n}\n\nexport const LoadingErrorMessage = (props: {\n loadingMessage?: string\n error: unknown\n}) => {\n const errorMessage = makeErrorMessage(props.error)\n const stack = props.error instanceof Error ? props.error.stack : null\n const theme = useTheme()\n\n return (\n <Stack\n sx={{\n maxHeight: \"100%\",\n maxWidth: \"min(100%, 800px)\",\n padding: 2,\n overflow: \"auto\",\n color: theme.palette.error.main,\n \"& pre\": {\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n paddingBottom: \"3rem\",\n },\n }}\n >\n {(props.loadingMessage\n ? `Error while ${lowerFirst(capitalize(props.loadingMessage))} - `\n : \"\") + errorMessage}\n <br />\n {stack && <pre>{stack}</pre>}\n </Stack>\n )\n}\n"],"names":["tryStringifyJson","json","assertUnreachable","x","msg","makeErrorMessage","err","AxiosError","_a","_b","_c","_d","LoadingCover","props","softTimeout","showSlowLoadingMessage","setShowSlowLoadingMessage","useState","theme","useTheme","useEffect","timeout","jsx","Stack","LoadingErrorMessage","jsxs","Fragment","CircularProgress","errorMessage","stack","lowerFirst","capitalize"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const t=require("./externalizeComponent-CkVWk2F_.cjs"),o=require("@mui/material"),l=require("lodash-es"),a=require("react"),c=require("axios");function m(e){try{return JSON.stringify(e)}catch{return}}function g(e,r){throw new Error(r+` ${JSON.stringify(e)}`)}function d(e){var r,s,n,i;return e instanceof c.AxiosError&&e.code==="ERR_NETWORK"?"Failed to connect to the server. Please check your internet connection.":e instanceof c.AxiosError&&e.response?`${(r=e.response)==null?void 0:r.status} ${(s=e.response)==null?void 0:s.statusText} from ${(n=e.response)==null?void 0:n.config.url}: ${JSON.stringify((i=e.response)==null?void 0:i.data)}`:e instanceof Error?e.message:`Unexpected error: ${m(e)||e}`}const h=e=>{const r=e.softTimeout||3e3,[s,n]=a.useState(!1),i=o.useTheme();return a.useEffect(()=>{const x=setTimeout(()=>{n(!0)},r);return()=>clearTimeout(x)}),t.jsxRuntimeExports.jsx(o.Stack,{width:"100%",height:"100%",alignItems:"center",justifyContent:"center",sx:{color:i.palette.text.primary},children:e.error?t.jsxRuntimeExports.jsx(u,{loadingMessage:e.message,error:e.error}):t.jsxRuntimeExports.jsxs(t.jsxRuntimeExports.Fragment,{children:[t.jsxRuntimeExports.jsx(o.CircularProgress,{sx:{marginBottom:"24px"}}),!!e.message&&t.jsxRuntimeExports.jsx("div",{children:e.message}),t.jsxRuntimeExports.jsx(o.Stack,{sx:{visibility:s?"visible":"hidden",marginTop:"1rem",color:i.palette.text.secondary},children:"This is taking longer than expected..."})]})})},u=e=>{const r=d(e.error),s=e.error instanceof Error?e.error.stack:null,n=o.useTheme();return t.jsxRuntimeExports.jsxs(o.Stack,{sx:{maxHeight:"100%",maxWidth:"min(100%, 800px)",padding:2,overflow:"auto",color:n.palette.error.main,"& pre":{whiteSpace:"pre-wrap",wordBreak:"break-word",paddingBottom:"3rem"}},children:[(e.loadingMessage?`Error while ${l.lowerFirst(o.capitalize(e.loadingMessage))} - `:"")+r,t.jsxRuntimeExports.jsx("br",{}),s&&t.jsxRuntimeExports.jsx("pre",{children:s})]})};exports.LoadingCover=h;exports.LoadingErrorMessage=u;exports.assertUnreachable=g;
|
|
2
|
-
//# sourceMappingURL=LoadingCover-CukpS_aj.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingCover-CukpS_aj.cjs","sources":["../src/components/utils/converters.ts","../src/components/utils/errorHandling.ts","../src/components/LoadingCover.tsx"],"sourcesContent":["export function radiansToDegree(radians: number): number {\n return radians * (180 / Math.PI)\n}\n\nexport function degreesToRadians(degrees: number): number {\n return degrees * (Math.PI / 180)\n}\n\nexport function tryParseJson(json: unknown): any {\n try {\n return JSON.parse(json as string)\n } catch {\n return undefined\n }\n}\n\nexport function tryStringifyJson(json: unknown): string | undefined {\n try {\n return JSON.stringify(json)\n } catch {\n return undefined\n }\n}\n","import { AxiosError } from \"axios\"\nimport { tryStringifyJson } from \"./converters\"\n\n// Please note: These helper functions also exist in nova.js\n// (with slightly different formatting), and will be unified\n// at some point in the future.\n\nexport function delay(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function makeShortErrorMessage(err: unknown) {\n if (err instanceof AxiosError && err.code === \"ERR_NETWORK\") {\n return \"Failed to connect to the server. Please check your internet connection.\"\n } else if (err instanceof AxiosError && err.response) {\n return `${err.response?.status} ${err.response?.statusText}: ${JSON.stringify(err.response?.data)}`\n } else if (err instanceof Error) {\n return err.message\n } else {\n return `Unexpected error: ${err}`\n }\n}\n\nexport function assertUnreachable(x: never, msg: string): never {\n throw new Error(msg + ` ${JSON.stringify(x)}`)\n}\n\nexport function makeErrorMessage(err: unknown) {\n if (err instanceof AxiosError && err.code === \"ERR_NETWORK\") {\n return \"Failed to connect to the server. Please check your internet connection.\"\n } else if (err instanceof AxiosError && err.response) {\n return `${err.response?.status} ${err.response?.statusText} from ${err.response?.config.url}: ${JSON.stringify(err.response?.data)}`\n } else if (err instanceof Error) {\n return err.message\n } else {\n return `Unexpected error: ${tryStringifyJson(err) || err}`\n }\n}\n","import { capitalize, CircularProgress, Stack, useTheme } from \"@mui/material\"\nimport { lowerFirst } from \"lodash-es\"\nimport { useEffect, useState } from \"react\"\nimport { makeErrorMessage } from \"./utils/errorHandling\"\n\nexport const LoadingCover = (props: {\n message?: string\n error?: unknown\n softTimeout?: number\n}) => {\n const softTimeout = props.softTimeout || 3000\n\n const [showSlowLoadingMessage, setShowSlowLoadingMessage] = useState(false)\n const theme = useTheme()\n\n useEffect(() => {\n const timeout = setTimeout(() => {\n setShowSlowLoadingMessage(true)\n }, softTimeout)\n\n return () => clearTimeout(timeout)\n })\n\n return (\n <Stack\n width=\"100%\"\n height=\"100%\"\n alignItems=\"center\"\n justifyContent=\"center\"\n sx={{ color: theme.palette.text.primary }}\n >\n {props.error ? (\n <LoadingErrorMessage\n loadingMessage={props.message}\n error={props.error}\n />\n ) : (\n <>\n <CircularProgress sx={{ marginBottom: \"24px\" }} />\n {!!props.message && <div>{props.message}</div>}\n <Stack\n sx={{\n visibility: showSlowLoadingMessage ? \"visible\" : \"hidden\",\n marginTop: \"1rem\",\n color: theme.palette.text.secondary,\n }}\n >\n {\"This is taking longer than expected...\"}\n </Stack>\n </>\n )}\n </Stack>\n )\n}\n\nexport const LoadingErrorMessage = (props: {\n loadingMessage?: string\n error: unknown\n}) => {\n const errorMessage = makeErrorMessage(props.error)\n const stack = props.error instanceof Error ? props.error.stack : null\n const theme = useTheme()\n\n return (\n <Stack\n sx={{\n maxHeight: \"100%\",\n maxWidth: \"min(100%, 800px)\",\n padding: 2,\n overflow: \"auto\",\n color: theme.palette.error.main,\n \"& pre\": {\n whiteSpace: \"pre-wrap\",\n wordBreak: \"break-word\",\n paddingBottom: \"3rem\",\n },\n }}\n >\n {(props.loadingMessage\n ? `Error while ${lowerFirst(capitalize(props.loadingMessage))} - `\n : \"\") + errorMessage}\n <br />\n {stack && <pre>{stack}</pre>}\n </Stack>\n )\n}\n"],"names":["tryStringifyJson","json","assertUnreachable","x","msg","makeErrorMessage","err","AxiosError","_a","_b","_c","_d","LoadingCover","props","softTimeout","showSlowLoadingMessage","setShowSlowLoadingMessage","useState","theme","useTheme","useEffect","timeout","jsx","Stack","LoadingErrorMessage","jsxs","Fragment","CircularProgress","errorMessage","stack","lowerFirst","capitalize"],"mappings":"4JAgBO,SAASA,EAAiBC,EAAmC,CAClE,GAAI,CACF,OAAO,KAAK,UAAUA,CAAI,CAC5B,MAAQ,CACN,MACF,CACF,CCCO,SAASC,EAAkBC,EAAUC,EAAoB,CAC9D,MAAM,IAAI,MAAMA,EAAM,IAAI,KAAK,UAAUD,CAAC,CAAC,EAAE,CAC/C,CAEO,SAASE,EAAiBC,EAAc,aAC7C,OAAIA,aAAeC,EAAAA,YAAcD,EAAI,OAAS,cACrC,0EACEA,aAAeC,cAAcD,EAAI,SACnC,IAAGE,EAAAF,EAAI,WAAJ,YAAAE,EAAc,MAAM,KAAIC,EAAAH,EAAI,WAAJ,YAAAG,EAAc,UAAU,UAASC,EAAAJ,EAAI,WAAJ,YAAAI,EAAc,OAAO,GAAG,KAAK,KAAK,WAAUC,EAAAL,EAAI,WAAJ,YAAAK,EAAc,IAAI,CAAC,GACzHL,aAAe,MACjBA,EAAI,QAEJ,qBAAqBN,EAAiBM,CAAG,GAAKA,CAAG,EAE5D,CChCO,MAAMM,EAAgBC,GAIvB,CACJ,MAAMC,EAAcD,EAAM,aAAe,IAEnC,CAACE,EAAwBC,CAAyB,EAAIC,EAAAA,SAAS,EAAK,EACpEC,EAAQC,EAAAA,SAAA,EAEdC,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAU,WAAW,IAAM,CAC/BL,EAA0B,EAAI,CAChC,EAAGF,CAAW,EAEd,MAAO,IAAM,aAAaO,CAAO,CACnC,CAAC,EAGCC,EAAAA,kBAAAA,IAACC,EAAAA,MAAA,CACC,MAAM,OACN,OAAO,OACP,WAAW,SACX,eAAe,SACf,GAAI,CAAE,MAAOL,EAAM,QAAQ,KAAK,OAAA,EAE/B,WAAM,MACLI,EAAAA,kBAAAA,IAACE,EAAA,CACC,eAAgBX,EAAM,QACtB,MAAOA,EAAM,KAAA,CAAA,EAGfY,EAAAA,kBAAAA,KAAAC,6BAAA,CACE,SAAA,CAAAJ,EAAAA,kBAAAA,IAACK,EAAAA,iBAAA,CAAiB,GAAI,CAAE,aAAc,QAAU,EAC/C,CAAC,CAACd,EAAM,SAAWS,EAAAA,kBAAAA,IAAC,MAAA,CAAK,WAAM,QAAQ,EACxCA,EAAAA,kBAAAA,IAACC,EAAAA,MAAA,CACC,GAAI,CACF,WAAYR,EAAyB,UAAY,SACjD,UAAW,OACX,MAAOG,EAAM,QAAQ,KAAK,SAAA,EAG3B,SAAA,wCAAA,CAAA,CACH,CAAA,CACF,CAAA,CAAA,CAIR,EAEaM,EAAuBX,GAG9B,CACJ,MAAMe,EAAevB,EAAiBQ,EAAM,KAAK,EAC3CgB,EAAQhB,EAAM,iBAAiB,MAAQA,EAAM,MAAM,MAAQ,KAC3DK,EAAQC,EAAAA,SAAA,EAEd,OACEM,EAAAA,kBAAAA,KAACF,EAAAA,MAAA,CACC,GAAI,CACF,UAAW,OACX,SAAU,mBACV,QAAS,EACT,SAAU,OACV,MAAOL,EAAM,QAAQ,MAAM,KAC3B,QAAS,CACP,WAAY,WACZ,UAAW,aACX,cAAe,MAAA,CACjB,EAGA,SAAA,EAAAL,EAAM,eACJ,eAAeiB,EAAAA,WAAWC,EAAAA,WAAWlB,EAAM,cAAc,CAAC,CAAC,MAC3D,IAAMe,0BACT,KAAA,EAAG,EACHC,GAASP,EAAAA,kBAAAA,IAAC,MAAA,CAAK,SAAAO,CAAA,CAAM,CAAA,CAAA,CAAA,CAG5B"}
|