brep-io-kernel 1.0.21 → 1.0.22
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 +4 -1
- package/dist-kernel/brep-kernel.js +11065 -10512
- package/package.json +3 -2
- package/src/BREP/Edge.js +2 -0
- package/src/BREP/Face.js +2 -0
- package/src/BREP/SolidMethods/visualize.js +372 -365
- package/src/BREP/Vertex.js +2 -17
- package/src/PartHistory.js +4 -25
- package/src/SketchSolver2D.js +3 -0
- package/src/UI/AccordionWidget.js +1 -1
- package/src/UI/EnvMonacoEditor.js +0 -3
- package/src/UI/HistoryWidget.js +3 -0
- package/src/UI/SceneListing.js +45 -7
- package/src/UI/SelectionFilter.js +469 -442
- package/src/UI/SelectionState.js +464 -0
- package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +40 -1
- package/src/UI/assembly/AssemblyConstraintsWidget.js +17 -3
- package/src/UI/assembly/constraintSelectionUtils.js +3 -182
- package/src/UI/{assembly/constraintFaceUtils.js → faceUtils.js} +30 -5
- package/src/UI/featureDialogs.js +99 -69
- package/src/UI/pmi/LabelOverlay.js +32 -0
- package/src/UI/pmi/PMIMode.js +23 -0
- package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +7 -1
- package/src/UI/toolbarButtons/orientToFaceButton.js +3 -36
- package/src/UI/toolbarButtons/registerDefaultButtons.js +2 -0
- package/src/UI/toolbarButtons/selectionStateButton.js +206 -0
- package/src/UI/viewer.js +16 -16
- package/src/assemblyConstraints/AssemblyConstraintHistory.js +18 -42
- package/src/assemblyConstraints/constraints/AngleConstraint.js +1 -0
- package/src/assemblyConstraints/constraints/DistanceConstraint.js +1 -0
- package/src/features/selectionUtils.js +21 -5
- package/src/features/sketch/SketchFeature.js +2 -2
- package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +3 -2
- package/src/utils/selectionResolver.js +258 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
const DEFAULT_SPLIT_REGEX = /›|>|\/|\||→|->/;
|
|
2
|
+
|
|
3
|
+
export function scoreObjectForNormal(object) {
|
|
4
|
+
if (!object) return -Infinity;
|
|
5
|
+
const type = object.userData?.type || object.userData?.brepType || object.type;
|
|
6
|
+
if (String(type).toUpperCase() === 'FACE') return 3;
|
|
7
|
+
if (object.geometry) return 2;
|
|
8
|
+
return 1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function resolveSelectionObject(scene, selection, options = {}) {
|
|
12
|
+
const {
|
|
13
|
+
scoreFn = null,
|
|
14
|
+
nameResolver = null,
|
|
15
|
+
arrayMode = 'firstResolved',
|
|
16
|
+
allowJson = true,
|
|
17
|
+
allowUuid = undefined,
|
|
18
|
+
allowUuidString = true,
|
|
19
|
+
allowUuidObject = true,
|
|
20
|
+
allowFuzzyName = true,
|
|
21
|
+
allowNameContains = true,
|
|
22
|
+
allowPath = true,
|
|
23
|
+
allowReference = true,
|
|
24
|
+
allowTarget = true,
|
|
25
|
+
allowSelectionName = true,
|
|
26
|
+
allowObjectPassthrough = false,
|
|
27
|
+
} = options;
|
|
28
|
+
|
|
29
|
+
const uuidString = allowUuid ?? allowUuidString;
|
|
30
|
+
const uuidObject = allowUuid ?? allowUuidObject;
|
|
31
|
+
|
|
32
|
+
return internalResolveSelectionObject(scene, selection, {
|
|
33
|
+
scoreFn,
|
|
34
|
+
nameResolver,
|
|
35
|
+
arrayMode,
|
|
36
|
+
allowJson,
|
|
37
|
+
allowUuidString: uuidString,
|
|
38
|
+
allowUuidObject: uuidObject,
|
|
39
|
+
allowFuzzyName,
|
|
40
|
+
allowNameContains,
|
|
41
|
+
allowPath,
|
|
42
|
+
allowReference,
|
|
43
|
+
allowTarget,
|
|
44
|
+
allowSelectionName,
|
|
45
|
+
allowObjectPassthrough,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function internalResolveSelectionObject(scene, selection, options) {
|
|
50
|
+
if (selection == null) return null;
|
|
51
|
+
if (selection.isObject3D) return selection;
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(selection)) {
|
|
54
|
+
if (options.arrayMode === 'first') {
|
|
55
|
+
const first = selection.find((item) => item != null);
|
|
56
|
+
return internalResolveSelectionObject(scene, first, options);
|
|
57
|
+
}
|
|
58
|
+
for (const item of selection) {
|
|
59
|
+
const resolved = internalResolveSelectionObject(scene, item, options);
|
|
60
|
+
if (resolved) return resolved;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof selection === 'string') {
|
|
66
|
+
return resolveObjectFromString(scene, selection, options);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof selection === 'object') {
|
|
70
|
+
if (selection.isObject3D) return selection;
|
|
71
|
+
|
|
72
|
+
const {
|
|
73
|
+
uuid,
|
|
74
|
+
name,
|
|
75
|
+
id,
|
|
76
|
+
path,
|
|
77
|
+
reference,
|
|
78
|
+
target,
|
|
79
|
+
selectionName,
|
|
80
|
+
} = selection;
|
|
81
|
+
|
|
82
|
+
if (options.allowUuidObject && typeof uuid === 'string' && scene?.getObjectByProperty) {
|
|
83
|
+
try {
|
|
84
|
+
const found = scene.getObjectByProperty('uuid', uuid);
|
|
85
|
+
if (found) return found;
|
|
86
|
+
} catch { /* ignore */ }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const resolveCandidate = (candidate) => (
|
|
90
|
+
typeof candidate === 'string'
|
|
91
|
+
? resolveObjectFromString(scene, candidate, options)
|
|
92
|
+
: null
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const nameCandidate = typeof name === 'string'
|
|
96
|
+
? name
|
|
97
|
+
: (options.allowSelectionName && typeof selectionName === 'string' ? selectionName : null);
|
|
98
|
+
const idCandidate = typeof id === 'string' ? id : null;
|
|
99
|
+
|
|
100
|
+
const nameResolved = resolveCandidate(nameCandidate);
|
|
101
|
+
if (nameResolved) return nameResolved;
|
|
102
|
+
|
|
103
|
+
const idResolved = resolveCandidate(idCandidate);
|
|
104
|
+
if (idResolved) return idResolved;
|
|
105
|
+
|
|
106
|
+
if (options.allowPath && Array.isArray(path)) {
|
|
107
|
+
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
108
|
+
const segment = path[i];
|
|
109
|
+
if (typeof segment !== 'string') continue;
|
|
110
|
+
const resolved = resolveObjectFromString(scene, segment, options);
|
|
111
|
+
if (resolved) return resolved;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (options.allowReference && reference != null) {
|
|
116
|
+
const resolved = internalResolveSelectionObject(scene, reference, options);
|
|
117
|
+
if (resolved) return resolved;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (options.allowTarget && target != null) {
|
|
121
|
+
const resolved = internalResolveSelectionObject(scene, target, options);
|
|
122
|
+
if (resolved) return resolved;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return options.allowObjectPassthrough ? selection : null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function resolveObjectFromString(scene, value, options) {
|
|
132
|
+
if (typeof value !== 'string') return null;
|
|
133
|
+
const trimmed = value.trim();
|
|
134
|
+
if (!trimmed) return null;
|
|
135
|
+
|
|
136
|
+
if (options.allowJson && isProbablyJson(trimmed)) {
|
|
137
|
+
try {
|
|
138
|
+
const parsed = JSON.parse(trimmed);
|
|
139
|
+
if (parsed != null) {
|
|
140
|
+
const resolved = internalResolveSelectionObject(scene, parsed, options);
|
|
141
|
+
if (resolved) return resolved;
|
|
142
|
+
}
|
|
143
|
+
} catch { /* ignore JSON parse errors */ }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (typeof options.nameResolver === 'function') {
|
|
147
|
+
try {
|
|
148
|
+
const direct = options.nameResolver(trimmed);
|
|
149
|
+
if (direct) return direct;
|
|
150
|
+
} catch { /* ignore */ }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (scene) {
|
|
154
|
+
const direct = findObjectByName(scene, trimmed, options.scoreFn);
|
|
155
|
+
if (direct) return direct;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (options.allowUuidString && scene?.getObjectByProperty && looksLikeUUID(trimmed)) {
|
|
159
|
+
try {
|
|
160
|
+
const byUuid = scene.getObjectByProperty('uuid', trimmed);
|
|
161
|
+
if (byUuid) return byUuid;
|
|
162
|
+
} catch { /* ignore */ }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!scene) return null;
|
|
166
|
+
|
|
167
|
+
if (options.allowFuzzyName) {
|
|
168
|
+
const candidates = new Set();
|
|
169
|
+
candidates.add(trimmed);
|
|
170
|
+
|
|
171
|
+
const splitByDelims = trimmed.split(DEFAULT_SPLIT_REGEX);
|
|
172
|
+
if (splitByDelims.length > 1) {
|
|
173
|
+
for (const segment of splitByDelims) {
|
|
174
|
+
const s = segment.trim();
|
|
175
|
+
if (s) candidates.add(s);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (trimmed.includes(':')) {
|
|
180
|
+
for (const segment of trimmed.split(':')) {
|
|
181
|
+
const s = segment.trim();
|
|
182
|
+
if (s) candidates.add(s);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (const candidate of candidates) {
|
|
187
|
+
const found = findObjectByName(scene, candidate, options.scoreFn);
|
|
188
|
+
if (found) return found;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (options.allowNameContains) {
|
|
193
|
+
let fallback = null;
|
|
194
|
+
try {
|
|
195
|
+
scene.traverse?.((obj) => {
|
|
196
|
+
if (fallback || !obj?.name) return;
|
|
197
|
+
if (!trimmed.includes(obj.name)) return;
|
|
198
|
+
if (!fallback) {
|
|
199
|
+
fallback = obj;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const currentScore = scoreObject(fallback, options.scoreFn);
|
|
203
|
+
const nextScore = scoreObject(obj, options.scoreFn);
|
|
204
|
+
if (nextScore > currentScore || obj.name.length > fallback.name.length) {
|
|
205
|
+
fallback = obj;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
} catch { /* ignore */ }
|
|
209
|
+
return fallback;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function findObjectByName(scene, name, scoreFn) {
|
|
216
|
+
if (!scene || typeof name !== 'string' || !name) return null;
|
|
217
|
+
|
|
218
|
+
if (typeof scene.traverse !== 'function') {
|
|
219
|
+
return scene?.getObjectByName?.(name) || null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let best = null;
|
|
223
|
+
scene.traverse((obj) => {
|
|
224
|
+
if (!obj || obj.name !== name) return;
|
|
225
|
+
if (!best) {
|
|
226
|
+
best = obj;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const currentScore = scoreObject(best, scoreFn);
|
|
230
|
+
const nextScore = scoreObject(obj, scoreFn);
|
|
231
|
+
if (nextScore > currentScore) best = obj;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
if (best) return best;
|
|
235
|
+
if (typeof scene.getObjectByName === 'function') return scene.getObjectByName(name);
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function scoreObject(object, scoreFn) {
|
|
240
|
+
if (typeof scoreFn !== 'function') return 0;
|
|
241
|
+
try {
|
|
242
|
+
const score = scoreFn(object);
|
|
243
|
+
return Number.isFinite(score) ? score : 0;
|
|
244
|
+
} catch {
|
|
245
|
+
return 0;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function looksLikeUUID(value) {
|
|
250
|
+
if (typeof value !== 'string') return false;
|
|
251
|
+
const trimmed = value.trim();
|
|
252
|
+
if (trimmed.length !== 36) return false;
|
|
253
|
+
return /^[0-9a-fA-F-]{36}$/.test(trimmed);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function isProbablyJson(value) {
|
|
257
|
+
return (value.startsWith('{') && value.endsWith('}')) || (value.startsWith('[') && value.endsWith(']'));
|
|
258
|
+
}
|