@toolpath/viewer 2.2.0 → 2.3.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/README.md +110 -43
- package/dist/{chunk-WTTOUG4P.js → chunk-N54FHMTG.js} +1023 -313
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +7 -205
- package/dist/index.js +155 -108
- package/dist/{normalize--FiXUhO4.d.ts → normalize-C4Wj4IGK.d.ts} +333 -3
- package/package.json +1 -1
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// src/engine/engine-part.tsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect8, useMemo as useMemo8 } from "react";
|
|
3
3
|
|
|
4
4
|
// src/part-mesh.tsx
|
|
5
|
-
import { useThree as
|
|
5
|
+
import { useThree as useThree8 } from "@react-three/fiber";
|
|
6
6
|
import {
|
|
7
7
|
useCallback as useCallback3,
|
|
8
|
-
useEffect as
|
|
9
|
-
useLayoutEffect as
|
|
10
|
-
useMemo as
|
|
8
|
+
useEffect as useEffect7,
|
|
9
|
+
useLayoutEffect as useLayoutEffect3,
|
|
10
|
+
useMemo as useMemo7,
|
|
11
11
|
useRef as useRef6,
|
|
12
12
|
useSyncExternalStore
|
|
13
13
|
} from "react";
|
|
14
|
-
import { Vector3 as
|
|
14
|
+
import { Vector3 as Vector312 } from "three";
|
|
15
15
|
|
|
16
16
|
// src/part-context.tsx
|
|
17
17
|
import { createContext, useContext } from "react";
|
|
@@ -136,6 +136,8 @@ var DEFAULT_THEME = {
|
|
|
136
136
|
picked: 16347926,
|
|
137
137
|
edge: 0,
|
|
138
138
|
edgeOpacity: 0.5,
|
|
139
|
+
// Red, which the direction palette's note keeps free for sharp corners.
|
|
140
|
+
sharpCorner: 14427686,
|
|
139
141
|
sectionCap: 14672618,
|
|
140
142
|
sectionHatch: 9080998,
|
|
141
143
|
sectionOutline: 7057587,
|
|
@@ -157,7 +159,7 @@ function resolveTheme(overrides) {
|
|
|
157
159
|
return { ...DEFAULT_THEME, ...overrides };
|
|
158
160
|
}
|
|
159
161
|
function themesEqual(a, b) {
|
|
160
|
-
return a.background === b.background && a.hemisphereSky === b.hemisphereSky && a.hemisphereGround === b.hemisphereGround && a.hemisphereIntensity === b.hemisphereIntensity && a.ambient === b.ambient && a.ambientIntensity === b.ambientIntensity && a.part === b.part && a.partEmissive === b.partEmissive && a.hover === b.hover && a.highlight === b.highlight && a.picked === b.picked && a.edge === b.edge && a.edgeOpacity === b.edgeOpacity && a.sectionCap === b.sectionCap && a.sectionHatch === b.sectionHatch && a.sectionOutline === b.sectionOutline && a.sectionHandle === b.sectionHandle && a.sectionHandleOutline === b.sectionHandleOutline && a.measure === b.measure && a.measureSnap === b.measureSnap && a.cube === b.cube && a.cubeEdge === b.cubeEdge && a.cubeLabel === b.cubeLabel;
|
|
162
|
+
return a.background === b.background && a.hemisphereSky === b.hemisphereSky && a.hemisphereGround === b.hemisphereGround && a.hemisphereIntensity === b.hemisphereIntensity && a.ambient === b.ambient && a.ambientIntensity === b.ambientIntensity && a.part === b.part && a.partEmissive === b.partEmissive && a.hover === b.hover && a.highlight === b.highlight && a.picked === b.picked && a.edge === b.edge && a.edgeOpacity === b.edgeOpacity && a.sharpCorner === b.sharpCorner && a.sectionCap === b.sectionCap && a.sectionHatch === b.sectionHatch && a.sectionOutline === b.sectionOutline && a.sectionHandle === b.sectionHandle && a.sectionHandleOutline === b.sectionHandleOutline && a.measure === b.measure && a.measureSnap === b.measureSnap && a.cube === b.cube && a.cubeEdge === b.cubeEdge && a.cubeLabel === b.cubeLabel;
|
|
161
163
|
}
|
|
162
164
|
function directionColor(index) {
|
|
163
165
|
const wrapped = index % DIRECTION_COLORS.length;
|
|
@@ -857,19 +859,19 @@ function useTapGuard() {
|
|
|
857
859
|
// src/render/part.ts
|
|
858
860
|
import {
|
|
859
861
|
Box3,
|
|
860
|
-
Color,
|
|
862
|
+
Color as Color2,
|
|
861
863
|
DataTexture,
|
|
862
|
-
DoubleSide,
|
|
863
|
-
Float32BufferAttribute as
|
|
864
|
-
Group,
|
|
864
|
+
DoubleSide as DoubleSide2,
|
|
865
|
+
Float32BufferAttribute as Float32BufferAttribute3,
|
|
866
|
+
Group as Group2,
|
|
865
867
|
LineBasicMaterial,
|
|
866
868
|
LineSegments,
|
|
867
|
-
Mesh,
|
|
869
|
+
Mesh as Mesh2,
|
|
868
870
|
MeshLambertMaterial,
|
|
869
871
|
RedFormat,
|
|
870
872
|
RGBAFormat,
|
|
871
873
|
UnsignedByteType,
|
|
872
|
-
Vector3 as
|
|
874
|
+
Vector3 as Vector35
|
|
873
875
|
} from "three";
|
|
874
876
|
|
|
875
877
|
// src/render/edges.ts
|
|
@@ -937,6 +939,555 @@ function regionEdgesGeometry(geometry, model) {
|
|
|
937
939
|
return edges;
|
|
938
940
|
}
|
|
939
941
|
|
|
942
|
+
// src/render/sharp-corners.ts
|
|
943
|
+
import {
|
|
944
|
+
BufferAttribute,
|
|
945
|
+
BufferGeometry,
|
|
946
|
+
Color,
|
|
947
|
+
DoubleSide,
|
|
948
|
+
Float32BufferAttribute as Float32BufferAttribute2,
|
|
949
|
+
GreaterDepth,
|
|
950
|
+
Group,
|
|
951
|
+
KeepStencilOp,
|
|
952
|
+
LessEqualDepth,
|
|
953
|
+
Mesh,
|
|
954
|
+
MeshBasicMaterial,
|
|
955
|
+
NotEqualStencilFunc,
|
|
956
|
+
ReplaceStencilOp,
|
|
957
|
+
ShaderMaterial,
|
|
958
|
+
Vector2 as Vector22,
|
|
959
|
+
Vector3 as Vector34,
|
|
960
|
+
Vector4
|
|
961
|
+
} from "three";
|
|
962
|
+
|
|
963
|
+
// src/render/adjacency.ts
|
|
964
|
+
var GRID = 1e-4;
|
|
965
|
+
var keyFor = (x, y, z) => `${Math.round(x / GRID)},${Math.round(y / GRID)},${Math.round(z / GRID)}`;
|
|
966
|
+
function regionAdjacency(model, geometry) {
|
|
967
|
+
const position = geometry.getAttribute("position");
|
|
968
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
969
|
+
if (!position) return adjacency;
|
|
970
|
+
const owner = new Int32Array(Math.floor(position.count / 3)).fill(-1);
|
|
971
|
+
for (const region of model.regions) {
|
|
972
|
+
for (let at = region.triangles.start; at < region.triangles.end; at++) {
|
|
973
|
+
if (at >= 0 && at < owner.length) owner[at] = region.idx;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
const edges = /* @__PURE__ */ new Map();
|
|
977
|
+
const join = (a, b) => {
|
|
978
|
+
if (a === b) return;
|
|
979
|
+
const mine = adjacency.get(a) ?? /* @__PURE__ */ new Set();
|
|
980
|
+
mine.add(b);
|
|
981
|
+
adjacency.set(a, mine);
|
|
982
|
+
const theirs = adjacency.get(b) ?? /* @__PURE__ */ new Set();
|
|
983
|
+
theirs.add(a);
|
|
984
|
+
adjacency.set(b, theirs);
|
|
985
|
+
};
|
|
986
|
+
for (let triangle = 0; triangle < owner.length; triangle++) {
|
|
987
|
+
const region = owner[triangle];
|
|
988
|
+
if (region === -1) continue;
|
|
989
|
+
const corners = [0, 1, 2].map((corner) => {
|
|
990
|
+
const at = triangle * 3 + corner;
|
|
991
|
+
return keyFor(position.getX(at), position.getY(at), position.getZ(at));
|
|
992
|
+
});
|
|
993
|
+
for (let corner = 0; corner < 3; corner++) {
|
|
994
|
+
const from = corners[corner];
|
|
995
|
+
const to = corners[(corner + 1) % 3];
|
|
996
|
+
const edge = from < to ? `${from}|${to}` : `${to}|${from}`;
|
|
997
|
+
const seen = edges.get(edge);
|
|
998
|
+
if (seen === void 0) edges.set(edge, region);
|
|
999
|
+
else join(seen, region);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return adjacency;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/render/sharp-corners.ts
|
|
1006
|
+
var MIN_FOLD_DEGREES = 20;
|
|
1007
|
+
var ALONG_TOLERANCE_DEGREES = 15;
|
|
1008
|
+
var BAND_WIDTH = 6;
|
|
1009
|
+
var NEAR_OPACITY = 1;
|
|
1010
|
+
var FAR_OPACITY = 0.35;
|
|
1011
|
+
var DEGREES = 180 / Math.PI;
|
|
1012
|
+
function surfaceCreases(geometry, model) {
|
|
1013
|
+
const position = geometry.getAttribute("position");
|
|
1014
|
+
if (!position || geometry.index) return emptyCreases();
|
|
1015
|
+
const triangleCount = Math.floor(position.count / 3);
|
|
1016
|
+
const surfaces = visualSurfaces(model.regions);
|
|
1017
|
+
const surfaceOf = new Int32Array(triangleCount).fill(-1);
|
|
1018
|
+
const regionOf = new Int32Array(triangleCount).fill(-1);
|
|
1019
|
+
for (const region of model.regions) {
|
|
1020
|
+
const end = Math.min(region.triangles.end, triangleCount);
|
|
1021
|
+
for (let triangle = Math.max(region.triangles.start, 0); triangle < end; triangle += 1) {
|
|
1022
|
+
surfaceOf[triangle] = surfaces.get(region.idx) ?? region.idx;
|
|
1023
|
+
regionOf[triangle] = region.idx;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
const normals = new Float32Array(triangleCount * 3);
|
|
1027
|
+
for (let triangle = 0; triangle < triangleCount; triangle += 1) {
|
|
1028
|
+
const at = triangle * 3;
|
|
1029
|
+
const ax = position.getX(at);
|
|
1030
|
+
const ay = position.getY(at);
|
|
1031
|
+
const az = position.getZ(at);
|
|
1032
|
+
const ux = position.getX(at + 1) - ax;
|
|
1033
|
+
const uy = position.getY(at + 1) - ay;
|
|
1034
|
+
const uz = position.getZ(at + 1) - az;
|
|
1035
|
+
const vx = position.getX(at + 2) - ax;
|
|
1036
|
+
const vy = position.getY(at + 2) - ay;
|
|
1037
|
+
const vz = position.getZ(at + 2) - az;
|
|
1038
|
+
const nx = uy * vz - uz * vy;
|
|
1039
|
+
const ny = uz * vx - ux * vz;
|
|
1040
|
+
const nz = ux * vy - uy * vx;
|
|
1041
|
+
const length = Math.hypot(nx, ny, nz);
|
|
1042
|
+
if (length === 0) continue;
|
|
1043
|
+
normals[at] = nx / length;
|
|
1044
|
+
normals[at + 1] = ny / length;
|
|
1045
|
+
normals[at + 2] = nz / length;
|
|
1046
|
+
}
|
|
1047
|
+
const keyOf = (vertex) => keyFor(position.getX(vertex), position.getY(vertex), position.getZ(vertex));
|
|
1048
|
+
const open = /* @__PURE__ */ new Map();
|
|
1049
|
+
const positions = [];
|
|
1050
|
+
const angles = [];
|
|
1051
|
+
const concave = [];
|
|
1052
|
+
const regions = [];
|
|
1053
|
+
const fars = [];
|
|
1054
|
+
const inFront = (triangle, vertex, on) => normals[triangle * 3] * (position.getX(vertex) - position.getX(on)) + normals[triangle * 3 + 1] * (position.getY(vertex) - position.getY(on)) + normals[triangle * 3 + 2] * (position.getZ(vertex) - position.getZ(on));
|
|
1055
|
+
const measure = (first, second) => {
|
|
1056
|
+
const t1 = Math.floor(first / 3);
|
|
1057
|
+
const t2 = Math.floor(second / 3);
|
|
1058
|
+
if (surfaceOf[t1] === surfaceOf[t2]) return;
|
|
1059
|
+
if (normals[t1 * 3] === 0 && normals[t1 * 3 + 1] === 0 && normals[t1 * 3 + 2] === 0) return;
|
|
1060
|
+
if (normals[t2 * 3] === 0 && normals[t2 * 3 + 1] === 0 && normals[t2 * 3 + 2] === 0) return;
|
|
1061
|
+
const dot2 = normals[t1 * 3] * normals[t2 * 3] + normals[t1 * 3 + 1] * normals[t2 * 3 + 1] + normals[t1 * 3 + 2] * normals[t2 * 3 + 2];
|
|
1062
|
+
const a = t1 * 3 + first % 3;
|
|
1063
|
+
const b = t1 * 3 + (first + 1) % 3;
|
|
1064
|
+
const far1 = t1 * 3 + (first + 2) % 3;
|
|
1065
|
+
const far2 = t2 * 3 + (second + 2) % 3;
|
|
1066
|
+
const fold = inFront(t1, far2, a) + inFront(t2, far1, a);
|
|
1067
|
+
positions.push(
|
|
1068
|
+
position.getX(a),
|
|
1069
|
+
position.getY(a),
|
|
1070
|
+
position.getZ(a),
|
|
1071
|
+
position.getX(b),
|
|
1072
|
+
position.getY(b),
|
|
1073
|
+
position.getZ(b)
|
|
1074
|
+
);
|
|
1075
|
+
angles.push(Math.acos(Math.min(1, Math.max(-1, dot2))) * DEGREES);
|
|
1076
|
+
concave.push(fold > 0 ? 1 : 0);
|
|
1077
|
+
regions.push(regionOf[t1], regionOf[t2]);
|
|
1078
|
+
fars.push(
|
|
1079
|
+
position.getX(far1),
|
|
1080
|
+
position.getY(far1),
|
|
1081
|
+
position.getZ(far1),
|
|
1082
|
+
position.getX(far2),
|
|
1083
|
+
position.getY(far2),
|
|
1084
|
+
position.getZ(far2)
|
|
1085
|
+
);
|
|
1086
|
+
};
|
|
1087
|
+
for (let triangle = 0; triangle < triangleCount; triangle += 1) {
|
|
1088
|
+
const keys = [keyOf(triangle * 3), keyOf(triangle * 3 + 1), keyOf(triangle * 3 + 2)];
|
|
1089
|
+
for (let corner = 0; corner < 3; corner += 1) {
|
|
1090
|
+
const from = keys[corner];
|
|
1091
|
+
const to = keys[(corner + 1) % 3];
|
|
1092
|
+
if (from === to) continue;
|
|
1093
|
+
const edge = from < to ? `${from}|${to}` : `${to}|${from}`;
|
|
1094
|
+
const seen = open.get(edge);
|
|
1095
|
+
if (seen === void 0) open.set(edge, triangle * 3 + corner);
|
|
1096
|
+
else if (seen !== -1) {
|
|
1097
|
+
measure(seen, triangle * 3 + corner);
|
|
1098
|
+
open.set(edge, -1);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
return {
|
|
1103
|
+
count: angles.length,
|
|
1104
|
+
positions: new Float32Array(positions),
|
|
1105
|
+
angles: new Float32Array(angles),
|
|
1106
|
+
concave: new Uint8Array(concave),
|
|
1107
|
+
regions: new Int32Array(regions),
|
|
1108
|
+
fars: new Float32Array(fars)
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function sharpCornerKey(options) {
|
|
1112
|
+
return options.features.map((tag) => tag.toLowerCase()).sort().join(",");
|
|
1113
|
+
}
|
|
1114
|
+
function findSharpCorners(creases, model, options) {
|
|
1115
|
+
const alongCos = Math.cos(ALONG_TOLERANCE_DEGREES / DEGREES);
|
|
1116
|
+
const flagged = new Set(options.features.map((tag) => tag.toLowerCase()));
|
|
1117
|
+
const owners = /* @__PURE__ */ new Map();
|
|
1118
|
+
for (const feature of model.features) {
|
|
1119
|
+
if (!flagged.has(feature.tag.toLowerCase())) continue;
|
|
1120
|
+
const axis = unit2(feature.machiningDirection);
|
|
1121
|
+
if (!axis) continue;
|
|
1122
|
+
for (const region of model.regionIndex.regionsForFeature(feature.tag)) {
|
|
1123
|
+
const held = owners.get(region);
|
|
1124
|
+
if (held) held.push({ tag: feature.tag, axis });
|
|
1125
|
+
else owners.set(region, [{ tag: feature.tag, axis }]);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
if (owners.size === 0) return [];
|
|
1129
|
+
const { positions } = creases;
|
|
1130
|
+
const kept = [];
|
|
1131
|
+
for (let segment = 0; segment < creases.count; segment += 1) {
|
|
1132
|
+
if (creases.concave[segment] !== 1 || creases.angles[segment] < MIN_FOLD_DEGREES) continue;
|
|
1133
|
+
const candidates = [
|
|
1134
|
+
...owners.get(creases.regions[segment * 2]) ?? [],
|
|
1135
|
+
...owners.get(creases.regions[segment * 2 + 1]) ?? []
|
|
1136
|
+
];
|
|
1137
|
+
if (candidates.length === 0) continue;
|
|
1138
|
+
const at = segment * 6;
|
|
1139
|
+
const dx = positions[at + 3] - positions[at];
|
|
1140
|
+
const dy = positions[at + 4] - positions[at + 1];
|
|
1141
|
+
const dz = positions[at + 5] - positions[at + 2];
|
|
1142
|
+
const length = Math.hypot(dx, dy, dz);
|
|
1143
|
+
if (length === 0) continue;
|
|
1144
|
+
const owner = candidates.find(
|
|
1145
|
+
({ axis }) => Math.abs(dx * axis.x + dy * axis.y + dz * axis.z) / length >= alongCos
|
|
1146
|
+
);
|
|
1147
|
+
if (owner) kept.push({ segment, feature: owner.tag });
|
|
1148
|
+
}
|
|
1149
|
+
const keyOf = (at) => keyFor(positions[at], positions[at + 1], positions[at + 2]);
|
|
1150
|
+
const parent = kept.map((_, at) => at);
|
|
1151
|
+
const root = (at) => {
|
|
1152
|
+
while (parent[at] !== at) at = parent[at] = parent[parent[at]];
|
|
1153
|
+
return at;
|
|
1154
|
+
};
|
|
1155
|
+
const byEnd = /* @__PURE__ */ new Map();
|
|
1156
|
+
kept.forEach(({ segment, feature }, at) => {
|
|
1157
|
+
for (const end of [segment * 6, segment * 6 + 3]) {
|
|
1158
|
+
const key = `${feature.toLowerCase()}|${keyOf(end)}`;
|
|
1159
|
+
const other = byEnd.get(key);
|
|
1160
|
+
if (other === void 0) byEnd.set(key, at);
|
|
1161
|
+
else parent[root(at)] = root(other);
|
|
1162
|
+
}
|
|
1163
|
+
});
|
|
1164
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1165
|
+
kept.forEach((_, at) => {
|
|
1166
|
+
const group = groups.get(root(at));
|
|
1167
|
+
if (group) group.push(at);
|
|
1168
|
+
else groups.set(root(at), [at]);
|
|
1169
|
+
});
|
|
1170
|
+
return [...groups.values()].map((members, index) => {
|
|
1171
|
+
const feature = kept[members[0]].feature;
|
|
1172
|
+
const segments = members.map((at) => kept[at].segment);
|
|
1173
|
+
const first = segments[0] * 6;
|
|
1174
|
+
const axis = unit2({
|
|
1175
|
+
x: positions[first + 3] - positions[first],
|
|
1176
|
+
y: positions[first + 4] - positions[first + 1],
|
|
1177
|
+
z: positions[first + 5] - positions[first + 2]
|
|
1178
|
+
});
|
|
1179
|
+
let start = null;
|
|
1180
|
+
let end = null;
|
|
1181
|
+
let low = Infinity;
|
|
1182
|
+
let high = -Infinity;
|
|
1183
|
+
let length = 0;
|
|
1184
|
+
let folded = 0;
|
|
1185
|
+
const regions = /* @__PURE__ */ new Set();
|
|
1186
|
+
for (const segment of segments) {
|
|
1187
|
+
const at = segment * 6;
|
|
1188
|
+
for (const point of [at, at + 3]) {
|
|
1189
|
+
const p = { x: positions[point], y: positions[point + 1], z: positions[point + 2] };
|
|
1190
|
+
const along = p.x * axis.x + p.y * axis.y + p.z * axis.z;
|
|
1191
|
+
if (along < low) [low, start] = [along, p];
|
|
1192
|
+
if (along > high) [high, end] = [along, p];
|
|
1193
|
+
}
|
|
1194
|
+
const run = Math.hypot(
|
|
1195
|
+
positions[at + 3] - positions[at],
|
|
1196
|
+
positions[at + 4] - positions[at + 1],
|
|
1197
|
+
positions[at + 5] - positions[at + 2]
|
|
1198
|
+
);
|
|
1199
|
+
length += run;
|
|
1200
|
+
folded += run * creases.angles[segment];
|
|
1201
|
+
regions.add(creases.regions[segment * 2]);
|
|
1202
|
+
regions.add(creases.regions[segment * 2 + 1]);
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
index,
|
|
1206
|
+
feature,
|
|
1207
|
+
start,
|
|
1208
|
+
end,
|
|
1209
|
+
length,
|
|
1210
|
+
// The normals turn by the fold; the faces themselves open by what is left of 180°.
|
|
1211
|
+
angle: 180 - folded / length,
|
|
1212
|
+
regions: [...regions],
|
|
1213
|
+
segments
|
|
1214
|
+
};
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
function sharpCornerPositions(creases, model, options) {
|
|
1218
|
+
const segments = findSharpCorners(creases, model, options).flatMap((corner) => corner.segments);
|
|
1219
|
+
const positions = new Float32Array(segments.length * 6);
|
|
1220
|
+
segments.forEach(
|
|
1221
|
+
(segment, at) => positions.set(creases.positions.subarray(segment * 6, segment * 6 + 6), at * 6)
|
|
1222
|
+
);
|
|
1223
|
+
return positions;
|
|
1224
|
+
}
|
|
1225
|
+
var SHARP_CORNER_HOVER_PIXELS = 6;
|
|
1226
|
+
function sharpCornerAt(corners, creases, hit, camera, viewport, matrixWorld) {
|
|
1227
|
+
const pointer = screenPoint(camera, hit.point, viewport);
|
|
1228
|
+
const a = new Vector34();
|
|
1229
|
+
const b = new Vector34();
|
|
1230
|
+
const from = new Vector22();
|
|
1231
|
+
const to = new Vector22();
|
|
1232
|
+
let nearest = null;
|
|
1233
|
+
let reach = SHARP_CORNER_HOVER_PIXELS;
|
|
1234
|
+
for (const corner of corners) {
|
|
1235
|
+
if (!corner.regions.includes(hit.region)) continue;
|
|
1236
|
+
for (const segment of corner.segments) {
|
|
1237
|
+
a.fromArray(creases.positions, segment * 6).applyMatrix4(matrixWorld);
|
|
1238
|
+
b.fromArray(creases.positions, segment * 6 + 3).applyMatrix4(matrixWorld);
|
|
1239
|
+
screenPoint(camera, a, viewport, from);
|
|
1240
|
+
screenPoint(camera, b, viewport, to);
|
|
1241
|
+
const distance = distanceToSegment(pointer, from, to);
|
|
1242
|
+
if (distance <= reach) [reach, nearest] = [distance, corner];
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
return nearest;
|
|
1246
|
+
}
|
|
1247
|
+
function distanceToSegment(point, from, to) {
|
|
1248
|
+
const dx = to.x - from.x;
|
|
1249
|
+
const dy = to.y - from.y;
|
|
1250
|
+
const span = dx * dx + dy * dy;
|
|
1251
|
+
const t = span === 0 ? 0 : Math.min(1, Math.max(0, ((point.x - from.x) * dx + (point.y - from.y) * dy) / span));
|
|
1252
|
+
return Math.hypot(point.x - (from.x + t * dx), point.y - (from.y + t * dy));
|
|
1253
|
+
}
|
|
1254
|
+
function sharpCornerBands(creases, corners) {
|
|
1255
|
+
const position = [];
|
|
1256
|
+
const perp = [];
|
|
1257
|
+
const side = [];
|
|
1258
|
+
const reach = [];
|
|
1259
|
+
const owner = [];
|
|
1260
|
+
const index = [];
|
|
1261
|
+
for (const { index: corner, segments } of corners) {
|
|
1262
|
+
for (const segment of segments) {
|
|
1263
|
+
const at = segment * 6;
|
|
1264
|
+
const a = [creases.positions[at], creases.positions[at + 1], creases.positions[at + 2]];
|
|
1265
|
+
const b = [creases.positions[at + 3], creases.positions[at + 4], creases.positions[at + 5]];
|
|
1266
|
+
const edge = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
1267
|
+
const length = Math.hypot(edge[0], edge[1], edge[2]);
|
|
1268
|
+
if (length === 0) continue;
|
|
1269
|
+
const along = edge.map((value) => value / length);
|
|
1270
|
+
for (let face = 0; face < 2; face += 1) {
|
|
1271
|
+
const far = at + face * 3;
|
|
1272
|
+
const v = [
|
|
1273
|
+
creases.fars[far] - a[0],
|
|
1274
|
+
creases.fars[far + 1] - a[1],
|
|
1275
|
+
creases.fars[far + 2] - a[2]
|
|
1276
|
+
];
|
|
1277
|
+
const t = v[0] * along[0] + v[1] * along[1] + v[2] * along[2];
|
|
1278
|
+
const across = [v[0] - t * along[0], v[1] - t * along[1], v[2] - t * along[2]];
|
|
1279
|
+
const extent = Math.hypot(across[0], across[1], across[2]);
|
|
1280
|
+
if (extent === 0) continue;
|
|
1281
|
+
const first = position.length / 3;
|
|
1282
|
+
for (const [point, out] of [
|
|
1283
|
+
[a, 0],
|
|
1284
|
+
[b, 0],
|
|
1285
|
+
[a, 1],
|
|
1286
|
+
[b, 1]
|
|
1287
|
+
]) {
|
|
1288
|
+
position.push(point[0], point[1], point[2]);
|
|
1289
|
+
perp.push(across[0] / extent, across[1] / extent, across[2] / extent);
|
|
1290
|
+
side.push(out);
|
|
1291
|
+
reach.push(extent);
|
|
1292
|
+
owner.push(corner);
|
|
1293
|
+
}
|
|
1294
|
+
index.push(first, first + 1, first + 3, first, first + 3, first + 2);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
const geometry = new BufferGeometry();
|
|
1299
|
+
geometry.setAttribute("position", new Float32BufferAttribute2(position, 3));
|
|
1300
|
+
geometry.setAttribute("aPerp", new Float32BufferAttribute2(perp, 3));
|
|
1301
|
+
geometry.setAttribute("aSide", new Float32BufferAttribute2(side, 1));
|
|
1302
|
+
geometry.setAttribute("aReach", new Float32BufferAttribute2(reach, 1));
|
|
1303
|
+
geometry.setAttribute("aCorner", new Float32BufferAttribute2(owner, 1));
|
|
1304
|
+
geometry.setIndex(new BufferAttribute(new Uint32Array(index), 1));
|
|
1305
|
+
return geometry;
|
|
1306
|
+
}
|
|
1307
|
+
var SHARP_CORNER_RENDER_ORDER = { depth: 6.25, near: 6.5, far: 6.75 };
|
|
1308
|
+
var SHARP_CORNER_STENCIL_BIT = 128;
|
|
1309
|
+
var BAND_VERTEX = (
|
|
1310
|
+
/* glsl */
|
|
1311
|
+
`
|
|
1312
|
+
#include <common>
|
|
1313
|
+
#include <clipping_planes_pars_vertex>
|
|
1314
|
+
|
|
1315
|
+
attribute vec3 aPerp;
|
|
1316
|
+
attribute float aSide;
|
|
1317
|
+
attribute float aReach;
|
|
1318
|
+
attribute float aCorner;
|
|
1319
|
+
uniform float uHalfWidth;
|
|
1320
|
+
uniform float uHovered;
|
|
1321
|
+
uniform vec2 uResolution;
|
|
1322
|
+
varying float vHovered;
|
|
1323
|
+
|
|
1324
|
+
void main() {
|
|
1325
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
1326
|
+
vec3 across = mat3(modelViewMatrix) * aPerp;
|
|
1327
|
+
float reach = aReach * length(across);
|
|
1328
|
+
across = normalize(across);
|
|
1329
|
+
|
|
1330
|
+
bool perspective = projectionMatrix[2][3] == -1.0;
|
|
1331
|
+
float pixel = 2.0 / (projectionMatrix[1][1] * uResolution.y);
|
|
1332
|
+
if (perspective) pixel *= -mvPosition.z;
|
|
1333
|
+
vec3 sight = perspective ? normalize(-mvPosition.xyz) : vec3(0.0, 0.0, 1.0);
|
|
1334
|
+
float shown = length(across - sight * dot(across, sight));
|
|
1335
|
+
vHovered = abs(aCorner - uHovered) < 0.5 ? 1.0 : 0.0;
|
|
1336
|
+
float offset = min(uHalfWidth * pixel / max(shown, 0.25), reach);
|
|
1337
|
+
|
|
1338
|
+
mvPosition.xyz += across * offset * aSide;
|
|
1339
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
1340
|
+
#include <clipping_planes_vertex>
|
|
1341
|
+
}
|
|
1342
|
+
`
|
|
1343
|
+
);
|
|
1344
|
+
var BAND_FRAGMENT = (
|
|
1345
|
+
/* glsl */
|
|
1346
|
+
`
|
|
1347
|
+
#include <common>
|
|
1348
|
+
#include <clipping_planes_pars_fragment>
|
|
1349
|
+
|
|
1350
|
+
uniform vec3 diffuse;
|
|
1351
|
+
uniform vec3 hoverColor;
|
|
1352
|
+
uniform float opacity;
|
|
1353
|
+
varying float vHovered;
|
|
1354
|
+
|
|
1355
|
+
void main() {
|
|
1356
|
+
#include <clipping_planes_fragment>
|
|
1357
|
+
// The corner under the pointer in the hover colour, as the part's faces are, not wider.
|
|
1358
|
+
vec3 color = mix(diffuse, hoverColor, vHovered);
|
|
1359
|
+
// And twice as strong: plain even where the part hides it.
|
|
1360
|
+
gl_FragColor = vec4(color, min(1.0, opacity * mix(1.0, 2.0, vHovered)));
|
|
1361
|
+
#include <colorspace_fragment>
|
|
1362
|
+
}
|
|
1363
|
+
`
|
|
1364
|
+
);
|
|
1365
|
+
function createSharpCornerDrawing(theme, part) {
|
|
1366
|
+
let geometry = new BufferGeometry();
|
|
1367
|
+
const resolution = { value: new Vector22(1, 1) };
|
|
1368
|
+
const hovered = { value: -1 };
|
|
1369
|
+
const viewport = new Vector4();
|
|
1370
|
+
const material = (opacity, depthFunc) => {
|
|
1371
|
+
const band = new ShaderMaterial({
|
|
1372
|
+
uniforms: {
|
|
1373
|
+
diffuse: { value: new Color(theme.sharpCorner) },
|
|
1374
|
+
hoverColor: { value: new Color(theme.hover) },
|
|
1375
|
+
opacity: { value: opacity },
|
|
1376
|
+
uHalfWidth: { value: BAND_WIDTH / 2 },
|
|
1377
|
+
uHovered: hovered,
|
|
1378
|
+
uResolution: resolution
|
|
1379
|
+
},
|
|
1380
|
+
vertexShader: BAND_VERTEX,
|
|
1381
|
+
fragmentShader: BAND_FRAGMENT,
|
|
1382
|
+
transparent: true,
|
|
1383
|
+
depthWrite: false,
|
|
1384
|
+
side: DoubleSide,
|
|
1385
|
+
clipping: true
|
|
1386
|
+
});
|
|
1387
|
+
band.depthFunc = depthFunc;
|
|
1388
|
+
band.polygonOffset = true;
|
|
1389
|
+
band.polygonOffsetFactor = -1;
|
|
1390
|
+
band.polygonOffsetUnits = -1;
|
|
1391
|
+
band.stencilWrite = true;
|
|
1392
|
+
band.stencilRef = SHARP_CORNER_STENCIL_BIT;
|
|
1393
|
+
band.stencilFuncMask = SHARP_CORNER_STENCIL_BIT;
|
|
1394
|
+
band.stencilWriteMask = SHARP_CORNER_STENCIL_BIT;
|
|
1395
|
+
band.stencilFunc = NotEqualStencilFunc;
|
|
1396
|
+
band.stencilFail = KeepStencilOp;
|
|
1397
|
+
band.stencilZFail = KeepStencilOp;
|
|
1398
|
+
band.stencilZPass = ReplaceStencilOp;
|
|
1399
|
+
return band;
|
|
1400
|
+
};
|
|
1401
|
+
const nearMaterial = material(NEAR_OPACITY, LessEqualDepth);
|
|
1402
|
+
const farMaterial = material(FAR_OPACITY, GreaterDepth);
|
|
1403
|
+
const near = new Mesh(geometry, nearMaterial);
|
|
1404
|
+
const far = new Mesh(geometry, farMaterial);
|
|
1405
|
+
near.name = "sharpCornersNear";
|
|
1406
|
+
far.name = "sharpCornersFar";
|
|
1407
|
+
near.renderOrder = SHARP_CORNER_RENDER_ORDER.near;
|
|
1408
|
+
far.renderOrder = SHARP_CORNER_RENDER_ORDER.far;
|
|
1409
|
+
near.raycast = () => {
|
|
1410
|
+
};
|
|
1411
|
+
far.raycast = () => {
|
|
1412
|
+
};
|
|
1413
|
+
const depthMaterial = new MeshBasicMaterial({
|
|
1414
|
+
colorWrite: false,
|
|
1415
|
+
depthWrite: true,
|
|
1416
|
+
transparent: true,
|
|
1417
|
+
polygonOffset: true,
|
|
1418
|
+
polygonOffsetFactor: 1,
|
|
1419
|
+
polygonOffsetUnits: 1
|
|
1420
|
+
});
|
|
1421
|
+
const depth = new Mesh(part, depthMaterial);
|
|
1422
|
+
depth.name = "sharpCornersDepth";
|
|
1423
|
+
depth.renderOrder = SHARP_CORNER_RENDER_ORDER.depth;
|
|
1424
|
+
depth.visible = false;
|
|
1425
|
+
depth.raycast = () => {
|
|
1426
|
+
};
|
|
1427
|
+
near.onBeforeRender = (renderer) => {
|
|
1428
|
+
renderer.getViewport(viewport);
|
|
1429
|
+
resolution.value.set(viewport.z, viewport.w);
|
|
1430
|
+
};
|
|
1431
|
+
const object = new Group();
|
|
1432
|
+
object.add(depth, far, near);
|
|
1433
|
+
object.visible = false;
|
|
1434
|
+
return {
|
|
1435
|
+
object,
|
|
1436
|
+
clear() {
|
|
1437
|
+
object.visible = false;
|
|
1438
|
+
},
|
|
1439
|
+
setHovered(index) {
|
|
1440
|
+
hovered.value = index ?? -1;
|
|
1441
|
+
},
|
|
1442
|
+
setCorners(creases, corners) {
|
|
1443
|
+
hovered.value = -1;
|
|
1444
|
+
object.visible = corners.length > 0;
|
|
1445
|
+
if (corners.length === 0) return;
|
|
1446
|
+
const next = sharpCornerBands(creases, corners);
|
|
1447
|
+
near.geometry = next;
|
|
1448
|
+
far.geometry = next;
|
|
1449
|
+
geometry.dispose();
|
|
1450
|
+
geometry = next;
|
|
1451
|
+
},
|
|
1452
|
+
setTheme(next) {
|
|
1453
|
+
for (const band of [nearMaterial, farMaterial]) {
|
|
1454
|
+
;
|
|
1455
|
+
band.uniforms["diffuse"].value.setHex(next.sharpCorner);
|
|
1456
|
+
band.uniforms["hoverColor"].value.setHex(next.hover);
|
|
1457
|
+
}
|
|
1458
|
+
},
|
|
1459
|
+
setPartDepth(on) {
|
|
1460
|
+
depth.visible = on;
|
|
1461
|
+
},
|
|
1462
|
+
setClippingPlanes(planes) {
|
|
1463
|
+
nearMaterial.clippingPlanes = planes;
|
|
1464
|
+
farMaterial.clippingPlanes = planes;
|
|
1465
|
+
depthMaterial.clippingPlanes = planes;
|
|
1466
|
+
},
|
|
1467
|
+
dispose() {
|
|
1468
|
+
object.clear();
|
|
1469
|
+
geometry.dispose();
|
|
1470
|
+
nearMaterial.dispose();
|
|
1471
|
+
farMaterial.dispose();
|
|
1472
|
+
depthMaterial.dispose();
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
function unit2(vector) {
|
|
1477
|
+
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
1478
|
+
return length === 0 ? null : { x: vector.x / length, y: vector.y / length, z: vector.z / length };
|
|
1479
|
+
}
|
|
1480
|
+
function emptyCreases() {
|
|
1481
|
+
return {
|
|
1482
|
+
count: 0,
|
|
1483
|
+
positions: new Float32Array(0),
|
|
1484
|
+
angles: new Float32Array(0),
|
|
1485
|
+
concave: new Uint8Array(0),
|
|
1486
|
+
regions: new Int32Array(0),
|
|
1487
|
+
fars: new Float32Array(0)
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
|
|
940
1491
|
// src/render/part.ts
|
|
941
1492
|
var REGION_ATTRIBUTE = "aRegion";
|
|
942
1493
|
var EMISSIVE_MIX = 0.4;
|
|
@@ -959,7 +1510,7 @@ function buildRegionAttribute(model, texels, vertexCount) {
|
|
|
959
1510
|
function createPart(model, geometry, theme) {
|
|
960
1511
|
const position = geometry.getAttribute("position");
|
|
961
1512
|
const texels = buildRegionTexels(model);
|
|
962
|
-
const regionAttribute = new
|
|
1513
|
+
const regionAttribute = new Float32BufferAttribute3(
|
|
963
1514
|
buildRegionAttribute(model, texels, position.count),
|
|
964
1515
|
1
|
|
965
1516
|
);
|
|
@@ -975,6 +1526,11 @@ function createPart(model, geometry, theme) {
|
|
|
975
1526
|
const wireframe = { value: false };
|
|
976
1527
|
let focused = false;
|
|
977
1528
|
let currentTheme = theme;
|
|
1529
|
+
let clipping = null;
|
|
1530
|
+
let creases = null;
|
|
1531
|
+
let sharpLines = null;
|
|
1532
|
+
let sharpKey = "";
|
|
1533
|
+
let corners = [];
|
|
978
1534
|
const material = new MeshLambertMaterial({
|
|
979
1535
|
color: theme.part,
|
|
980
1536
|
emissive: theme.partEmissive,
|
|
@@ -1038,11 +1594,11 @@ function createPart(model, geometry, theme) {
|
|
|
1038
1594
|
emissive: theme.partEmissive,
|
|
1039
1595
|
// A selected face can be viewed through the part from the side its normal
|
|
1040
1596
|
// faces away from.
|
|
1041
|
-
side:
|
|
1597
|
+
side: DoubleSide2
|
|
1042
1598
|
});
|
|
1043
1599
|
configureShader(focusMaterial, true);
|
|
1044
1600
|
configureShader(material, false);
|
|
1045
|
-
const mesh = new
|
|
1601
|
+
const mesh = new Mesh2(geometry, material);
|
|
1046
1602
|
mesh.renderOrder = 3;
|
|
1047
1603
|
const edgeGeometry = regionEdgesGeometry(geometry, model);
|
|
1048
1604
|
const edgeMaterial = new LineBasicMaterial({
|
|
@@ -1054,7 +1610,7 @@ function createPart(model, geometry, theme) {
|
|
|
1054
1610
|
edges.renderOrder = 4;
|
|
1055
1611
|
edges.raycast = () => {
|
|
1056
1612
|
};
|
|
1057
|
-
const focusMesh = new
|
|
1613
|
+
const focusMesh = new Mesh2(geometry, focusMaterial);
|
|
1058
1614
|
focusMesh.renderOrder = 3;
|
|
1059
1615
|
focusMesh.visible = false;
|
|
1060
1616
|
focusMesh.raycast = () => {
|
|
@@ -1068,11 +1624,12 @@ function createPart(model, geometry, theme) {
|
|
|
1068
1624
|
}
|
|
1069
1625
|
focusState.value = focused;
|
|
1070
1626
|
focusMesh.visible = focused;
|
|
1627
|
+
sharpLines?.setPartDepth(transparent);
|
|
1071
1628
|
};
|
|
1072
|
-
const object = new
|
|
1629
|
+
const object = new Group2();
|
|
1073
1630
|
object.add(focusMesh, mesh, edges);
|
|
1074
|
-
const scratchColor = new
|
|
1075
|
-
const scratchVector = new
|
|
1631
|
+
const scratchColor = new Color2();
|
|
1632
|
+
const scratchVector = new Vector35();
|
|
1076
1633
|
const paintRegion = (region, color, weight) => {
|
|
1077
1634
|
const column = texels.get(region);
|
|
1078
1635
|
if (column === void 0) return;
|
|
@@ -1146,9 +1703,11 @@ function createPart(model, geometry, theme) {
|
|
|
1146
1703
|
},
|
|
1147
1704
|
setClippingPlanes(planes) {
|
|
1148
1705
|
const value = planes === null ? null : [...planes];
|
|
1706
|
+
clipping = value;
|
|
1149
1707
|
material.clippingPlanes = value;
|
|
1150
1708
|
focusMaterial.clippingPlanes = value;
|
|
1151
1709
|
edgeMaterial.clippingPlanes = value;
|
|
1710
|
+
sharpLines?.setClippingPlanes(value);
|
|
1152
1711
|
},
|
|
1153
1712
|
setTheme(next) {
|
|
1154
1713
|
currentTheme = next;
|
|
@@ -1158,6 +1717,7 @@ function createPart(model, geometry, theme) {
|
|
|
1158
1717
|
focusMaterial.emissive.setHex(next.partEmissive);
|
|
1159
1718
|
edgeMaterial.color.setHex(wireframe.value ? next.part : next.edge);
|
|
1160
1719
|
edgeMaterial.opacity = wireframe.value ? 1 : next.edgeOpacity;
|
|
1720
|
+
sharpLines?.setTheme(next);
|
|
1161
1721
|
},
|
|
1162
1722
|
setDisplay(display, showEdges = true) {
|
|
1163
1723
|
const enabled = display === "wireframe";
|
|
@@ -1169,6 +1729,35 @@ function createPart(model, geometry, theme) {
|
|
|
1169
1729
|
edgeMaterial.color.setHex(enabled ? currentTheme.part : currentTheme.edge);
|
|
1170
1730
|
edgeMaterial.opacity = enabled ? 1 : currentTheme.edgeOpacity;
|
|
1171
1731
|
},
|
|
1732
|
+
setSharpCorners(options) {
|
|
1733
|
+
const key = options === null ? "" : sharpCornerKey(options);
|
|
1734
|
+
if (key === sharpKey) return;
|
|
1735
|
+
sharpKey = key;
|
|
1736
|
+
if (options === null || options.features.length === 0) {
|
|
1737
|
+
corners = [];
|
|
1738
|
+
sharpLines?.clear();
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
creases ??= surfaceCreases(geometry, model);
|
|
1742
|
+
if (!sharpLines) {
|
|
1743
|
+
sharpLines = createSharpCornerDrawing(currentTheme, geometry);
|
|
1744
|
+
sharpLines.setClippingPlanes(clipping);
|
|
1745
|
+
sharpLines.setPartDepth(wireframe.value || focused);
|
|
1746
|
+
object.add(sharpLines.object);
|
|
1747
|
+
}
|
|
1748
|
+
corners = findSharpCorners(creases, model, options);
|
|
1749
|
+
sharpLines.setCorners(creases, corners);
|
|
1750
|
+
},
|
|
1751
|
+
sharpCorners() {
|
|
1752
|
+
return corners;
|
|
1753
|
+
},
|
|
1754
|
+
sharpCornerAt(hit, camera, viewport) {
|
|
1755
|
+
if (!creases || corners.length === 0) return null;
|
|
1756
|
+
return sharpCornerAt(corners, creases, hit, camera, viewport, mesh.matrixWorld);
|
|
1757
|
+
},
|
|
1758
|
+
setHoveredSharpCorner(index) {
|
|
1759
|
+
sharpLines?.setHovered(index);
|
|
1760
|
+
},
|
|
1172
1761
|
dispose() {
|
|
1173
1762
|
object.clear();
|
|
1174
1763
|
if (geometry.getAttribute(REGION_ATTRIBUTE) === regionAttribute) {
|
|
@@ -1178,54 +1767,13 @@ function createPart(model, geometry, theme) {
|
|
|
1178
1767
|
focusMaterial.dispose();
|
|
1179
1768
|
edgeGeometry.dispose();
|
|
1180
1769
|
edgeMaterial.dispose();
|
|
1770
|
+
sharpLines?.dispose();
|
|
1181
1771
|
stateTexture.dispose();
|
|
1182
1772
|
opacityTexture.dispose();
|
|
1183
1773
|
}
|
|
1184
1774
|
};
|
|
1185
1775
|
}
|
|
1186
1776
|
|
|
1187
|
-
// src/render/adjacency.ts
|
|
1188
|
-
var GRID = 1e-4;
|
|
1189
|
-
var keyFor = (x, y, z) => `${Math.round(x / GRID)},${Math.round(y / GRID)},${Math.round(z / GRID)}`;
|
|
1190
|
-
function regionAdjacency(model, geometry) {
|
|
1191
|
-
const position = geometry.getAttribute("position");
|
|
1192
|
-
const adjacency = /* @__PURE__ */ new Map();
|
|
1193
|
-
if (!position) return adjacency;
|
|
1194
|
-
const owner = new Int32Array(Math.floor(position.count / 3)).fill(-1);
|
|
1195
|
-
for (const region of model.regions) {
|
|
1196
|
-
for (let at = region.triangles.start; at < region.triangles.end; at++) {
|
|
1197
|
-
if (at >= 0 && at < owner.length) owner[at] = region.idx;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
const edges = /* @__PURE__ */ new Map();
|
|
1201
|
-
const join = (a, b) => {
|
|
1202
|
-
if (a === b) return;
|
|
1203
|
-
const mine = adjacency.get(a) ?? /* @__PURE__ */ new Set();
|
|
1204
|
-
mine.add(b);
|
|
1205
|
-
adjacency.set(a, mine);
|
|
1206
|
-
const theirs = adjacency.get(b) ?? /* @__PURE__ */ new Set();
|
|
1207
|
-
theirs.add(a);
|
|
1208
|
-
adjacency.set(b, theirs);
|
|
1209
|
-
};
|
|
1210
|
-
for (let triangle = 0; triangle < owner.length; triangle++) {
|
|
1211
|
-
const region = owner[triangle];
|
|
1212
|
-
if (region === -1) continue;
|
|
1213
|
-
const corners = [0, 1, 2].map((corner) => {
|
|
1214
|
-
const at = triangle * 3 + corner;
|
|
1215
|
-
return keyFor(position.getX(at), position.getY(at), position.getZ(at));
|
|
1216
|
-
});
|
|
1217
|
-
for (let corner = 0; corner < 3; corner++) {
|
|
1218
|
-
const from = corners[corner];
|
|
1219
|
-
const to = corners[(corner + 1) % 3];
|
|
1220
|
-
const edge = from < to ? `${from}|${to}` : `${to}|${from}`;
|
|
1221
|
-
const seen = edges.get(edge);
|
|
1222
|
-
if (seen === void 0) edges.set(edge, region);
|
|
1223
|
-
else join(seen, region);
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
return adjacency;
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
1777
|
// src/render/selection.ts
|
|
1230
1778
|
var FEATURE_TYPE_RANKS = [
|
|
1231
1779
|
["blind_hole", "through_hole", "filleted_blind_hole"],
|
|
@@ -1337,7 +1885,7 @@ import {
|
|
|
1337
1885
|
useMemo as useMemo4,
|
|
1338
1886
|
useRef as useRef3
|
|
1339
1887
|
} from "react";
|
|
1340
|
-
import { Box3 as Box33, Vector3 as
|
|
1888
|
+
import { Box3 as Box33, Vector3 as Vector39 } from "three";
|
|
1341
1889
|
|
|
1342
1890
|
// src/camera.tsx
|
|
1343
1891
|
import { useFrame, useThree as useThree2 } from "@react-three/fiber";
|
|
@@ -1353,9 +1901,9 @@ import {
|
|
|
1353
1901
|
Raycaster,
|
|
1354
1902
|
Sphere,
|
|
1355
1903
|
Spherical,
|
|
1356
|
-
Vector2 as
|
|
1357
|
-
Vector3 as
|
|
1358
|
-
Vector4
|
|
1904
|
+
Vector2 as Vector23,
|
|
1905
|
+
Vector3 as Vector36,
|
|
1906
|
+
Vector4 as Vector42
|
|
1359
1907
|
} from "three";
|
|
1360
1908
|
|
|
1361
1909
|
// src/render/control-schemes.ts
|
|
@@ -1451,9 +1999,9 @@ CameraControls.install({
|
|
|
1451
1999
|
Raycaster,
|
|
1452
2000
|
Sphere,
|
|
1453
2001
|
Spherical,
|
|
1454
|
-
Vector2:
|
|
1455
|
-
Vector3:
|
|
1456
|
-
Vector4
|
|
2002
|
+
Vector2: Vector23,
|
|
2003
|
+
Vector3: Vector36,
|
|
2004
|
+
Vector4: Vector42
|
|
1457
2005
|
}
|
|
1458
2006
|
});
|
|
1459
2007
|
var EPSILON3 = 1e-6;
|
|
@@ -1475,9 +2023,9 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1475
2023
|
// Scratch objects — `#onPointerMove` and `#adaptUpVector` run at pointer and
|
|
1476
2024
|
// frame rate respectively, so neither may allocate.
|
|
1477
2025
|
#spherical = new Spherical();
|
|
1478
|
-
#scratchA = new
|
|
1479
|
-
#scratchB = new
|
|
1480
|
-
#scratchC = new
|
|
2026
|
+
#scratchA = new Vector36();
|
|
2027
|
+
#scratchB = new Vector36();
|
|
2028
|
+
#scratchC = new Vector36();
|
|
1481
2029
|
constructor(camera, domElement, options = {}) {
|
|
1482
2030
|
super(camera, domElement);
|
|
1483
2031
|
this.#domElement = domElement;
|
|
@@ -1819,10 +2367,10 @@ function counted(notify) {
|
|
|
1819
2367
|
import { useFrame as useFrame2, useThree as useThree3 } from "@react-three/fiber";
|
|
1820
2368
|
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2 } from "react";
|
|
1821
2369
|
import {
|
|
1822
|
-
DoubleSide as
|
|
2370
|
+
DoubleSide as DoubleSide3,
|
|
1823
2371
|
RingGeometry,
|
|
1824
2372
|
SphereGeometry,
|
|
1825
|
-
Vector3 as
|
|
2373
|
+
Vector3 as Vector37
|
|
1826
2374
|
} from "three";
|
|
1827
2375
|
|
|
1828
2376
|
// src/render/target.ts
|
|
@@ -1865,8 +2413,8 @@ var TargetMarker = ({ controlsRef }) => {
|
|
|
1865
2413
|
const heldUntil = useRef2(0);
|
|
1866
2414
|
const painted = useRef2(-1);
|
|
1867
2415
|
const placed = useRef2(false);
|
|
1868
|
-
const lastTarget = useMemo3(() => new
|
|
1869
|
-
const scratch = useMemo3(() => new
|
|
2416
|
+
const lastTarget = useMemo3(() => new Vector37(), []);
|
|
2417
|
+
const scratch = useMemo3(() => new Vector37(), []);
|
|
1870
2418
|
useEffect3(() => {
|
|
1871
2419
|
const controls = controlsRef.current;
|
|
1872
2420
|
if (!controls) return void 0;
|
|
@@ -1932,7 +2480,7 @@ var TargetMarker = ({ controlsRef }) => {
|
|
|
1932
2480
|
opacity: 0,
|
|
1933
2481
|
depthTest: false,
|
|
1934
2482
|
depthWrite: false,
|
|
1935
|
-
side:
|
|
2483
|
+
side: DoubleSide3
|
|
1936
2484
|
}
|
|
1937
2485
|
)
|
|
1938
2486
|
}
|
|
@@ -1962,11 +2510,11 @@ var TargetMarker = ({ controlsRef }) => {
|
|
|
1962
2510
|
|
|
1963
2511
|
// src/render/view-cube.ts
|
|
1964
2512
|
import {
|
|
1965
|
-
BufferGeometry,
|
|
2513
|
+
BufferGeometry as BufferGeometry2,
|
|
1966
2514
|
CanvasTexture,
|
|
1967
|
-
Float32BufferAttribute as
|
|
2515
|
+
Float32BufferAttribute as Float32BufferAttribute4,
|
|
1968
2516
|
SRGBColorSpace,
|
|
1969
|
-
Vector3 as
|
|
2517
|
+
Vector3 as Vector38
|
|
1970
2518
|
} from "three";
|
|
1971
2519
|
var VIEW_NAMES = [
|
|
1972
2520
|
// The six faces.
|
|
@@ -2050,12 +2598,12 @@ function viewUp(direction) {
|
|
|
2050
2598
|
return { x: 0, y: 0, z: 1 };
|
|
2051
2599
|
}
|
|
2052
2600
|
function squaredUp(direction, currentUp) {
|
|
2053
|
-
const forward = new
|
|
2601
|
+
const forward = new Vector38(direction.x, direction.y, direction.z).normalize();
|
|
2054
2602
|
const canonical = viewUp(direction);
|
|
2055
|
-
const zero = new
|
|
2603
|
+
const zero = new Vector38(canonical.x, canonical.y, canonical.z);
|
|
2056
2604
|
zero.addScaledVector(forward, -forward.dot(zero)).normalize();
|
|
2057
|
-
const quarter = new
|
|
2058
|
-
const current = new
|
|
2605
|
+
const quarter = new Vector38().crossVectors(forward, zero);
|
|
2606
|
+
const current = new Vector38(currentUp.x, currentUp.y, currentUp.z);
|
|
2059
2607
|
const rolls = [zero, quarter, zero.clone().negate(), quarter.clone().negate()];
|
|
2060
2608
|
const nearest = rolls.reduce(
|
|
2061
2609
|
(best, roll) => roll.dot(current) > best.dot(current) ? roll : best
|
|
@@ -2073,11 +2621,11 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
2073
2621
|
const direction = viewVector(name);
|
|
2074
2622
|
const [sx, sy, sz] = VIEW_SIGNS[name];
|
|
2075
2623
|
const sign = (axis) => VIEW_SIGNS[name][axis] ?? 0;
|
|
2076
|
-
const normal = new
|
|
2624
|
+
const normal = new Vector38(direction.x, direction.y, direction.z);
|
|
2077
2625
|
let polygon;
|
|
2078
2626
|
if (kind === "face") {
|
|
2079
2627
|
const up = viewUp(direction);
|
|
2080
|
-
const upVector = new
|
|
2628
|
+
const upVector = new Vector38(up.x, up.y, up.z);
|
|
2081
2629
|
const right = normal.clone().negate().cross(upVector).normalize();
|
|
2082
2630
|
const square = [
|
|
2083
2631
|
[-1, -1],
|
|
@@ -2099,7 +2647,7 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
2099
2647
|
[chamfer, 1, -chamfer]
|
|
2100
2648
|
];
|
|
2101
2649
|
polygon = rectangle.map(
|
|
2102
|
-
([onA, onB, onC]) => new
|
|
2650
|
+
([onA, onB, onC]) => new Vector38().setComponent(a, sign(a) * onA).setComponent(b, sign(b) * onB).setComponent(c, onC)
|
|
2103
2651
|
);
|
|
2104
2652
|
} else {
|
|
2105
2653
|
const triangle = [
|
|
@@ -2107,11 +2655,11 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
2107
2655
|
[chamfer, 1, chamfer],
|
|
2108
2656
|
[chamfer, chamfer, 1]
|
|
2109
2657
|
];
|
|
2110
|
-
polygon = triangle.map(([onX, onY, onZ]) => new
|
|
2658
|
+
polygon = triangle.map(([onX, onY, onZ]) => new Vector38(sx * onX, sy * onY, sz * onZ));
|
|
2111
2659
|
}
|
|
2112
2660
|
const [first, second, third] = polygon;
|
|
2113
2661
|
if (first && second && third) {
|
|
2114
|
-
const facing = new
|
|
2662
|
+
const facing = new Vector38().subVectors(second, first).cross(new Vector38().subVectors(third, first));
|
|
2115
2663
|
if (facing.dot(normal) < 0) polygon.reverse();
|
|
2116
2664
|
}
|
|
2117
2665
|
return { name, kind, direction, polygon: polygon.map(vec) };
|
|
@@ -2121,7 +2669,7 @@ function panelGeometry(zone) {
|
|
|
2121
2669
|
const positions = [];
|
|
2122
2670
|
const normals = [];
|
|
2123
2671
|
const [first] = zone.polygon;
|
|
2124
|
-
const geometry = new
|
|
2672
|
+
const geometry = new BufferGeometry2();
|
|
2125
2673
|
if (!first) return geometry;
|
|
2126
2674
|
for (let index = 1; index + 1 < zone.polygon.length; index += 1) {
|
|
2127
2675
|
const b = zone.polygon[index];
|
|
@@ -2132,8 +2680,8 @@ function panelGeometry(zone) {
|
|
|
2132
2680
|
normals.push(zone.direction.x, zone.direction.y, zone.direction.z);
|
|
2133
2681
|
}
|
|
2134
2682
|
}
|
|
2135
|
-
geometry.setAttribute("position", new
|
|
2136
|
-
geometry.setAttribute("normal", new
|
|
2683
|
+
geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
|
|
2684
|
+
geometry.setAttribute("normal", new Float32BufferAttribute4(normals, 3));
|
|
2137
2685
|
return geometry;
|
|
2138
2686
|
}
|
|
2139
2687
|
function cubeOutlineGeometry(zones) {
|
|
@@ -2146,8 +2694,8 @@ function cubeOutlineGeometry(zones) {
|
|
|
2146
2694
|
positions.push(from.x, from.y, from.z, to.x, to.y, to.z);
|
|
2147
2695
|
}
|
|
2148
2696
|
}
|
|
2149
|
-
const geometry = new
|
|
2150
|
-
geometry.setAttribute("position", new
|
|
2697
|
+
const geometry = new BufferGeometry2();
|
|
2698
|
+
geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
|
|
2151
2699
|
return geometry;
|
|
2152
2700
|
}
|
|
2153
2701
|
function labelGeometry(zone) {
|
|
@@ -2171,9 +2719,9 @@ function labelGeometry(zone) {
|
|
|
2171
2719
|
);
|
|
2172
2720
|
uvs.push(uv[0] ?? 0, uv[1] ?? 0);
|
|
2173
2721
|
}
|
|
2174
|
-
const geometry = new
|
|
2175
|
-
geometry.setAttribute("position", new
|
|
2176
|
-
geometry.setAttribute("uv", new
|
|
2722
|
+
const geometry = new BufferGeometry2();
|
|
2723
|
+
geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
|
|
2724
|
+
geometry.setAttribute("uv", new Float32BufferAttribute4(uvs, 2));
|
|
2177
2725
|
return geometry;
|
|
2178
2726
|
}
|
|
2179
2727
|
function labelTexture(label, color) {
|
|
@@ -2241,10 +2789,10 @@ var ViewerScene = ({
|
|
|
2241
2789
|
const framedRef = useRef3(null);
|
|
2242
2790
|
const scratchBox = useMemo4(() => new Box33(), []);
|
|
2243
2791
|
const scratchBoundary = useMemo4(() => new Box33(), []);
|
|
2244
|
-
const scratchDirection = useMemo4(() => new
|
|
2245
|
-
const scratchView = useMemo4(() => new
|
|
2246
|
-
const scratchTarget = useMemo4(() => new
|
|
2247
|
-
const scratchPosition = useMemo4(() => new
|
|
2792
|
+
const scratchDirection = useMemo4(() => new Vector39(), []);
|
|
2793
|
+
const scratchView = useMemo4(() => new Vector39(), []);
|
|
2794
|
+
const scratchTarget = useMemo4(() => new Vector39(), []);
|
|
2795
|
+
const scratchPosition = useMemo4(() => new Vector39(), []);
|
|
2248
2796
|
const applyLimits = useCallback(
|
|
2249
2797
|
(bounds, framed) => {
|
|
2250
2798
|
controlsRef.current?.applyLimits(
|
|
@@ -2293,8 +2841,8 @@ var ViewerScene = ({
|
|
|
2293
2841
|
(bounds) => {
|
|
2294
2842
|
const controls = controlsRef.current;
|
|
2295
2843
|
if (!controls) return false;
|
|
2296
|
-
const target = controls.getTarget(new
|
|
2297
|
-
const direction = currentViewDirection(camera, target, new
|
|
2844
|
+
const target = controls.getTarget(new Vector39());
|
|
2845
|
+
const direction = currentViewDirection(camera, target, new Vector39());
|
|
2298
2846
|
const distance = fitDistance(projection, size, bounds, DEFAULT_FIT_MARGIN);
|
|
2299
2847
|
const position = direction.multiplyScalar(distance).add(bounds.center);
|
|
2300
2848
|
void controls.setLookAt(
|
|
@@ -2319,8 +2867,8 @@ var ViewerScene = ({
|
|
|
2319
2867
|
const fitContent = useCallback(() => {
|
|
2320
2868
|
const controls = controlsRef.current;
|
|
2321
2869
|
if (!controls) return false;
|
|
2322
|
-
const target = controls.getTarget(new
|
|
2323
|
-
return frame(currentViewDirection(camera, target, new
|
|
2870
|
+
const target = controls.getTarget(new Vector39());
|
|
2871
|
+
return frame(currentViewDirection(camera, target, new Vector39()), true);
|
|
2324
2872
|
}, [camera, frame]);
|
|
2325
2873
|
const resetContent = useCallback(() => {
|
|
2326
2874
|
const bounds = measure();
|
|
@@ -2526,67 +3074,234 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
2526
3074
|
});
|
|
2527
3075
|
|
|
2528
3076
|
// src/section-view.tsx
|
|
2529
|
-
import { useFrame as useFrame4, useThree as
|
|
2530
|
-
import { useCallback as useCallback2, useEffect as
|
|
3077
|
+
import { useFrame as useFrame4, useThree as useThree6 } from "@react-three/fiber";
|
|
3078
|
+
import { useCallback as useCallback2, useEffect as useEffect6, useLayoutEffect as useLayoutEffect2, useMemo as useMemo6, useRef as useRef4, useState } from "react";
|
|
2531
3079
|
import {
|
|
2532
|
-
Color as
|
|
2533
|
-
DoubleSide as
|
|
3080
|
+
Color as Color5,
|
|
3081
|
+
DoubleSide as DoubleSide5,
|
|
2534
3082
|
EdgesGeometry,
|
|
2535
|
-
Mesh as
|
|
3083
|
+
Mesh as Mesh4,
|
|
2536
3084
|
Plane as Plane2,
|
|
2537
3085
|
PlaneGeometry,
|
|
2538
3086
|
Quaternion as Quaternion2,
|
|
2539
3087
|
Raycaster as Raycaster2,
|
|
2540
3088
|
Scene,
|
|
2541
|
-
Vector2 as
|
|
2542
|
-
Vector3 as
|
|
3089
|
+
Vector2 as Vector26,
|
|
3090
|
+
Vector3 as Vector311
|
|
2543
3091
|
} from "three";
|
|
2544
3092
|
|
|
2545
|
-
// src/
|
|
2546
|
-
import {
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
var
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
3093
|
+
// src/arrow-mesh.tsx
|
|
3094
|
+
import { useThree as useThree5 } from "@react-three/fiber";
|
|
3095
|
+
import { useEffect as useEffect5, useLayoutEffect, useMemo as useMemo5 } from "react";
|
|
3096
|
+
|
|
3097
|
+
// src/render/arrow-material.ts
|
|
3098
|
+
import { AlwaysDepth, Color as Color3, ShaderMaterial as ShaderMaterial2 } from "three";
|
|
3099
|
+
var VERTEX = (
|
|
3100
|
+
/* glsl */
|
|
3101
|
+
`
|
|
3102
|
+
varying vec3 vNormal;
|
|
3103
|
+
|
|
3104
|
+
void main() {
|
|
3105
|
+
vNormal = normalize(normalMatrix * normal);
|
|
3106
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
3107
|
+
}
|
|
3108
|
+
`
|
|
3109
|
+
);
|
|
3110
|
+
var FRAGMENT = (
|
|
3111
|
+
/* glsl */
|
|
3112
|
+
`
|
|
3113
|
+
uniform vec3 uColor;
|
|
3114
|
+
uniform float uOpacity;
|
|
3115
|
+
|
|
3116
|
+
varying vec3 vNormal;
|
|
3117
|
+
|
|
3118
|
+
// Above, to the left and toward the camera, in the camera's own frame.
|
|
3119
|
+
const vec3 KEY = vec3(-0.4, 0.6, 0.7);
|
|
3120
|
+
|
|
3121
|
+
void main() {
|
|
3122
|
+
// Wrapped, and over a narrow range: a quarter darker at most, so the shape
|
|
3123
|
+
// shows without the colour going anywhere.
|
|
3124
|
+
float light = mix(0.75, 1.0, 0.5 + 0.5 * dot(normalize(vNormal), normalize(KEY)));
|
|
3125
|
+
gl_FragColor = vec4(uColor * light, uOpacity);
|
|
3126
|
+
#include <tonemapping_fragment>
|
|
3127
|
+
#include <colorspace_fragment>
|
|
3128
|
+
}
|
|
3129
|
+
`
|
|
3130
|
+
);
|
|
3131
|
+
function createArrowMaterial() {
|
|
3132
|
+
const uniforms = {
|
|
3133
|
+
uColor: { value: new Color3() },
|
|
3134
|
+
uOpacity: { value: 1 }
|
|
3135
|
+
};
|
|
3136
|
+
return new ShaderMaterial2({
|
|
3137
|
+
vertexShader: VERTEX,
|
|
3138
|
+
fragmentShader: FRAGMENT,
|
|
3139
|
+
uniforms,
|
|
3140
|
+
transparent: true
|
|
3141
|
+
});
|
|
3142
|
+
}
|
|
3143
|
+
function createArrowDepthMaterial() {
|
|
3144
|
+
const material = createArrowMaterial();
|
|
3145
|
+
material.colorWrite = false;
|
|
3146
|
+
return material;
|
|
3147
|
+
}
|
|
3148
|
+
function applyArrowColor(material, color, opacity) {
|
|
3149
|
+
material.uniforms.uColor.value.set(color);
|
|
3150
|
+
material.uniforms.uOpacity.value = opacity;
|
|
3151
|
+
}
|
|
3152
|
+
var RESET_VERTEX = (
|
|
3153
|
+
/* glsl */
|
|
3154
|
+
`
|
|
3155
|
+
void main() {
|
|
3156
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
3157
|
+
// On the far plane, so what it leaves in the depth buffer is "nothing here".
|
|
3158
|
+
gl_Position.z = gl_Position.w;
|
|
3159
|
+
}
|
|
3160
|
+
`
|
|
3161
|
+
);
|
|
3162
|
+
var RESET_FRAGMENT = (
|
|
3163
|
+
/* glsl */
|
|
3164
|
+
`
|
|
3165
|
+
void main() {
|
|
3166
|
+
gl_FragColor = vec4(0.0);
|
|
3167
|
+
}
|
|
3168
|
+
`
|
|
3169
|
+
);
|
|
3170
|
+
function createDepthResetMaterial() {
|
|
3171
|
+
return new ShaderMaterial2({
|
|
3172
|
+
vertexShader: RESET_VERTEX,
|
|
3173
|
+
fragmentShader: RESET_FRAGMENT,
|
|
3174
|
+
transparent: true,
|
|
3175
|
+
colorWrite: false,
|
|
3176
|
+
depthFunc: AlwaysDepth
|
|
3177
|
+
});
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
// src/arrow-mesh.tsx
|
|
3181
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
3182
|
+
var ArrowMesh = ({ geometry, color, opacity, onTop = false, events }) => {
|
|
3183
|
+
const invalidate = useThree5((state) => state.invalidate);
|
|
3184
|
+
const material = useMemo5(() => createArrowMaterial(), []);
|
|
3185
|
+
useEffect5(() => () => material.dispose(), [material]);
|
|
3186
|
+
const depth = useMemo5(() => createArrowDepthMaterial(), []);
|
|
3187
|
+
useEffect5(() => () => depth.dispose(), [depth]);
|
|
3188
|
+
const reset = useMemo5(() => onTop ? createDepthResetMaterial() : null, [onTop]);
|
|
3189
|
+
useEffect5(() => () => reset?.dispose(), [reset]);
|
|
3190
|
+
useLayoutEffect(() => {
|
|
3191
|
+
applyArrowColor(material, color, opacity);
|
|
3192
|
+
invalidate();
|
|
3193
|
+
}, [color, invalidate, material, opacity]);
|
|
3194
|
+
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
3195
|
+
reset ? /* @__PURE__ */ jsx4("mesh", { geometry, material: reset, renderOrder: 0, raycast: () => null }) : null,
|
|
3196
|
+
/* @__PURE__ */ jsx4("mesh", { geometry, material: depth, renderOrder: 1, raycast: () => null }),
|
|
3197
|
+
/* @__PURE__ */ jsx4("mesh", { geometry, material, renderOrder: 2, ...events })
|
|
3198
|
+
] });
|
|
3199
|
+
};
|
|
3200
|
+
|
|
3201
|
+
// src/render/arrow.ts
|
|
3202
|
+
import { LatheGeometry, Vector2 as Vector24, Vector3 as Vector310 } from "three";
|
|
3203
|
+
var ARROW_AXIS2 = new Vector310(0, 1, 0);
|
|
3204
|
+
var ARROW_ROUND = 32;
|
|
3205
|
+
var HEAD_LENGTH = 0.415;
|
|
3206
|
+
var HEAD_RADIUS = 0.153;
|
|
3207
|
+
var SHAFT_RADIUS = 0.0515;
|
|
3208
|
+
var HANDLE_TIP = 0.76;
|
|
3209
|
+
var HANDLE_HEAD_LENGTH = 0.3;
|
|
3210
|
+
var HANDLE_HEAD_RADIUS = 0.14;
|
|
3211
|
+
var HANDLE_SHAFT_RADIUS = 0.035;
|
|
3212
|
+
var HANDLE_BEAD_RADIUS = 0.1;
|
|
3213
|
+
var RIM_ROUND = 6e-3;
|
|
3214
|
+
var NECK_ROUND = 8e-3;
|
|
3215
|
+
var BEAD_ROUND = 0.02;
|
|
3216
|
+
var ROUND_STEPS = 4;
|
|
3217
|
+
var CAP_STEPS = 6;
|
|
3218
|
+
var BEAD_STEPS = 12;
|
|
3219
|
+
var head = ({ length, radius, shaft }) => [
|
|
3220
|
+
{ at: new Vector24(0, 0) },
|
|
3221
|
+
{ at: new Vector24(radius, length), round: RIM_ROUND },
|
|
3222
|
+
{ at: new Vector24(shaft, length), round: NECK_ROUND }
|
|
3223
|
+
];
|
|
3224
|
+
var rounded = (corners) => corners.flatMap(({ at, round = 0 }, index) => {
|
|
3225
|
+
const before = corners[index - 1]?.at;
|
|
3226
|
+
const after = corners[index + 1]?.at;
|
|
3227
|
+
if (!(round > 0) || !before || !after) return [at];
|
|
3228
|
+
const back = before.clone().sub(at);
|
|
3229
|
+
const ahead = after.clone().sub(at);
|
|
3230
|
+
const reach = Math.min(back.length(), ahead.length()) / 2;
|
|
3231
|
+
back.normalize();
|
|
3232
|
+
ahead.normalize();
|
|
3233
|
+
const angle = Math.acos(Math.min(Math.max(back.dot(ahead), -1), 1));
|
|
3234
|
+
if (angle > Math.PI - 1e-6 || angle < 1e-6) return [at];
|
|
3235
|
+
const half = angle / 2;
|
|
3236
|
+
const offset = Math.min(round / Math.tan(half), reach);
|
|
3237
|
+
const radius = offset * Math.tan(half);
|
|
3238
|
+
const centre = at.clone().addScaledVector(back.clone().add(ahead).normalize(), radius / Math.sin(half));
|
|
3239
|
+
const from = at.clone().addScaledVector(back, offset).sub(centre);
|
|
3240
|
+
const to = at.clone().addScaledVector(ahead, offset).sub(centre);
|
|
3241
|
+
const start = Math.atan2(from.y, from.x);
|
|
3242
|
+
let sweep = Math.atan2(to.y, to.x) - start;
|
|
3243
|
+
if (sweep > Math.PI) sweep -= Math.PI * 2;
|
|
3244
|
+
if (sweep < -Math.PI) sweep += Math.PI * 2;
|
|
3245
|
+
return Array.from({ length: ROUND_STEPS + 1 }, (_, step) => {
|
|
3246
|
+
const turn = start + sweep * step / ROUND_STEPS;
|
|
3247
|
+
return new Vector24(centre.x + Math.cos(turn) * radius, centre.y + Math.sin(turn) * radius);
|
|
3248
|
+
});
|
|
3249
|
+
});
|
|
3250
|
+
function arrowProfile() {
|
|
3251
|
+
const body = rounded([
|
|
3252
|
+
...head({ length: HEAD_LENGTH, radius: HEAD_RADIUS, shaft: SHAFT_RADIUS }),
|
|
3253
|
+
{ at: new Vector24(SHAFT_RADIUS, 1 - SHAFT_RADIUS) }
|
|
3254
|
+
]);
|
|
3255
|
+
const tail = Array.from({ length: CAP_STEPS }, (_, step) => {
|
|
3256
|
+
const turn = (step + 1) / CAP_STEPS * (Math.PI / 2);
|
|
3257
|
+
return new Vector24(
|
|
3258
|
+
step + 1 === CAP_STEPS ? 0 : Math.cos(turn) * SHAFT_RADIUS,
|
|
3259
|
+
1 - SHAFT_RADIUS + Math.sin(turn) * SHAFT_RADIUS
|
|
3260
|
+
);
|
|
3261
|
+
});
|
|
3262
|
+
return [...body, ...tail];
|
|
3263
|
+
}
|
|
3264
|
+
function handleProfile() {
|
|
3265
|
+
const lower = head({
|
|
3266
|
+
length: HANDLE_HEAD_LENGTH,
|
|
3267
|
+
radius: HANDLE_HEAD_RADIUS,
|
|
3268
|
+
shaft: HANDLE_SHAFT_RADIUS
|
|
3269
|
+
}).map(({ at, round }) => ({ at: new Vector24(at.x, at.y - HANDLE_TIP), round }));
|
|
3270
|
+
const upper = lower.slice().reverse().map(({ at, round }) => ({ at: new Vector24(at.x, -at.y), round }));
|
|
3271
|
+
const meet = Math.acos(HANDLE_SHAFT_RADIUS / HANDLE_BEAD_RADIUS);
|
|
3272
|
+
const bead = Array.from({ length: BEAD_STEPS + 1 }, (_, step) => {
|
|
3273
|
+
const turn = -meet + 2 * meet * step / BEAD_STEPS;
|
|
3274
|
+
const at = new Vector24(Math.cos(turn), Math.sin(turn)).multiplyScalar(HANDLE_BEAD_RADIUS);
|
|
3275
|
+
return { at, round: step === 0 || step === BEAD_STEPS ? BEAD_ROUND : 0 };
|
|
3276
|
+
});
|
|
3277
|
+
return rounded([...lower, ...bead, ...upper]);
|
|
2570
3278
|
}
|
|
3279
|
+
var turned = (profile) => {
|
|
3280
|
+
const geometry = new LatheGeometry(profile, ARROW_ROUND);
|
|
3281
|
+
geometry.normalizeNormals();
|
|
3282
|
+
return geometry;
|
|
3283
|
+
};
|
|
3284
|
+
var arrowGeometry = () => turned(arrowProfile());
|
|
3285
|
+
var handleGeometry = () => turned(handleProfile());
|
|
2571
3286
|
|
|
2572
3287
|
// src/render/section-cap.ts
|
|
2573
3288
|
import {
|
|
2574
3289
|
AlwaysStencilFunc,
|
|
2575
3290
|
BackSide,
|
|
2576
|
-
Color as
|
|
3291
|
+
Color as Color4,
|
|
2577
3292
|
DecrementWrapStencilOp,
|
|
2578
|
-
DoubleSide as
|
|
3293
|
+
DoubleSide as DoubleSide4,
|
|
2579
3294
|
FrontSide,
|
|
2580
3295
|
IncrementWrapStencilOp,
|
|
2581
3296
|
LinearFilter,
|
|
2582
|
-
MeshBasicMaterial as
|
|
2583
|
-
NotEqualStencilFunc,
|
|
2584
|
-
ReplaceStencilOp,
|
|
2585
|
-
ShaderMaterial,
|
|
2586
|
-
Vector2 as
|
|
3297
|
+
MeshBasicMaterial as MeshBasicMaterial3,
|
|
3298
|
+
NotEqualStencilFunc as NotEqualStencilFunc2,
|
|
3299
|
+
ReplaceStencilOp as ReplaceStencilOp2,
|
|
3300
|
+
ShaderMaterial as ShaderMaterial3,
|
|
3301
|
+
Vector2 as Vector25,
|
|
2587
3302
|
WebGLRenderTarget
|
|
2588
3303
|
} from "three";
|
|
2589
|
-
var
|
|
3304
|
+
var VERTEX2 = (
|
|
2590
3305
|
/* glsl */
|
|
2591
3306
|
`
|
|
2592
3307
|
void main() {
|
|
@@ -2594,7 +3309,7 @@ void main() {
|
|
|
2594
3309
|
}
|
|
2595
3310
|
`
|
|
2596
3311
|
);
|
|
2597
|
-
var
|
|
3312
|
+
var FRAGMENT2 = (
|
|
2598
3313
|
/* glsl */
|
|
2599
3314
|
`
|
|
2600
3315
|
uniform sampler2D uMask;
|
|
@@ -2642,25 +3357,25 @@ function createMaskTarget() {
|
|
|
2642
3357
|
function createCapMaterial(mask) {
|
|
2643
3358
|
const uniforms = {
|
|
2644
3359
|
uMask: { value: mask },
|
|
2645
|
-
uResolution: { value: new
|
|
2646
|
-
uFill: { value: new
|
|
2647
|
-
uHatch: { value: new
|
|
2648
|
-
uOutline: { value: new
|
|
3360
|
+
uResolution: { value: new Vector25(1, 1) },
|
|
3361
|
+
uFill: { value: new Color4() },
|
|
3362
|
+
uHatch: { value: new Color4() },
|
|
3363
|
+
uOutline: { value: new Color4() },
|
|
2649
3364
|
uPitch: { value: CAP_HATCH.pitch },
|
|
2650
3365
|
uLine: { value: CAP_HATCH.line },
|
|
2651
3366
|
uThickness: { value: CAP_HATCH.outline }
|
|
2652
3367
|
};
|
|
2653
|
-
return new
|
|
2654
|
-
vertexShader:
|
|
2655
|
-
fragmentShader:
|
|
3368
|
+
return new ShaderMaterial3({
|
|
3369
|
+
vertexShader: VERTEX2,
|
|
3370
|
+
fragmentShader: FRAGMENT2,
|
|
2656
3371
|
uniforms,
|
|
2657
|
-
side:
|
|
3372
|
+
side: DoubleSide4,
|
|
2658
3373
|
stencilWrite: true,
|
|
2659
3374
|
stencilRef: 0,
|
|
2660
|
-
stencilFunc:
|
|
2661
|
-
stencilFail:
|
|
2662
|
-
stencilZFail:
|
|
2663
|
-
stencilZPass:
|
|
3375
|
+
stencilFunc: NotEqualStencilFunc2,
|
|
3376
|
+
stencilFail: ReplaceStencilOp2,
|
|
3377
|
+
stencilZFail: ReplaceStencilOp2,
|
|
3378
|
+
stencilZPass: ReplaceStencilOp2
|
|
2664
3379
|
});
|
|
2665
3380
|
}
|
|
2666
3381
|
function applyCapTheme(material, theme, dpr) {
|
|
@@ -2681,14 +3396,14 @@ function createStencilMaterials(clip) {
|
|
|
2681
3396
|
clippingPlanes: clip
|
|
2682
3397
|
};
|
|
2683
3398
|
return [
|
|
2684
|
-
new
|
|
3399
|
+
new MeshBasicMaterial3({
|
|
2685
3400
|
...shared,
|
|
2686
3401
|
side: BackSide,
|
|
2687
3402
|
stencilFail: IncrementWrapStencilOp,
|
|
2688
3403
|
stencilZFail: IncrementWrapStencilOp,
|
|
2689
3404
|
stencilZPass: IncrementWrapStencilOp
|
|
2690
3405
|
}),
|
|
2691
|
-
new
|
|
3406
|
+
new MeshBasicMaterial3({
|
|
2692
3407
|
...shared,
|
|
2693
3408
|
side: FrontSide,
|
|
2694
3409
|
stencilFail: DecrementWrapStencilOp,
|
|
@@ -2698,25 +3413,25 @@ function createStencilMaterials(clip) {
|
|
|
2698
3413
|
];
|
|
2699
3414
|
}
|
|
2700
3415
|
function createMaskMaterial() {
|
|
2701
|
-
return new
|
|
3416
|
+
return new MeshBasicMaterial3({
|
|
2702
3417
|
color: 16777215,
|
|
2703
|
-
side:
|
|
3418
|
+
side: DoubleSide4,
|
|
2704
3419
|
stencilWrite: true,
|
|
2705
3420
|
stencilRef: 0,
|
|
2706
|
-
stencilFunc:
|
|
2707
|
-
stencilFail:
|
|
2708
|
-
stencilZFail:
|
|
2709
|
-
stencilZPass:
|
|
3421
|
+
stencilFunc: NotEqualStencilFunc2,
|
|
3422
|
+
stencilFail: ReplaceStencilOp2,
|
|
3423
|
+
stencilZFail: ReplaceStencilOp2,
|
|
3424
|
+
stencilZPass: ReplaceStencilOp2
|
|
2710
3425
|
});
|
|
2711
3426
|
}
|
|
2712
3427
|
|
|
2713
3428
|
// src/section-view.tsx
|
|
2714
|
-
import { Fragment, jsx as
|
|
3429
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2715
3430
|
var FURNITURE2 = { [EXCLUDE_FROM_FRAME]: true };
|
|
2716
3431
|
function resolveSectionPlane(options, box) {
|
|
2717
3432
|
if (!options?.enabled || box.isEmpty()) return null;
|
|
2718
3433
|
const normal = options.plane?.normal ?? options.normal ?? DEFAULT_SECTION_NORMAL;
|
|
2719
|
-
const axis = new
|
|
3434
|
+
const axis = new Vector311(normal.x, normal.y, normal.z);
|
|
2720
3435
|
if (axis.lengthSq() === 0) axis.set(0, 0, 1);
|
|
2721
3436
|
axis.normalize();
|
|
2722
3437
|
const bounds = sectionBounds(box, normal);
|
|
@@ -2737,7 +3452,7 @@ function resolveSectionPlane(options, box) {
|
|
|
2737
3452
|
}
|
|
2738
3453
|
};
|
|
2739
3454
|
}
|
|
2740
|
-
var Z = new
|
|
3455
|
+
var Z = new Vector311(0, 0, 1);
|
|
2741
3456
|
var SectionView = ({
|
|
2742
3457
|
geometry,
|
|
2743
3458
|
box,
|
|
@@ -2747,67 +3462,69 @@ var SectionView = ({
|
|
|
2747
3462
|
showHandle,
|
|
2748
3463
|
onDrag
|
|
2749
3464
|
}) => {
|
|
2750
|
-
const camera =
|
|
2751
|
-
const size =
|
|
2752
|
-
const dpr =
|
|
2753
|
-
const gl =
|
|
2754
|
-
const invalidate =
|
|
2755
|
-
const controls =
|
|
2756
|
-
const domElement =
|
|
3465
|
+
const camera = useThree6((state) => state.camera);
|
|
3466
|
+
const size = useThree6((state) => state.size);
|
|
3467
|
+
const dpr = useThree6((state) => state.viewport.dpr);
|
|
3468
|
+
const gl = useThree6((state) => state.gl);
|
|
3469
|
+
const invalidate = useThree6((state) => state.invalidate);
|
|
3470
|
+
const controls = useThree6((state) => state.controls);
|
|
3471
|
+
const domElement = useThree6((state) => state.gl.domElement);
|
|
2757
3472
|
const handleRef = useRef4(null);
|
|
2758
3473
|
const [hovered, setHovered] = useState(false);
|
|
2759
3474
|
const dragging = useRef4(null);
|
|
2760
|
-
const span =
|
|
3475
|
+
const span = useMemo6(() => box.getSize(new Vector311()).length(), [box]);
|
|
2761
3476
|
const frameSize = span * SECTION_GIZMO_FRAME_SCALE;
|
|
2762
|
-
const directionColor2 =
|
|
3477
|
+
const directionColor2 = useMemo6(() => sectionDirectionColor(plane.normal), [plane]);
|
|
2763
3478
|
const resolvedHandleColor = sectionHandleColor(handleColor, directionColor2);
|
|
2764
|
-
const clip =
|
|
2765
|
-
const capPosition =
|
|
2766
|
-
const capQuaternion =
|
|
2767
|
-
const handleQuaternion =
|
|
2768
|
-
() => new Quaternion2().setFromUnitVectors(
|
|
3479
|
+
const clip = useMemo6(() => [plane], [plane]);
|
|
3480
|
+
const capPosition = useMemo6(() => sectionAnchor(box, plane), [box, plane]);
|
|
3481
|
+
const capQuaternion = useMemo6(() => new Quaternion2().setFromUnitVectors(Z, plane.normal), [plane]);
|
|
3482
|
+
const handleQuaternion = useMemo6(
|
|
3483
|
+
() => new Quaternion2().setFromUnitVectors(ARROW_AXIS2, plane.normal.clone().negate()),
|
|
2769
3484
|
[plane]
|
|
2770
3485
|
);
|
|
2771
|
-
const frameSurface =
|
|
2772
|
-
|
|
2773
|
-
const frameEdges =
|
|
2774
|
-
|
|
2775
|
-
const
|
|
2776
|
-
|
|
2777
|
-
|
|
3486
|
+
const frameSurface = useMemo6(() => new PlaneGeometry(frameSize, frameSize), [frameSize]);
|
|
3487
|
+
useEffect6(() => () => frameSurface.dispose(), [frameSurface]);
|
|
3488
|
+
const frameEdges = useMemo6(() => new EdgesGeometry(frameSurface), [frameSurface]);
|
|
3489
|
+
useEffect6(() => () => frameEdges.dispose(), [frameEdges]);
|
|
3490
|
+
const handleShape = useMemo6(() => handleGeometry(), []);
|
|
3491
|
+
useEffect6(() => () => handleShape.dispose(), [handleShape]);
|
|
3492
|
+
const stencils = useMemo6(() => createStencilMaterials([]), []);
|
|
3493
|
+
useEffect6(() => () => stencils.forEach((material) => material.dispose()), [stencils]);
|
|
3494
|
+
useLayoutEffect2(() => {
|
|
2778
3495
|
for (const material of stencils) material.clippingPlanes = clip;
|
|
2779
3496
|
}, [clip, stencils]);
|
|
2780
|
-
const mask =
|
|
2781
|
-
|
|
2782
|
-
const cap =
|
|
2783
|
-
|
|
2784
|
-
const quad =
|
|
2785
|
-
|
|
2786
|
-
const maskScene =
|
|
3497
|
+
const mask = useMemo6(() => createMaskTarget(), []);
|
|
3498
|
+
useEffect6(() => () => mask.dispose(), [mask]);
|
|
3499
|
+
const cap = useMemo6(() => createCapMaterial(mask.texture), [mask]);
|
|
3500
|
+
useEffect6(() => () => cap.dispose(), [cap]);
|
|
3501
|
+
const quad = useMemo6(() => new PlaneGeometry(span * 1.5, span * 1.5), [span]);
|
|
3502
|
+
useEffect6(() => () => quad.dispose(), [quad]);
|
|
3503
|
+
const maskScene = useMemo6(() => {
|
|
2787
3504
|
const scene = new Scene();
|
|
2788
3505
|
const [back, front] = stencils;
|
|
2789
|
-
const backMesh = new
|
|
3506
|
+
const backMesh = new Mesh4(geometry, back);
|
|
2790
3507
|
backMesh.renderOrder = SECTION_RENDER_ORDER.stencil;
|
|
2791
|
-
const frontMesh = new
|
|
3508
|
+
const frontMesh = new Mesh4(geometry, front);
|
|
2792
3509
|
frontMesh.renderOrder = SECTION_RENDER_ORDER.stencil;
|
|
2793
|
-
const maskMesh = new
|
|
3510
|
+
const maskMesh = new Mesh4(quad, createMaskMaterial());
|
|
2794
3511
|
maskMesh.renderOrder = SECTION_RENDER_ORDER.cap;
|
|
2795
3512
|
scene.add(backMesh, frontMesh, maskMesh);
|
|
2796
3513
|
return { scene, maskMesh };
|
|
2797
3514
|
}, [geometry, quad, stencils]);
|
|
2798
|
-
|
|
2799
|
-
|
|
3515
|
+
useEffect6(() => () => maskScene.maskMesh.material.dispose(), [maskScene]);
|
|
3516
|
+
useEffect6(() => {
|
|
2800
3517
|
maskScene.maskMesh.position.copy(capPosition);
|
|
2801
3518
|
maskScene.maskMesh.quaternion.copy(capQuaternion);
|
|
2802
3519
|
}, [capPosition, capQuaternion, maskScene]);
|
|
2803
|
-
|
|
2804
|
-
const buffer = gl.getDrawingBufferSize(new
|
|
3520
|
+
useLayoutEffect2(() => {
|
|
3521
|
+
const buffer = gl.getDrawingBufferSize(new Vector26());
|
|
2805
3522
|
mask.setSize(buffer.x, buffer.y);
|
|
2806
3523
|
cap.uniforms.uResolution.value.copy(buffer);
|
|
2807
3524
|
applyCapTheme(cap, theme, dpr);
|
|
2808
3525
|
invalidate();
|
|
2809
3526
|
}, [cap, dpr, gl, invalidate, mask, size, theme]);
|
|
2810
|
-
const clearColor =
|
|
3527
|
+
const clearColor = useMemo6(() => new Color5(), []);
|
|
2811
3528
|
useFrame4(({ gl: renderer, camera: eye }) => {
|
|
2812
3529
|
const previousAlpha = renderer.getClearAlpha();
|
|
2813
3530
|
renderer.getClearColor(clearColor);
|
|
@@ -2839,7 +3556,7 @@ var SectionView = ({
|
|
|
2839
3556
|
event.stopPropagation();
|
|
2840
3557
|
const view = camera.position.clone().sub(capPosition).normalize();
|
|
2841
3558
|
const surface = dragPlane(plane.normal.clone(), view, capPosition);
|
|
2842
|
-
const hit = event.ray.intersectPlane(surface, new
|
|
3559
|
+
const hit = event.ray.intersectPlane(surface, new Vector311());
|
|
2843
3560
|
const start = {
|
|
2844
3561
|
plane: surface,
|
|
2845
3562
|
from: hit ? hit.dot(plane.normal) : 0,
|
|
@@ -2848,7 +3565,7 @@ var SectionView = ({
|
|
|
2848
3565
|
dragging.current = start;
|
|
2849
3566
|
setControlsEnabled(false);
|
|
2850
3567
|
const raycaster = new Raycaster2();
|
|
2851
|
-
const pointer = new
|
|
3568
|
+
const pointer = new Vector26();
|
|
2852
3569
|
const move = (native) => {
|
|
2853
3570
|
const rect = domElement.getBoundingClientRect();
|
|
2854
3571
|
pointer.set(
|
|
@@ -2856,7 +3573,7 @@ var SectionView = ({
|
|
|
2856
3573
|
-((native.clientY - rect.top) / rect.height) * 2 + 1
|
|
2857
3574
|
);
|
|
2858
3575
|
raycaster.setFromCamera(pointer, camera);
|
|
2859
|
-
const point = raycaster.ray.intersectPlane(start.plane, new
|
|
3576
|
+
const point = raycaster.ray.intersectPlane(start.plane, new Vector311());
|
|
2860
3577
|
if (!point) return;
|
|
2861
3578
|
onDrag(start.constant - (point.dot(plane.normal) - start.from));
|
|
2862
3579
|
invalidate();
|
|
@@ -2888,8 +3605,8 @@ var SectionView = ({
|
|
|
2888
3605
|
// Excluded from framing, all of it. The cap is a quad half again as wide as
|
|
2889
3606
|
// the part's diagonal, so a Fit that measured it would frame the cut rather
|
|
2890
3607
|
// than the part and leave the part a speck in the middle of it.
|
|
2891
|
-
/* @__PURE__ */
|
|
2892
|
-
/* @__PURE__ */
|
|
3608
|
+
/* @__PURE__ */ jsxs4("group", { userData: FURNITURE2, children: [
|
|
3609
|
+
/* @__PURE__ */ jsx5(
|
|
2893
3610
|
"mesh",
|
|
2894
3611
|
{
|
|
2895
3612
|
geometry,
|
|
@@ -2898,7 +3615,7 @@ var SectionView = ({
|
|
|
2898
3615
|
raycast: () => null
|
|
2899
3616
|
}
|
|
2900
3617
|
),
|
|
2901
|
-
/* @__PURE__ */
|
|
3618
|
+
/* @__PURE__ */ jsx5(
|
|
2902
3619
|
"mesh",
|
|
2903
3620
|
{
|
|
2904
3621
|
geometry,
|
|
@@ -2907,7 +3624,7 @@ var SectionView = ({
|
|
|
2907
3624
|
raycast: () => null
|
|
2908
3625
|
}
|
|
2909
3626
|
),
|
|
2910
|
-
/* @__PURE__ */
|
|
3627
|
+
/* @__PURE__ */ jsx5(
|
|
2911
3628
|
"mesh",
|
|
2912
3629
|
{
|
|
2913
3630
|
geometry: quad,
|
|
@@ -2918,78 +3635,46 @@ var SectionView = ({
|
|
|
2918
3635
|
raycast: () => null
|
|
2919
3636
|
}
|
|
2920
3637
|
),
|
|
2921
|
-
showHandle && onDrag ? /* @__PURE__ */
|
|
2922
|
-
/* @__PURE__ */
|
|
3638
|
+
showHandle && onDrag ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3639
|
+
/* @__PURE__ */ jsxs4(
|
|
2923
3640
|
"group",
|
|
2924
3641
|
{
|
|
2925
3642
|
position: capPosition,
|
|
2926
3643
|
quaternion: capQuaternion,
|
|
2927
3644
|
renderOrder: SECTION_RENDER_ORDER.outline,
|
|
2928
3645
|
children: [
|
|
2929
|
-
/* @__PURE__ */
|
|
3646
|
+
/* @__PURE__ */ jsx5("mesh", { geometry: frameSurface, raycast: () => null, children: /* @__PURE__ */ jsx5(
|
|
2930
3647
|
"meshBasicMaterial",
|
|
2931
3648
|
{
|
|
2932
3649
|
color: directionColor2,
|
|
2933
3650
|
transparent: true,
|
|
2934
3651
|
opacity: 0.18,
|
|
2935
|
-
side:
|
|
3652
|
+
side: DoubleSide5,
|
|
2936
3653
|
depthTest: false,
|
|
2937
3654
|
depthWrite: false
|
|
2938
3655
|
}
|
|
2939
3656
|
) }),
|
|
2940
|
-
/* @__PURE__ */
|
|
3657
|
+
/* @__PURE__ */ jsx5("lineSegments", { geometry: frameEdges, raycast: () => null, children: /* @__PURE__ */ jsx5("lineBasicMaterial", { color: directionColor2, depthTest: false, depthWrite: false }) })
|
|
2941
3658
|
]
|
|
2942
3659
|
}
|
|
2943
3660
|
),
|
|
2944
|
-
/* @__PURE__ */
|
|
3661
|
+
/* @__PURE__ */ jsx5(
|
|
2945
3662
|
"group",
|
|
2946
3663
|
{
|
|
2947
3664
|
ref: handleRef,
|
|
2948
3665
|
position: capPosition,
|
|
2949
3666
|
quaternion: handleQuaternion,
|
|
2950
3667
|
renderOrder: SECTION_RENDER_ORDER.handle,
|
|
2951
|
-
children:
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
] }),
|
|
2962
|
-
/* @__PURE__ */ jsxs3("mesh", { ...grab, children: [
|
|
2963
|
-
/* @__PURE__ */ jsx4("cylinderGeometry", { args: [0.035, 0.035, 0.9, 12] }),
|
|
2964
|
-
/* @__PURE__ */ jsx4(
|
|
2965
|
-
"meshBasicMaterial",
|
|
2966
|
-
{
|
|
2967
|
-
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2968
|
-
depthTest: false
|
|
2969
|
-
}
|
|
2970
|
-
)
|
|
2971
|
-
] }),
|
|
2972
|
-
/* @__PURE__ */ jsxs3("mesh", { position: [0, 0.61, 0], ...grab, children: [
|
|
2973
|
-
/* @__PURE__ */ jsx4("coneGeometry", { args: [0.15, 0.3, 20] }),
|
|
2974
|
-
/* @__PURE__ */ jsx4(
|
|
2975
|
-
"meshBasicMaterial",
|
|
2976
|
-
{
|
|
2977
|
-
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2978
|
-
depthTest: false
|
|
2979
|
-
}
|
|
2980
|
-
)
|
|
2981
|
-
] }),
|
|
2982
|
-
/* @__PURE__ */ jsxs3("mesh", { position: [0, -0.61, 0], rotation: [Math.PI, 0, 0], ...grab, children: [
|
|
2983
|
-
/* @__PURE__ */ jsx4("coneGeometry", { args: [0.15, 0.3, 20] }),
|
|
2984
|
-
/* @__PURE__ */ jsx4(
|
|
2985
|
-
"meshBasicMaterial",
|
|
2986
|
-
{
|
|
2987
|
-
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2988
|
-
depthTest: false
|
|
2989
|
-
}
|
|
2990
|
-
)
|
|
2991
|
-
] })
|
|
2992
|
-
]
|
|
3668
|
+
children: /* @__PURE__ */ jsx5(
|
|
3669
|
+
ArrowMesh,
|
|
3670
|
+
{
|
|
3671
|
+
geometry: handleShape,
|
|
3672
|
+
color: hovered ? theme.hover : resolvedHandleColor,
|
|
3673
|
+
opacity: 1,
|
|
3674
|
+
onTop: true,
|
|
3675
|
+
events: grab
|
|
3676
|
+
}
|
|
3677
|
+
)
|
|
2993
3678
|
}
|
|
2994
3679
|
)
|
|
2995
3680
|
] }) : null
|
|
@@ -2998,11 +3683,11 @@ var SectionView = ({
|
|
|
2998
3683
|
};
|
|
2999
3684
|
|
|
3000
3685
|
// src/content-box.ts
|
|
3001
|
-
import { useFrame as useFrame5, useThree as
|
|
3686
|
+
import { useFrame as useFrame5, useThree as useThree7 } from "@react-three/fiber";
|
|
3002
3687
|
import { useRef as useRef5, useState as useState2 } from "react";
|
|
3003
3688
|
import { Box3 as Box34 } from "three";
|
|
3004
3689
|
function useContentBox() {
|
|
3005
|
-
const scene =
|
|
3690
|
+
const scene = useThree7((state) => state.scene);
|
|
3006
3691
|
const [box, setBox] = useState2(() => new Box34());
|
|
3007
3692
|
const measured = useRef5(false);
|
|
3008
3693
|
useFrame5(() => {
|
|
@@ -3017,7 +3702,7 @@ function useContentBox() {
|
|
|
3017
3702
|
}
|
|
3018
3703
|
|
|
3019
3704
|
// src/part-mesh.tsx
|
|
3020
|
-
import { Fragment as
|
|
3705
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
3021
3706
|
var PartMesh = ({
|
|
3022
3707
|
model,
|
|
3023
3708
|
geometry,
|
|
@@ -3038,17 +3723,19 @@ var PartMesh = ({
|
|
|
3038
3723
|
onPick,
|
|
3039
3724
|
theme,
|
|
3040
3725
|
showEdges = true,
|
|
3726
|
+
sharpCorners = null,
|
|
3041
3727
|
display = "solid",
|
|
3042
3728
|
children
|
|
3043
3729
|
}) => {
|
|
3044
|
-
const { camera, controls, invalidate } =
|
|
3045
|
-
const context =
|
|
3730
|
+
const { camera, controls, invalidate, size } = useThree8();
|
|
3731
|
+
const context = useMemo7(() => ({ model, geometry }), [model, geometry]);
|
|
3046
3732
|
const viewerControls = useViewerControls();
|
|
3047
3733
|
const resolved = useStableTheme(theme);
|
|
3048
3734
|
const currentTheme = useRef6(resolved);
|
|
3049
3735
|
currentTheme.current = resolved;
|
|
3050
|
-
const part =
|
|
3736
|
+
const part = useMemo7(() => createPart(model, geometry, currentTheme.current), [geometry, model]);
|
|
3051
3737
|
const hoverRegion = useRef6(null);
|
|
3738
|
+
const hoverCorner = useRef6(null);
|
|
3052
3739
|
const onHoverRef = useRef6(onHover);
|
|
3053
3740
|
onHoverRef.current = onHover;
|
|
3054
3741
|
const box = useContentBox();
|
|
@@ -3056,7 +3743,7 @@ var PartMesh = ({
|
|
|
3056
3743
|
const shared = useSyncExternalStore(store.subscribe, store.get, store.get);
|
|
3057
3744
|
const controlled = section !== void 0;
|
|
3058
3745
|
const options = controlled ? section : shared ?? void 0;
|
|
3059
|
-
const cut =
|
|
3746
|
+
const cut = useMemo7(() => resolveSectionPlane(options, box), [box, options]);
|
|
3060
3747
|
const engaged = useSyncExternalStore(store.subscribe, store.isEngaged, store.isEngaged);
|
|
3061
3748
|
const pressedWhileEngaged = useRef6(false);
|
|
3062
3749
|
const layers = useRef6({
|
|
@@ -3079,24 +3766,37 @@ var PartMesh = ({
|
|
|
3079
3766
|
const { hoveredFeatureIds: hoveredFeatures, ...rest } = layers.current;
|
|
3080
3767
|
applyHighlightLayers(
|
|
3081
3768
|
part,
|
|
3082
|
-
{
|
|
3769
|
+
{
|
|
3770
|
+
...rest,
|
|
3771
|
+
hoveredFeatures,
|
|
3772
|
+
// On a corner the corner is what is hovered, in the hover colour; the
|
|
3773
|
+
// face it lies on is not painted as if the pointer meant it.
|
|
3774
|
+
hoverRegion: hoverCorner.current === null ? hoverRegion.current : null
|
|
3775
|
+
},
|
|
3083
3776
|
currentTheme.current
|
|
3084
3777
|
);
|
|
3085
3778
|
invalidate();
|
|
3086
3779
|
}, [invalidate, part]);
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3780
|
+
const dropHover = useCallback3(() => {
|
|
3781
|
+
hoverRegion.current = null;
|
|
3782
|
+
hoverCorner.current = null;
|
|
3783
|
+
part.setHoveredSharpCorner(null);
|
|
3784
|
+
repaint();
|
|
3785
|
+
onHoverRef.current?.(null);
|
|
3786
|
+
}, [part, repaint]);
|
|
3787
|
+
useEffect7(() => () => part.dispose(), [part]);
|
|
3788
|
+
const adjacency = useMemo7(() => regionAdjacency(model, geometry), [model, geometry]);
|
|
3789
|
+
useEffect7(() => {
|
|
3090
3790
|
onAdjacency?.(adjacency);
|
|
3091
3791
|
}, [adjacency, onAdjacency]);
|
|
3092
3792
|
const framed = useRef6(null);
|
|
3093
|
-
|
|
3793
|
+
useEffect7(() => {
|
|
3094
3794
|
if (focusFeature === null || focusFeature === framed.current) return;
|
|
3095
3795
|
framed.current = focusFeature;
|
|
3096
3796
|
const box2 = part.boxForFeature(focusFeature);
|
|
3097
3797
|
if (box2) viewerControls.frameBox(box2);
|
|
3098
3798
|
}, [focusFeature, part, viewerControls]);
|
|
3099
|
-
|
|
3799
|
+
useLayoutEffect3(() => {
|
|
3100
3800
|
part.setTheme(resolved);
|
|
3101
3801
|
repaint();
|
|
3102
3802
|
}, [part, repaint, resolved]);
|
|
@@ -3105,20 +3805,28 @@ var PartMesh = ({
|
|
|
3105
3805
|
const selectionRef = useRef6(selection);
|
|
3106
3806
|
selectionRef.current = selection;
|
|
3107
3807
|
const focusKey = focusStateKey(focus, selection);
|
|
3108
|
-
|
|
3808
|
+
useLayoutEffect3(() => {
|
|
3109
3809
|
part.setFocus(selectionRef.current, focusRef.current);
|
|
3110
3810
|
invalidate();
|
|
3111
3811
|
}, [focusKey, invalidate, part]);
|
|
3112
|
-
|
|
3812
|
+
useLayoutEffect3(() => {
|
|
3113
3813
|
part.setDisplay(display, showEdges);
|
|
3114
3814
|
invalidate();
|
|
3115
3815
|
}, [display, invalidate, part, showEdges]);
|
|
3116
|
-
|
|
3816
|
+
useLayoutEffect3(() => {
|
|
3117
3817
|
part.setClippingPlanes(cut ? [cut.plane] : null);
|
|
3118
3818
|
invalidate();
|
|
3119
3819
|
}, [cut, invalidate, part]);
|
|
3820
|
+
const sharpCornersRef = useRef6(sharpCorners);
|
|
3821
|
+
sharpCornersRef.current = sharpCorners;
|
|
3822
|
+
const sharpKey = sharpCorners ? sharpCornerKey(sharpCorners) : "";
|
|
3823
|
+
useLayoutEffect3(() => {
|
|
3824
|
+
part.setSharpCorners(sharpCornersRef.current);
|
|
3825
|
+
if (hoverCorner.current !== null) dropHover();
|
|
3826
|
+
invalidate();
|
|
3827
|
+
}, [dropHover, invalidate, part, sharpKey]);
|
|
3120
3828
|
const reportedSection = useRef6("");
|
|
3121
|
-
|
|
3829
|
+
useLayoutEffect3(() => {
|
|
3122
3830
|
const state = cut?.state ?? null;
|
|
3123
3831
|
const key = state ? `${state.constant}|${state.normal.x},${state.normal.y},${state.normal.z}` : "";
|
|
3124
3832
|
if (key === reportedSection.current) return;
|
|
@@ -3135,12 +3843,12 @@ var PartMesh = ({
|
|
|
3135
3843
|
highlights.map((entry) => `${entry.tag}:${entry.color}:${entry.weight ?? ""}`).join(" "),
|
|
3136
3844
|
regionHighlights.map((entry) => `${entry.region}:${entry.color}:${entry.weight ?? ""}`).join(" ")
|
|
3137
3845
|
].join("|");
|
|
3138
|
-
|
|
3846
|
+
useLayoutEffect3(() => {
|
|
3139
3847
|
repaint();
|
|
3140
3848
|
}, [layerKey, repaint]);
|
|
3141
3849
|
const isTap = useTapGuard();
|
|
3142
3850
|
const retarget = useRetarget();
|
|
3143
|
-
const doubles =
|
|
3851
|
+
const doubles = useMemo7(() => trackDoubleTaps(), []);
|
|
3144
3852
|
const pickFor = (event, doubled = false) => {
|
|
3145
3853
|
const triangleIndex = event.faceIndex;
|
|
3146
3854
|
if (triangleIndex == null) return null;
|
|
@@ -3149,7 +3857,7 @@ var PartMesh = ({
|
|
|
3149
3857
|
const target = readTarget(controls);
|
|
3150
3858
|
const normal = event.face?.normal ?? UP;
|
|
3151
3859
|
const source = event.nativeEvent;
|
|
3152
|
-
|
|
3860
|
+
const pick = buildPick({
|
|
3153
3861
|
model,
|
|
3154
3862
|
region,
|
|
3155
3863
|
triangleIndex,
|
|
@@ -3167,26 +3875,27 @@ var PartMesh = ({
|
|
|
3167
3875
|
secondary: "button" in source && source.button === 2
|
|
3168
3876
|
}
|
|
3169
3877
|
});
|
|
3878
|
+
const corner = part.sharpCornerAt({ point: event.point, region }, camera, size);
|
|
3879
|
+
return corner ? { ...pick, sharpCorner: corner } : pick;
|
|
3170
3880
|
};
|
|
3171
3881
|
const emitHover = (next) => {
|
|
3172
3882
|
const region = next?.region ?? null;
|
|
3173
|
-
|
|
3883
|
+
const corner = next?.sharpCorner?.index ?? null;
|
|
3884
|
+
if (hoverRegion.current === region && hoverCorner.current === corner) return;
|
|
3174
3885
|
hoverRegion.current = region;
|
|
3886
|
+
hoverCorner.current = corner;
|
|
3887
|
+
part.setHoveredSharpCorner(corner);
|
|
3175
3888
|
repaint();
|
|
3176
3889
|
onHover?.(next);
|
|
3177
3890
|
};
|
|
3178
|
-
|
|
3891
|
+
useLayoutEffect3(() => {
|
|
3179
3892
|
if (hover || hoverRegion.current === null) return;
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
}, [hover, repaint]);
|
|
3184
|
-
useLayoutEffect2(() => {
|
|
3893
|
+
dropHover();
|
|
3894
|
+
}, [dropHover, hover]);
|
|
3895
|
+
useLayoutEffect3(() => {
|
|
3185
3896
|
if (!engaged || hoverRegion.current === null) return;
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
onHoverRef.current?.(null);
|
|
3189
|
-
}, [engaged, repaint]);
|
|
3897
|
+
dropHover();
|
|
3898
|
+
}, [dropHover, engaged]);
|
|
3190
3899
|
const dragSection = useCallback3(
|
|
3191
3900
|
(constant) => {
|
|
3192
3901
|
if (!cut) return;
|
|
@@ -3205,8 +3914,8 @@ var PartMesh = ({
|
|
|
3205
3914
|
},
|
|
3206
3915
|
[box, controlled, cut, onSectionChange, options, store]
|
|
3207
3916
|
);
|
|
3208
|
-
return /* @__PURE__ */
|
|
3209
|
-
/* @__PURE__ */
|
|
3917
|
+
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3918
|
+
/* @__PURE__ */ jsx6(
|
|
3210
3919
|
"primitive",
|
|
3211
3920
|
{
|
|
3212
3921
|
object: part.object,
|
|
@@ -3243,7 +3952,7 @@ var PartMesh = ({
|
|
|
3243
3952
|
}
|
|
3244
3953
|
}
|
|
3245
3954
|
),
|
|
3246
|
-
cut ? /* @__PURE__ */
|
|
3955
|
+
cut ? /* @__PURE__ */ jsx6(
|
|
3247
3956
|
SectionView,
|
|
3248
3957
|
{
|
|
3249
3958
|
geometry,
|
|
@@ -3255,12 +3964,12 @@ var PartMesh = ({
|
|
|
3255
3964
|
onDrag: !controlled || onSectionChange ? dragSection : void 0
|
|
3256
3965
|
}
|
|
3257
3966
|
) : null,
|
|
3258
|
-
children ? /* @__PURE__ */
|
|
3967
|
+
children ? /* @__PURE__ */ jsx6(PartContext.Provider, { value: context, children }) : null
|
|
3259
3968
|
] });
|
|
3260
3969
|
};
|
|
3261
|
-
var ORIGIN = new
|
|
3262
|
-
var UP = new
|
|
3263
|
-
var TARGET = new
|
|
3970
|
+
var ORIGIN = new Vector312();
|
|
3971
|
+
var UP = new Vector312(0, 0, 1);
|
|
3972
|
+
var TARGET = new Vector312();
|
|
3264
3973
|
function readTarget(controls) {
|
|
3265
3974
|
if (controls && typeof controls.getTarget === "function") {
|
|
3266
3975
|
return controls.getTarget(TARGET);
|
|
@@ -3276,7 +3985,7 @@ function useStableTheme(theme) {
|
|
|
3276
3985
|
}
|
|
3277
3986
|
|
|
3278
3987
|
// src/engine/geometry.ts
|
|
3279
|
-
import { Matrix4 as Matrix42, Mesh as
|
|
3988
|
+
import { Matrix4 as Matrix42, Mesh as Mesh5 } from "three";
|
|
3280
3989
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
3281
3990
|
import { STLLoader } from "three/examples/jsm/loaders/STLLoader.js";
|
|
3282
3991
|
var PartMeshError = class extends Error {
|
|
@@ -3351,7 +4060,7 @@ function parseStl(data, mesh) {
|
|
|
3351
4060
|
function singleMesh(scene) {
|
|
3352
4061
|
const meshes = [];
|
|
3353
4062
|
scene.traverse((object) => {
|
|
3354
|
-
if (object instanceof
|
|
4063
|
+
if (object instanceof Mesh5) meshes.push(object);
|
|
3355
4064
|
});
|
|
3356
4065
|
const [mesh] = meshes;
|
|
3357
4066
|
if (mesh === void 0 || meshes.length !== 1) {
|
|
@@ -3387,7 +4096,7 @@ function assertCounts(geometry, expected) {
|
|
|
3387
4096
|
}
|
|
3388
4097
|
function disposeMaterials(scene) {
|
|
3389
4098
|
scene.traverse((object) => {
|
|
3390
|
-
if (!(object instanceof
|
|
4099
|
+
if (!(object instanceof Mesh5)) return;
|
|
3391
4100
|
for (const material of Array.isArray(object.material) ? object.material : [object.material]) {
|
|
3392
4101
|
material.dispose();
|
|
3393
4102
|
}
|
|
@@ -3395,7 +4104,7 @@ function disposeMaterials(scene) {
|
|
|
3395
4104
|
}
|
|
3396
4105
|
|
|
3397
4106
|
// src/engine/normals.ts
|
|
3398
|
-
import { Float32BufferAttribute as
|
|
4107
|
+
import { Float32BufferAttribute as Float32BufferAttribute5 } from "three";
|
|
3399
4108
|
function smoothRegionNormals(geometry, regions) {
|
|
3400
4109
|
const position = geometry.getAttribute("position");
|
|
3401
4110
|
if (!position || geometry.index) return;
|
|
@@ -3461,7 +4170,7 @@ function smoothRegionNormals(geometry, regions) {
|
|
|
3461
4170
|
normals[vertex * 3 + 1] = y / length;
|
|
3462
4171
|
normals[vertex * 3 + 2] = z / length;
|
|
3463
4172
|
}
|
|
3464
|
-
geometry.setAttribute("normal", new
|
|
4173
|
+
geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
|
|
3465
4174
|
}
|
|
3466
4175
|
|
|
3467
4176
|
// src/engine/geometry-cache.ts
|
|
@@ -3884,15 +4593,15 @@ function compareVersions(a, b) {
|
|
|
3884
4593
|
}
|
|
3885
4594
|
|
|
3886
4595
|
// src/engine/engine-part.tsx
|
|
3887
|
-
import { jsx as
|
|
4596
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
3888
4597
|
var EnginePart = ({ report, ...props }) => {
|
|
3889
|
-
const model =
|
|
4598
|
+
const model = useMemo8(() => normalizePartReport(report), [report]);
|
|
3890
4599
|
const resource = useGeometryResource(model);
|
|
3891
|
-
|
|
4600
|
+
useEffect8(() => {
|
|
3892
4601
|
engineGeometryCache.retain(resource);
|
|
3893
4602
|
return () => engineGeometryCache.release(resource);
|
|
3894
4603
|
}, [resource]);
|
|
3895
|
-
return /* @__PURE__ */
|
|
4604
|
+
return /* @__PURE__ */ jsx7(PartMesh, { model, geometry: resource.geometry, ...props });
|
|
3896
4605
|
};
|
|
3897
4606
|
function useGeometryResource(part) {
|
|
3898
4607
|
const resource = engineGeometryCache.get(part);
|
|
@@ -4001,11 +4710,14 @@ export {
|
|
|
4001
4710
|
useTapGuard,
|
|
4002
4711
|
visualSurfaces,
|
|
4003
4712
|
regionEdgesGeometry,
|
|
4713
|
+
regionAdjacency,
|
|
4714
|
+
surfaceCreases,
|
|
4715
|
+
findSharpCorners,
|
|
4716
|
+
sharpCornerPositions,
|
|
4004
4717
|
REGION_ATTRIBUTE,
|
|
4005
4718
|
buildRegionTexels,
|
|
4006
4719
|
buildRegionAttribute,
|
|
4007
4720
|
createPart,
|
|
4008
|
-
regionAdjacency,
|
|
4009
4721
|
FEATURE_TYPE_RANKS,
|
|
4010
4722
|
featureTypeRank,
|
|
4011
4723
|
rankOwners,
|
|
@@ -4045,11 +4757,9 @@ export {
|
|
|
4045
4757
|
useSectionStore,
|
|
4046
4758
|
useRetarget,
|
|
4047
4759
|
Viewer,
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
SHAFT_RADIUS,
|
|
4052
|
-
arrowPlacement,
|
|
4760
|
+
ArrowMesh,
|
|
4761
|
+
ARROW_AXIS2 as ARROW_AXIS,
|
|
4762
|
+
arrowGeometry,
|
|
4053
4763
|
createMaskTarget,
|
|
4054
4764
|
createCapMaterial,
|
|
4055
4765
|
applyCapTheme,
|