@shapediver/viewer.data-engine.geometry-engine 3.3.4 → 3.3.7
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/package.json +12 -13
- package/src/GeometryEngine.ts +0 -149
- package/src/gltfv1/GLTFLoader.ts +0 -356
- package/src/gltfv1/SDGTFLoader.ts +0 -823
- package/src/gltfv2/GLTFLoader.ts +0 -527
- package/src/gltfv2/draco/draco_decoder.js +0 -36
- package/src/gltfv2/loaders/AccessorLoader.ts +0 -100
- package/src/gltfv2/loaders/BufferLoader.ts +0 -76
- package/src/gltfv2/loaders/BufferViewLoader.ts +0 -48
- package/src/gltfv2/loaders/GeometryLoader.ts +0 -220
- package/src/gltfv2/loaders/MaterialLoader.ts +0 -380
- package/src/gltfv2/loaders/TextureLoader.ts +0 -116
- package/src/index.ts +0 -5
- package/tsconfig.json +0 -19
|
@@ -1,823 +0,0 @@
|
|
|
1
|
-
import { ITreeNode, TreeNode } from '@shapediver/viewer.shared.node-tree'
|
|
2
|
-
import { Logger, ShapeDiverViewerDataProcessingError } from '@shapediver/viewer.shared.services'
|
|
3
|
-
import {
|
|
4
|
-
ACCESSORCOMPONENTTYPE_V1 as ACCESSOR_COMPONENTTYPE,
|
|
5
|
-
ACCESSORTYPE_V1 as ACCESSORTYPE,
|
|
6
|
-
ISDGTF_v1,
|
|
7
|
-
} from '@shapediver/viewer.data-engine.shared-types'
|
|
8
|
-
import {
|
|
9
|
-
AttributeData,
|
|
10
|
-
GeometryData,
|
|
11
|
-
MaterialStandardData,
|
|
12
|
-
PRIMITIVE_MODE,
|
|
13
|
-
PrimitiveData,
|
|
14
|
-
} from '@shapediver/viewer.shared.types'
|
|
15
|
-
import { mat4, vec3, vec4 } from 'gl-matrix'
|
|
16
|
-
|
|
17
|
-
export class SDGTFLoader {
|
|
18
|
-
// #region Properties (5)
|
|
19
|
-
|
|
20
|
-
private readonly BINARY_EXTENSION_HEADER_LENGTH = 20;
|
|
21
|
-
private readonly _logger: Logger = Logger.instance;
|
|
22
|
-
|
|
23
|
-
private _body!: ArrayBuffer;
|
|
24
|
-
private _content!: ISDGTF_v1;
|
|
25
|
-
|
|
26
|
-
// #endregion Properties (5)
|
|
27
|
-
|
|
28
|
-
// #region Public Methods (1)
|
|
29
|
-
|
|
30
|
-
public async load(binaryGeometry: ArrayBuffer, gltfLength: number): Promise<ITreeNode> {
|
|
31
|
-
if (gltfLength < binaryGeometry.byteLength) {
|
|
32
|
-
const headerDataView = new DataView(binaryGeometry, gltfLength, this.BINARY_EXTENSION_HEADER_LENGTH + 1);
|
|
33
|
-
const header = {
|
|
34
|
-
magic: String.fromCharCode(headerDataView.getUint8(0)) + String.fromCharCode(headerDataView.getUint8(1)) + String.fromCharCode(headerDataView.getUint8(2)) + String.fromCharCode(headerDataView.getUint8(3)) + String.fromCharCode(headerDataView.getUint8(4)),
|
|
35
|
-
version: headerDataView.getUint32(5, true),
|
|
36
|
-
length: headerDataView.getUint32(9, true),
|
|
37
|
-
contentLength: headerDataView.getUint32(13, true),
|
|
38
|
-
contentFormat: headerDataView.getUint32(17, true)
|
|
39
|
-
}
|
|
40
|
-
if (header.magic != 'sdgTF')
|
|
41
|
-
throw new ShapeDiverViewerDataProcessingError('SDGTFLoader.load: Invalid data: sdgTF magic wrong.');
|
|
42
|
-
|
|
43
|
-
// create content
|
|
44
|
-
const contentDataView = new DataView(binaryGeometry, gltfLength + this.BINARY_EXTENSION_HEADER_LENGTH + 1, header.contentLength);
|
|
45
|
-
const contentDecoded = new TextDecoder().decode(contentDataView);
|
|
46
|
-
this._content = JSON.parse(contentDecoded);
|
|
47
|
-
this._body = binaryGeometry.slice(gltfLength + this.BINARY_EXTENSION_HEADER_LENGTH + 1 + header.contentLength, gltfLength + header.length);
|
|
48
|
-
} else {
|
|
49
|
-
return new TreeNode();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return await this.loadScene();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// #endregion Public Methods (1)
|
|
56
|
-
|
|
57
|
-
// #region Private Methods (6)
|
|
58
|
-
|
|
59
|
-
private convertToIndicesArray(indices: number[]): Uint8Array | Uint16Array | Uint32Array {
|
|
60
|
-
const max = Math.max(0, ...indices);
|
|
61
|
-
if(max < (1 << 8) - 1) {
|
|
62
|
-
return new Uint8Array(indices);
|
|
63
|
-
} else if (max < (1 << 16) - 1) {
|
|
64
|
-
return new Uint16Array(indices);
|
|
65
|
-
} else {
|
|
66
|
-
return new Uint32Array(indices);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private async loadAccessor(accessorName: string): Promise<AttributeData> {
|
|
71
|
-
if (!this._content.accessors![accessorName]) throw new Error('Accessor not available.')
|
|
72
|
-
const accessor = this._content.accessors![accessorName];
|
|
73
|
-
const bufferView = this._body;
|
|
74
|
-
|
|
75
|
-
const itemSize = ACCESSORTYPE[<keyof typeof ACCESSORTYPE>accessor.type];
|
|
76
|
-
const ArrayType = ACCESSOR_COMPONENTTYPE[<keyof typeof ACCESSOR_COMPONENTTYPE>accessor.componentType];
|
|
77
|
-
|
|
78
|
-
const elementBytes = ArrayType.BYTES_PER_ELEMENT;
|
|
79
|
-
const itemBytes = elementBytes * itemSize;
|
|
80
|
-
const byteOffset = accessor.byteOffset || 0;
|
|
81
|
-
|
|
82
|
-
return new AttributeData(new ArrayType(bufferView, byteOffset, itemSize * accessor.count), itemSize, itemBytes, byteOffset, elementBytes, false, accessor.count);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private async loadArcs(): Promise<ITreeNode> {
|
|
86
|
-
if (!this._content.arcs) throw new Error('Arcs not available.')
|
|
87
|
-
const arc = this._content.arcs;
|
|
88
|
-
const arcNode = new TreeNode('arcs');
|
|
89
|
-
|
|
90
|
-
const data = await this.loadAccessor(arc.attributes['ARCS']);
|
|
91
|
-
|
|
92
|
-
// data with an absolute classic array of Vec12s ...
|
|
93
|
-
// like you usually have it in any good program
|
|
94
|
-
// not 4 Vec3s, no, that would be to logic, but a Vec12 instead
|
|
95
|
-
|
|
96
|
-
const count = data.array.length / data.itemSize;
|
|
97
|
-
|
|
98
|
-
for (let i = 0; i < count; ++i) {
|
|
99
|
-
const singleArcNode = new TreeNode('arc_' + i);
|
|
100
|
-
|
|
101
|
-
const index = i * 12;
|
|
102
|
-
const arcCenter = vec3.fromValues(data.array[index + 0], data.array[index + 1], data.array[index + 2]);
|
|
103
|
-
const arcXAxis = vec3.fromValues(data.array[index + 3], data.array[index + 4], data.array[index + 5]);
|
|
104
|
-
const arcYAxis = vec3.fromValues(data.array[index + 6], data.array[index + 7], data.array[index + 8]);
|
|
105
|
-
const arcRadius = data.array[index + 9];
|
|
106
|
-
const arcMinAngle = data.array[index + 10];
|
|
107
|
-
const arcMaxAngle = data.array[index + 11];
|
|
108
|
-
const arcZAxis = vec3.cross(vec3.create(), arcXAxis, arcYAxis)
|
|
109
|
-
|
|
110
|
-
if (arcRadius <= 0) {
|
|
111
|
-
this._logger.warn('SDGTFLoader.loadArcs: Arc radius is <= 0.');
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const points: number[] = [];
|
|
115
|
-
const getPointOnArc = (t: number): void => {
|
|
116
|
-
const twoPi = Math.PI * 2;
|
|
117
|
-
let deltaAngle = arcMaxAngle - arcMinAngle;
|
|
118
|
-
const samePoints = Math.abs(deltaAngle) < Number.EPSILON;
|
|
119
|
-
// ensures that deltaAngle is 0 .. 2 PI
|
|
120
|
-
while (deltaAngle < 0) deltaAngle += twoPi;
|
|
121
|
-
while (deltaAngle > twoPi) deltaAngle -= twoPi;
|
|
122
|
-
deltaAngle = deltaAngle < Number.EPSILON ? samePoints ? 0 : twoPi : deltaAngle;
|
|
123
|
-
const angle = arcMinAngle + t * deltaAngle;
|
|
124
|
-
let x = arcRadius * Math.cos(angle);
|
|
125
|
-
let y = arcRadius * Math.sin(angle);
|
|
126
|
-
points.push(x, y, 0);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const numberOfPoints = Math.max(3, Math.round(50 * ((arcMaxAngle - arcMinAngle) / 2 * Math.PI)));
|
|
130
|
-
for (let d = 0; d <= numberOfPoints; d++)
|
|
131
|
-
getPointOnArc(d / numberOfPoints);
|
|
132
|
-
|
|
133
|
-
const array = new Float32Array(points);
|
|
134
|
-
const attributes: {
|
|
135
|
-
[key: string]: AttributeData
|
|
136
|
-
} = {};
|
|
137
|
-
attributes['POSITION'] = new AttributeData(array, 3, 0, 0, 0, false, array.length / 3)
|
|
138
|
-
|
|
139
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, null), PRIMITIVE_MODE.LINE_STRIP);
|
|
140
|
-
singleArcNode.data.push(geometry);
|
|
141
|
-
|
|
142
|
-
singleArcNode.addTransformation({
|
|
143
|
-
id: 'arc_' + i + '_translation',
|
|
144
|
-
matrix: mat4.translate(mat4.create(), mat4.create(), vec3.fromValues(arcCenter[0], arcCenter[1], arcCenter[2]))
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const arcRotationMatrix = mat4.transpose(mat4.create(), mat4.fromValues(
|
|
148
|
-
arcXAxis[0], arcYAxis[0], arcZAxis[0], 0,
|
|
149
|
-
arcXAxis[1], arcYAxis[1], arcZAxis[1], 0,
|
|
150
|
-
arcXAxis[2], arcYAxis[2], arcZAxis[2], 0,
|
|
151
|
-
0, 0, 0, 1
|
|
152
|
-
));
|
|
153
|
-
singleArcNode.addTransformation({
|
|
154
|
-
id: 'arc_' + i + '_rotation',
|
|
155
|
-
matrix: arcRotationMatrix
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
arcNode.addChild(singleArcNode);
|
|
159
|
-
}
|
|
160
|
-
return arcNode;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private async loadBeziercurve(beziercurveName: string): Promise<ITreeNode> {
|
|
164
|
-
if (!this._content.beziercurves![beziercurveName]) throw new Error('Beziercurve not available.')
|
|
165
|
-
const beziercurve = this._content.beziercurves![beziercurveName];
|
|
166
|
-
const beziercurveNode = new TreeNode(beziercurveName);
|
|
167
|
-
|
|
168
|
-
const controlPointsData = await this.loadAccessor(beziercurve.attributes['CONTROLPOINTS']); // vec3
|
|
169
|
-
const controlPoints: vec4[] = [];
|
|
170
|
-
for (let i = 0; i < controlPointsData.array.length; i += 3)
|
|
171
|
-
controlPoints.push(vec4.fromValues(controlPointsData.array[i], controlPointsData.array[i + 1], controlPointsData.array[i + 2], 1));
|
|
172
|
-
|
|
173
|
-
const knotsData = await this.loadAccessor(beziercurve.attributes['KNOTS']); // scalar
|
|
174
|
-
const knots: number[] = [knotsData.array[0]];
|
|
175
|
-
for (let i = 0; i < knotsData.array.length; i++)
|
|
176
|
-
knots.push(knotsData.array[i]);
|
|
177
|
-
knots.push(knotsData.array[knotsData.array.length - 1])
|
|
178
|
-
const degree = beziercurve.degree;
|
|
179
|
-
|
|
180
|
-
const findSpan = (u: number): number => {
|
|
181
|
-
const n = knots.length - degree - 1;
|
|
182
|
-
if (u >= knots[n])
|
|
183
|
-
return n - 1;
|
|
184
|
-
if (u <= knots[degree])
|
|
185
|
-
return degree;
|
|
186
|
-
|
|
187
|
-
let low = degree;
|
|
188
|
-
let high = n;
|
|
189
|
-
let mid = Math.floor((low + high) / 2);
|
|
190
|
-
|
|
191
|
-
while (u < knots[mid] || u >= knots[mid + 1]) {
|
|
192
|
-
if (u < knots[mid]) {
|
|
193
|
-
high = mid;
|
|
194
|
-
} else {
|
|
195
|
-
low = mid;
|
|
196
|
-
}
|
|
197
|
-
mid = Math.floor((low + high) / 2);
|
|
198
|
-
}
|
|
199
|
-
return mid;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const calcBasisFunctions = (span: number, u: number) => {
|
|
203
|
-
const N = [];
|
|
204
|
-
const left = [];
|
|
205
|
-
const right = [];
|
|
206
|
-
N[0] = 1.0;
|
|
207
|
-
|
|
208
|
-
for (let j = 1; j <= degree; ++j) {
|
|
209
|
-
left[j] = u - knots[span + 1 - j];
|
|
210
|
-
right[j] = knots[span + j] - u;
|
|
211
|
-
|
|
212
|
-
let saved = 0.0;
|
|
213
|
-
for (let r = 0; r < j; ++r) {
|
|
214
|
-
const rv = right[r + 1];
|
|
215
|
-
const lv = left[j - r];
|
|
216
|
-
const temp: number = N[r] / (rv + lv);
|
|
217
|
-
N[r] = saved + rv * temp;
|
|
218
|
-
saved = lv * temp;
|
|
219
|
-
}
|
|
220
|
-
N[j] = saved;
|
|
221
|
-
}
|
|
222
|
-
return N;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const calcBSplinePoint = (u: number): vec4 => {
|
|
226
|
-
const span = findSpan(u);
|
|
227
|
-
const N = calcBasisFunctions(span, u);
|
|
228
|
-
const C = vec4.create();
|
|
229
|
-
for (let j = 0; j <= degree; ++j) {
|
|
230
|
-
const point = controlPoints[span - degree + j];
|
|
231
|
-
const Nj = N[j];
|
|
232
|
-
const wNj = point[3] * Nj;
|
|
233
|
-
vec4.add(C, C, vec4.fromValues(point[0] * wNj, point[1] * wNj, point[2] * wNj, point[3] * Nj))
|
|
234
|
-
}
|
|
235
|
-
return C;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const points: number[] = [];
|
|
239
|
-
const getPointOnBezierCurve = (t: number): void => {
|
|
240
|
-
const u = knots[0] + t * (knots[knots.length - 1] - knots[0]); // linear mapping t->u
|
|
241
|
-
// following results in (wx, wy, wz, w) homogeneous point
|
|
242
|
-
let hpoint = calcBSplinePoint(u);
|
|
243
|
-
if (hpoint[3] !== 1.0) {
|
|
244
|
-
// project to 3D space: (wx, wy, wz, w) -> (x, y, z, 1)
|
|
245
|
-
hpoint = vec4.divide(vec4.create(), hpoint, vec4.fromValues(hpoint[3], hpoint[3], hpoint[3], hpoint[3]))
|
|
246
|
-
}
|
|
247
|
-
points.push(hpoint[0], hpoint[1], hpoint[2]);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Number of points calculation
|
|
251
|
-
// We go through the control points, measure the distance
|
|
252
|
-
let distance = 0;
|
|
253
|
-
for (let i = 1; i < controlPoints.length; i++)
|
|
254
|
-
distance += vec3.distance(vec3.fromValues(controlPoints[i - 1][0], controlPoints[i - 1][1], controlPoints[i - 1][2]), vec3.fromValues(controlPoints[i][0], controlPoints[i][1], controlPoints[i][2]));
|
|
255
|
-
|
|
256
|
-
const numberOfPoints = Math.min(100, Math.max(25, Math.floor(distance / 0.1)));
|
|
257
|
-
for (let d = 0; d <= numberOfPoints; d++)
|
|
258
|
-
getPointOnBezierCurve(d / numberOfPoints);
|
|
259
|
-
|
|
260
|
-
const array = new Float32Array(points);
|
|
261
|
-
const attributes: {
|
|
262
|
-
[key: string]: AttributeData
|
|
263
|
-
} = {};
|
|
264
|
-
attributes['POSITION'] = new AttributeData(array, 3, 0, 0, 0, false, array.length / 3)
|
|
265
|
-
|
|
266
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, null), PRIMITIVE_MODE.LINE_STRIP);
|
|
267
|
-
beziercurveNode.data.push(geometry);
|
|
268
|
-
|
|
269
|
-
return beziercurveNode;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
private async loadCircles(): Promise<ITreeNode> {
|
|
273
|
-
if (!this._content.circles) throw new Error('Circles not available.')
|
|
274
|
-
const circle = this._content.circles;
|
|
275
|
-
const circleNode = new TreeNode('circles');
|
|
276
|
-
|
|
277
|
-
const data = await this.loadAccessor(circle.attributes['CIRCLES']);
|
|
278
|
-
|
|
279
|
-
const count = data.array.length / data.itemSize;
|
|
280
|
-
for (let i = 0; i < count; i++) {
|
|
281
|
-
const singleCircleNode = new TreeNode('circle_' + i);
|
|
282
|
-
|
|
283
|
-
const index = i * 10;
|
|
284
|
-
const circleCenter = vec3.fromValues(data.array[index + 0], data.array[index + 1], data.array[index + 2]);
|
|
285
|
-
const circleXAxis = vec3.fromValues(data.array[index + 3], data.array[index + 4], data.array[index + 5]);
|
|
286
|
-
const circleYAxis = vec3.fromValues(data.array[index + 6], data.array[index + 7], data.array[index + 8]);
|
|
287
|
-
const circleRadius = data.array[index + 9];
|
|
288
|
-
const circleZAxis = vec3.cross(vec3.create(), circleXAxis, circleYAxis)
|
|
289
|
-
|
|
290
|
-
if (circleRadius <= 0) {
|
|
291
|
-
this._logger.warn('SDGTFLoader.loadCircles: Circle radius is <= 0.');
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const points: number[] = [];
|
|
296
|
-
const getPointOnArc = (t: number): void => {
|
|
297
|
-
const twoPi = Math.PI * 2;
|
|
298
|
-
let deltaAngle = 2.0 * Math.PI - 0;
|
|
299
|
-
const samePoints = Math.abs(deltaAngle) < Number.EPSILON;
|
|
300
|
-
// ensures that deltaAngle is 0 .. 2 PI
|
|
301
|
-
while (deltaAngle < 0) deltaAngle += twoPi;
|
|
302
|
-
while (deltaAngle > twoPi) deltaAngle -= twoPi;
|
|
303
|
-
deltaAngle = deltaAngle < Number.EPSILON ? samePoints ? 0 : twoPi : deltaAngle;
|
|
304
|
-
const angle = 0 + t * deltaAngle;
|
|
305
|
-
let x = circleRadius * Math.cos(angle);
|
|
306
|
-
let y = circleRadius * Math.sin(angle);
|
|
307
|
-
points.push(x, y, 0);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const numberOfPoints = 50;
|
|
311
|
-
for (let d = 0; d <= numberOfPoints; d++)
|
|
312
|
-
getPointOnArc(d / numberOfPoints);
|
|
313
|
-
|
|
314
|
-
const array = new Float32Array(points);
|
|
315
|
-
const attributes: {
|
|
316
|
-
[key: string]: AttributeData
|
|
317
|
-
} = {};
|
|
318
|
-
attributes['POSITION'] = new AttributeData(array, 3, 0, 0, 0, false, array.length / 3)
|
|
319
|
-
|
|
320
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, null), PRIMITIVE_MODE.LINE_STRIP);
|
|
321
|
-
singleCircleNode.data.push(geometry);
|
|
322
|
-
|
|
323
|
-
singleCircleNode.addTransformation({
|
|
324
|
-
id: 'circle_' + i + '_translation',
|
|
325
|
-
matrix: mat4.translate(mat4.create(), mat4.create(), vec3.fromValues(circleCenter[0], circleCenter[1], circleCenter[2]))
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
const circleRotationMatrix = mat4.transpose(mat4.create(), mat4.fromValues(
|
|
329
|
-
circleXAxis[0], circleYAxis[0], circleZAxis[0], 0,
|
|
330
|
-
circleXAxis[1], circleYAxis[1], circleZAxis[1], 0,
|
|
331
|
-
circleXAxis[2], circleYAxis[2], circleZAxis[2], 0,
|
|
332
|
-
0, 0, 0, 1
|
|
333
|
-
));
|
|
334
|
-
singleCircleNode.addTransformation({
|
|
335
|
-
id: 'circle_' + i + '_rotation',
|
|
336
|
-
matrix: circleRotationMatrix
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
circleNode.addChild(singleCircleNode);
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
return circleNode;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
private async loadCylinders(): Promise<ITreeNode> {
|
|
346
|
-
if (!this._content.cylinders) throw new Error('Cylinders not available.')
|
|
347
|
-
const cylinder = this._content.cylinders;
|
|
348
|
-
const cylinderNode = new TreeNode('cylinders');
|
|
349
|
-
|
|
350
|
-
const data = await this.loadAccessor(cylinder.attributes['CYLINDERS']);
|
|
351
|
-
|
|
352
|
-
const count = data.array.length / data.itemSize;
|
|
353
|
-
for (let i = 0; i < count; i++) {
|
|
354
|
-
const singleCylinderNode = new TreeNode('cylinder_' + i);
|
|
355
|
-
|
|
356
|
-
const index = i * 7;
|
|
357
|
-
const cylinderTop = vec3.fromValues(data.array[index + 0], data.array[index + 1], data.array[index + 2]);
|
|
358
|
-
const cylinderBottom = vec3.fromValues(data.array[index + 3], data.array[index + 4], data.array[index + 5]);
|
|
359
|
-
const cylinderRadius = data.array[index + 6];
|
|
360
|
-
const cylinderAxis = vec3.sub(vec3.create(), cylinderTop, cylinderBottom)
|
|
361
|
-
const dotX = Math.abs(vec3.dot(cylinderAxis, vec3.fromValues(1, 0, 0)));
|
|
362
|
-
const dotY = Math.abs(vec3.dot(cylinderAxis, vec3.fromValues(0, 1, 0)));
|
|
363
|
-
|
|
364
|
-
let cylinderXAxis: vec3;
|
|
365
|
-
if (dotX < dotY) {
|
|
366
|
-
cylinderXAxis = vec3.cross(vec3.create(), cylinderAxis, vec3.fromValues(1, 0, 0));
|
|
367
|
-
} else {
|
|
368
|
-
cylinderXAxis = vec3.cross(vec3.create(), cylinderAxis, vec3.fromValues(0, 1, 0));
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
const cylinderYAxis = vec3.cross(vec3.create(), cylinderAxis, cylinderXAxis);
|
|
372
|
-
|
|
373
|
-
vec3.normalize(cylinderAxis, cylinderAxis);
|
|
374
|
-
vec3.normalize(cylinderXAxis, cylinderXAxis);
|
|
375
|
-
vec3.normalize(cylinderYAxis, cylinderYAxis);
|
|
376
|
-
|
|
377
|
-
if (cylinderRadius <= 0) {
|
|
378
|
-
this._logger.warn('SDGTFLoader.loadCylinders: Cylinder radius is <= 0.');
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const indices: number[] = [];
|
|
383
|
-
const vertices: number[] = [];
|
|
384
|
-
const normals: number[] = [];
|
|
385
|
-
const uvs: number[] = [];
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const height = vec3.distance(cylinderTop, cylinderBottom);
|
|
389
|
-
const halfHeight = height / 2;
|
|
390
|
-
const thetaStart = 0, thetaLength = Math.PI * 2
|
|
391
|
-
let indexCounter = 0;
|
|
392
|
-
const indexArray: number[][] = [];
|
|
393
|
-
|
|
394
|
-
const heightSegments = 1, radialSegments = 50;
|
|
395
|
-
|
|
396
|
-
const normal = vec3.create();
|
|
397
|
-
const vertex = vec3.create();
|
|
398
|
-
let groupCount = 0;
|
|
399
|
-
// this will be used to calculate the normal
|
|
400
|
-
const slope = 0;
|
|
401
|
-
// generate vertices, normals and uvs
|
|
402
|
-
for (let y = 0; y <= heightSegments; y++) {
|
|
403
|
-
const indexRow = [];
|
|
404
|
-
const v = y / heightSegments;
|
|
405
|
-
// calculate the radius of the current row
|
|
406
|
-
const radius = cylinderRadius;
|
|
407
|
-
for (let x = 0; x <= radialSegments; x++) {
|
|
408
|
-
const u = x / radialSegments;
|
|
409
|
-
const theta = u * thetaLength + thetaStart;
|
|
410
|
-
const sinTheta = Math.sin(theta);
|
|
411
|
-
const cosTheta = Math.cos(theta);
|
|
412
|
-
// vertex
|
|
413
|
-
vertex[0] = radius * sinTheta;
|
|
414
|
-
vertex[1] = - v * height + halfHeight;
|
|
415
|
-
vertex[2] = radius * cosTheta;
|
|
416
|
-
vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
417
|
-
// normal
|
|
418
|
-
vec3.normalize(normal, vec3.fromValues(sinTheta, slope, cosTheta))
|
|
419
|
-
normals.push(normal[0], normal[1], normal[2]);
|
|
420
|
-
// uv
|
|
421
|
-
uvs.push(u, 1 - v);
|
|
422
|
-
// save index of vertex in respective row
|
|
423
|
-
indexRow.push(indexCounter++);
|
|
424
|
-
}
|
|
425
|
-
// now save vertices of the row in our index array
|
|
426
|
-
indexArray.push(indexRow);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// generate indices
|
|
430
|
-
for (let x = 0; x < radialSegments; x++) {
|
|
431
|
-
for (let y = 0; y < heightSegments; y++) {
|
|
432
|
-
// we use the index array to access the correct indices
|
|
433
|
-
const a = indexArray[y][x];
|
|
434
|
-
const b = indexArray[y + 1][x];
|
|
435
|
-
const c = indexArray[y + 1][x + 1];
|
|
436
|
-
const d = indexArray[y][x + 1];
|
|
437
|
-
// faces
|
|
438
|
-
indices.push(a, b, d);
|
|
439
|
-
indices.push(b, c, d);
|
|
440
|
-
// update group counter
|
|
441
|
-
groupCount += 6;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const attributes: {
|
|
446
|
-
[key: string]: AttributeData
|
|
447
|
-
} = {};
|
|
448
|
-
attributes['POSITION'] = new AttributeData(new Float32Array(vertices), 3, 0, 0, 0, false, vertices.length / 3)
|
|
449
|
-
attributes['NORMAL'] = new AttributeData(new Float32Array(normals), 3, 0, 0, 0, false, normals.length / 3)
|
|
450
|
-
attributes['TEXCOORD_0'] = new AttributeData(new Float32Array(uvs), 2, 0, 0, 0, false, uvs.length / 2)
|
|
451
|
-
|
|
452
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, new AttributeData(this.convertToIndicesArray(indices), 1, 0, 0, 0, false, indices.length)), PRIMITIVE_MODE.TRIANGLES);
|
|
453
|
-
singleCylinderNode.data.push(geometry);
|
|
454
|
-
|
|
455
|
-
singleCylinderNode.addTransformation({
|
|
456
|
-
id: 'cylinder_' + i + '_translation',
|
|
457
|
-
matrix: mat4.translate(mat4.create(), mat4.create(), cylinderBottom)
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
const cylinderRotationMatrix = mat4.transpose(mat4.create(), mat4.fromValues(
|
|
461
|
-
cylinderXAxis[0], cylinderYAxis[0], cylinderAxis[0], 0,
|
|
462
|
-
cylinderXAxis[1], cylinderYAxis[1], cylinderAxis[1], 0,
|
|
463
|
-
cylinderXAxis[2], cylinderYAxis[2], cylinderAxis[2], 0,
|
|
464
|
-
0, 0, 0, 1
|
|
465
|
-
));
|
|
466
|
-
singleCylinderNode.addTransformation({
|
|
467
|
-
id: 'cylinder_' + i + '_rotation',
|
|
468
|
-
matrix: cylinderRotationMatrix
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
singleCylinderNode.addTransformation({
|
|
473
|
-
id: 'cylinder_' + i + '_rotation2',
|
|
474
|
-
matrix: mat4.rotateX(mat4.create(), mat4.create(), 0.5 * Math.PI)
|
|
475
|
-
});
|
|
476
|
-
singleCylinderNode.addTransformation({
|
|
477
|
-
id: 'cylinder_' + i + '_translation2',
|
|
478
|
-
matrix: mat4.translate(mat4.create(), mat4.create(), vec3.fromValues(0, 0, 0.5 * vec3.distance(cylinderTop, cylinderBottom)))
|
|
479
|
-
});
|
|
480
|
-
cylinderNode.addChild(singleCylinderNode);
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
return cylinderNode;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
private async loadSpheres(): Promise<ITreeNode> {
|
|
487
|
-
if (!this._content.spheres) throw new Error('Spheres not available.')
|
|
488
|
-
const sphere = this._content.spheres;
|
|
489
|
-
const sphereNode = new TreeNode('spheres');
|
|
490
|
-
|
|
491
|
-
const data = await this.loadAccessor(sphere.attributes['SPHERES']);
|
|
492
|
-
|
|
493
|
-
const count = data.array.length / data.itemSize;
|
|
494
|
-
for (let i = 0; i < count; i++) {
|
|
495
|
-
const singleSphereNode = new TreeNode('sphere_' + i);
|
|
496
|
-
|
|
497
|
-
const index = i * 4;
|
|
498
|
-
const sphereTranslation = vec3.fromValues(data.array[index + 0], data.array[index + 1], data.array[index + 2]);
|
|
499
|
-
const sphereRadius = data.array[index + 3];
|
|
500
|
-
if (sphereRadius <= 0) {
|
|
501
|
-
this._logger.warn('SDGTFLoader.loadSpheres: Sphere radius is <= 0.');
|
|
502
|
-
continue;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
const indices: number[] = [];
|
|
506
|
-
const vertices: number[] = [];
|
|
507
|
-
const normals: number[] = [];
|
|
508
|
-
const uvs: number[] = [];
|
|
509
|
-
const grid: number[][] = [];
|
|
510
|
-
|
|
511
|
-
// for some reason, this doesn't work with values > 15
|
|
512
|
-
// let's not look into it, it's legacy stuff
|
|
513
|
-
const heightSegments = 15, widthSegments = 15;
|
|
514
|
-
const phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI;
|
|
515
|
-
const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI);
|
|
516
|
-
|
|
517
|
-
let indexCounter = 0;
|
|
518
|
-
|
|
519
|
-
// generate vertices, normals and uvs
|
|
520
|
-
|
|
521
|
-
for (let iy = 0; iy <= heightSegments; iy++) {
|
|
522
|
-
const verticesRow = [];
|
|
523
|
-
const v = iy / heightSegments;
|
|
524
|
-
|
|
525
|
-
// special case for the poles
|
|
526
|
-
let uOffset = 0;
|
|
527
|
-
if (iy == 0 && thetaStart == 0) {
|
|
528
|
-
uOffset = 0.5 / widthSegments;
|
|
529
|
-
} else if (iy == heightSegments && thetaEnd == Math.PI) {
|
|
530
|
-
uOffset = - 0.5 / widthSegments;
|
|
531
|
-
}
|
|
532
|
-
for (let ix = 0; ix <= widthSegments; ix++) {
|
|
533
|
-
const u = ix / widthSegments;
|
|
534
|
-
// vertex
|
|
535
|
-
const vertex = vec3.fromValues(
|
|
536
|
-
- sphereRadius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength),
|
|
537
|
-
sphereRadius * Math.cos(thetaStart + v * thetaLength),
|
|
538
|
-
sphereRadius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)
|
|
539
|
-
);
|
|
540
|
-
vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
541
|
-
// normal
|
|
542
|
-
const normal = vec3.normalize(vec3.create(), vertex);
|
|
543
|
-
normals.push(normal[0], normal[1], normal[2]);
|
|
544
|
-
// uv
|
|
545
|
-
uvs.push(u + uOffset, 1 - v);
|
|
546
|
-
verticesRow.push(indexCounter++);
|
|
547
|
-
}
|
|
548
|
-
grid.push(verticesRow);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
// indices
|
|
552
|
-
for (let iy = 0; iy < heightSegments; iy++) {
|
|
553
|
-
for (let ix = 0; ix < widthSegments; ix++) {
|
|
554
|
-
const a = grid[iy][ix + 1];
|
|
555
|
-
const b = grid[iy][ix];
|
|
556
|
-
const c = grid[iy + 1][ix];
|
|
557
|
-
const d = grid[iy + 1][ix + 1];
|
|
558
|
-
if (iy !== 0 || thetaStart > 0) indices.push(a, b, d);
|
|
559
|
-
if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const attributes: {
|
|
564
|
-
[key: string]: AttributeData
|
|
565
|
-
} = {};
|
|
566
|
-
attributes['POSITION'] = new AttributeData(new Float32Array(vertices), 3, 0, 0, 0, false, vertices.length / 3)
|
|
567
|
-
attributes['NORMAL'] = new AttributeData(new Float32Array(normals), 3, 0, 0, 0, false, normals.length / 3)
|
|
568
|
-
attributes['TEXCOORD_0'] = new AttributeData(new Float32Array(uvs), 2, 0, 0, 0, false, uvs.length / 2)
|
|
569
|
-
|
|
570
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, new AttributeData(this.convertToIndicesArray(indices), 1, 0, 0, 0, false, indices.length)), PRIMITIVE_MODE.TRIANGLES);
|
|
571
|
-
singleSphereNode.data.push(geometry);
|
|
572
|
-
|
|
573
|
-
singleSphereNode.addTransformation({
|
|
574
|
-
id: 'sphere_' + i + '_translation',
|
|
575
|
-
matrix: mat4.translate(mat4.create(), mat4.create(), sphereTranslation)
|
|
576
|
-
});
|
|
577
|
-
sphereNode.addChild(singleSphereNode);
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
return sphereNode;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
private async loadPoint(pointName: string): Promise<ITreeNode> {
|
|
584
|
-
if (!this._content.points![pointName]) throw new Error('Point not available.')
|
|
585
|
-
const point = this._content.points![pointName];
|
|
586
|
-
const pointNode = new TreeNode(pointName);
|
|
587
|
-
|
|
588
|
-
const attributes: {
|
|
589
|
-
[key: string]: AttributeData
|
|
590
|
-
} = {};
|
|
591
|
-
|
|
592
|
-
const data = await this.loadAccessor(point.attributes['POINTS']);
|
|
593
|
-
attributes['POSITION'] = new AttributeData(data.array, 3, data.itemBytes, data.byteOffset, data.elementBytes, data.normalized, data.count)
|
|
594
|
-
|
|
595
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, null), PRIMITIVE_MODE.POINTS);
|
|
596
|
-
pointNode.data.push(geometry);
|
|
597
|
-
|
|
598
|
-
return pointNode;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
private async loadPolyline(polylineName: string): Promise<ITreeNode> {
|
|
602
|
-
if (!this._content.polylines![polylineName]) throw new Error('Polyline not available.')
|
|
603
|
-
const polyLine = this._content.polylines![polylineName];
|
|
604
|
-
const polyLineNode = new TreeNode(polylineName);
|
|
605
|
-
|
|
606
|
-
const attributes: {
|
|
607
|
-
[key: string]: AttributeData
|
|
608
|
-
} = {};
|
|
609
|
-
|
|
610
|
-
const data = await this.loadAccessor(polyLine.attributes['VERTICES']);
|
|
611
|
-
attributes['POSITION'] = new AttributeData(data.array, 3, data.itemBytes, data.byteOffset, data.elementBytes, data.normalized, data.count)
|
|
612
|
-
|
|
613
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, null), PRIMITIVE_MODE.LINE_STRIP);
|
|
614
|
-
polyLineNode.data.push(geometry);
|
|
615
|
-
|
|
616
|
-
return polyLineNode;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
private async loadSurfacepatch(surfacepatchName: string): Promise<ITreeNode> {
|
|
620
|
-
if (!this._content.surfacepatches![surfacepatchName]) throw new Error('Surfacepatch not available.')
|
|
621
|
-
const surfacepatch = this._content.surfacepatches![surfacepatchName];
|
|
622
|
-
const surfacepatchNode = new TreeNode(surfacepatchName);
|
|
623
|
-
|
|
624
|
-
const controlPointCountU = surfacepatch.controlPointCountU;
|
|
625
|
-
const controlPointCountV = surfacepatch.controlPointCountV;
|
|
626
|
-
|
|
627
|
-
const controlPointsData = await this.loadAccessor(surfacepatch.attributes['CONTROLPOINTS']); // vec3
|
|
628
|
-
const controlPoints: vec4[][] = [];
|
|
629
|
-
let pointCount = 0;
|
|
630
|
-
for (let u = 0; u < controlPointCountU; u++) {
|
|
631
|
-
let innerArray = []
|
|
632
|
-
for (let v = 0; v < controlPointCountV; v++) {
|
|
633
|
-
innerArray.push(vec4.fromValues(controlPointsData.array[pointCount * 3], controlPointsData.array[pointCount * 3 + 1], controlPointsData.array[pointCount * 3 + 2], 1));
|
|
634
|
-
pointCount++;
|
|
635
|
-
}
|
|
636
|
-
controlPoints.push(innerArray);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
const knotsUData = await this.loadAccessor(surfacepatch.attributes['KNOTSU']); // scalar
|
|
640
|
-
const knotsU: number[] = [knotsUData.array[0]];
|
|
641
|
-
for (let i = 0; i < knotsUData.array.length; i++)
|
|
642
|
-
knotsU.push(knotsUData.array[i]);
|
|
643
|
-
knotsU.push(knotsUData.array[knotsUData.array.length - 1])
|
|
644
|
-
|
|
645
|
-
const knotsVData = await this.loadAccessor(surfacepatch.attributes['KNOTSV']); // scalar
|
|
646
|
-
const knotsV: number[] = [knotsVData.array[0]];
|
|
647
|
-
for (let i = 0; i < knotsVData.array.length; i++)
|
|
648
|
-
knotsV.push(knotsVData.array[i]);
|
|
649
|
-
knotsV.push(knotsVData.array[knotsVData.array.length - 1])
|
|
650
|
-
|
|
651
|
-
const degreeU = surfacepatch.degreeU;
|
|
652
|
-
const degreeV = surfacepatch.degreeV;
|
|
653
|
-
|
|
654
|
-
const findSpan = (knots: number[], degree: number, u: number): number => {
|
|
655
|
-
const n = knots.length - degree - 1;
|
|
656
|
-
if (u >= knots[n])
|
|
657
|
-
return n - 1;
|
|
658
|
-
if (u <= knots[degree])
|
|
659
|
-
return degree;
|
|
660
|
-
|
|
661
|
-
let low = degree;
|
|
662
|
-
let high = n;
|
|
663
|
-
let mid = Math.floor((low + high) / 2);
|
|
664
|
-
|
|
665
|
-
while (u < knots[mid] || u >= knots[mid + 1]) {
|
|
666
|
-
if (u < knots[mid]) {
|
|
667
|
-
high = mid;
|
|
668
|
-
} else {
|
|
669
|
-
low = mid;
|
|
670
|
-
}
|
|
671
|
-
mid = Math.floor((low + high) / 2);
|
|
672
|
-
}
|
|
673
|
-
return mid;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
const calcBasisFunctions = (knots: number[], degree: number, span: number, u: number) => {
|
|
677
|
-
const N = [];
|
|
678
|
-
const left = [];
|
|
679
|
-
const right = [];
|
|
680
|
-
N[0] = 1.0;
|
|
681
|
-
|
|
682
|
-
for (let j = 1; j <= degree; ++j) {
|
|
683
|
-
left[j] = u - knots[span + 1 - j];
|
|
684
|
-
right[j] = knots[span + j] - u;
|
|
685
|
-
|
|
686
|
-
let saved = 0.0;
|
|
687
|
-
for (let r = 0; r < j; ++r) {
|
|
688
|
-
const rv = right[r + 1];
|
|
689
|
-
const lv = left[j - r];
|
|
690
|
-
const temp: number = N[r] / (rv + lv);
|
|
691
|
-
N[r] = saved + rv * temp;
|
|
692
|
-
saved = lv * temp;
|
|
693
|
-
}
|
|
694
|
-
N[j] = saved;
|
|
695
|
-
}
|
|
696
|
-
return N;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
const calcSurfacePoint = (u: number, v: number): vec3 => {
|
|
700
|
-
|
|
701
|
-
const uspan = findSpan(knotsU, degreeU, u);
|
|
702
|
-
const vspan = findSpan(knotsV, degreeV, v);
|
|
703
|
-
const Nu = calcBasisFunctions(knotsU, degreeU, uspan, u);
|
|
704
|
-
const Nv = calcBasisFunctions(knotsV, degreeV, vspan, v);
|
|
705
|
-
const temp: vec4[] = [];
|
|
706
|
-
|
|
707
|
-
for (let l = 0; l <= degreeV; ++l) {
|
|
708
|
-
|
|
709
|
-
temp[l] = vec4.create();
|
|
710
|
-
for (let k = 0; k <= degreeU; ++k) {
|
|
711
|
-
|
|
712
|
-
const point = vec4.clone(controlPoints[uspan - degreeU + k][vspan - degreeV + l]);
|
|
713
|
-
const w = point[3];
|
|
714
|
-
point[0] *= w;
|
|
715
|
-
point[1] *= w;
|
|
716
|
-
point[2] *= w;
|
|
717
|
-
vec4.add(temp[l], temp[l], vec4.multiply(vec4.create(), point, vec4.fromValues(Nu[k], Nu[k], Nu[k], Nu[k])))
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
const Sw = vec4.create();
|
|
722
|
-
for (let l = 0; l <= degreeV; ++l) {
|
|
723
|
-
vec4.add(Sw, Sw, vec4.multiply(vec4.create(), temp[l], vec4.fromValues(Nv[l], Nv[l], Nv[l], Nv[l])))
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
vec4.divide(Sw, Sw, vec4.fromValues(Sw[3], Sw[3], Sw[3], Sw[3]))
|
|
727
|
-
return vec3.fromValues(Sw[0], Sw[1], Sw[2]);
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
const getPointOnSurfacepatch = (t1: number, t2: number): vec3 => {
|
|
731
|
-
const u = knotsU[0] + t1 * (knotsU[knotsU.length - 1] - knotsU[0]); // linear mapping t1->u
|
|
732
|
-
const v = knotsV[0] + t2 * (knotsV[knotsV.length - 1] - knotsV[0]); // linear mapping t2->u
|
|
733
|
-
return calcSurfacePoint(u, v);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
const numberOfPoints = 15;
|
|
737
|
-
|
|
738
|
-
const indices: number[] = [];
|
|
739
|
-
const vertices = [];
|
|
740
|
-
|
|
741
|
-
for (let d = 0; d <= numberOfPoints; d++) {
|
|
742
|
-
const v = d / numberOfPoints;
|
|
743
|
-
for (let f = 0; f <= numberOfPoints; f++) {
|
|
744
|
-
const u = f / numberOfPoints;
|
|
745
|
-
const vertex = getPointOnSurfacepatch(u, v);
|
|
746
|
-
vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
for (let d = 0; d < numberOfPoints; d++) {
|
|
751
|
-
for (let f = 0; f < numberOfPoints; f++) {
|
|
752
|
-
const i1 = d * (numberOfPoints + 1) + f;
|
|
753
|
-
const i2 = d * (numberOfPoints + 1) + f + 1;
|
|
754
|
-
const i3 = (d+1) * (numberOfPoints + 1) + f;
|
|
755
|
-
const i4 = (d+1) * (numberOfPoints + 1) + f + 1;
|
|
756
|
-
// faces one and two
|
|
757
|
-
indices.push(i3, i2, i1);
|
|
758
|
-
indices.push(i2, i3, i4);
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
const attributes: {
|
|
763
|
-
[key: string]: AttributeData
|
|
764
|
-
} = {};
|
|
765
|
-
attributes['POSITION'] = new AttributeData(new Float32Array(vertices), 3, 0, 0, 0, false, vertices.length / 3);
|
|
766
|
-
// to not compute normals ourselves, we just let three.js do it
|
|
767
|
-
// in our geometry loader, this array will cause the computation of vertex normals
|
|
768
|
-
attributes['NORMAL'] = new AttributeData(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), 3, 0, 0, 0, false, vertices.length / 3);
|
|
769
|
-
|
|
770
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, new AttributeData(this.convertToIndicesArray(indices), 1, 0, 0, 0, false, indices.length)), PRIMITIVE_MODE.TRIANGLES);
|
|
771
|
-
surfacepatchNode.data.push(geometry);
|
|
772
|
-
|
|
773
|
-
return surfacepatchNode;
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
private async loadScene(): Promise<ITreeNode> {
|
|
778
|
-
const sceneNode = new TreeNode('sdgtf_content');
|
|
779
|
-
|
|
780
|
-
// arcs
|
|
781
|
-
if (this._content.arcs)
|
|
782
|
-
sceneNode.addChild(await this.loadArcs());
|
|
783
|
-
|
|
784
|
-
// beziercurves
|
|
785
|
-
if (this._content.beziercurves) {
|
|
786
|
-
for (let beziercurve in this._content.beziercurves)
|
|
787
|
-
sceneNode.addChild(await this.loadBeziercurve(beziercurve));
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// circles
|
|
791
|
-
if (this._content.circles)
|
|
792
|
-
sceneNode.addChild(await this.loadCircles());
|
|
793
|
-
|
|
794
|
-
// cylinders
|
|
795
|
-
if (this._content.cylinders)
|
|
796
|
-
sceneNode.addChild(await this.loadCylinders());
|
|
797
|
-
|
|
798
|
-
//points
|
|
799
|
-
if (this._content.points) {
|
|
800
|
-
for (let point in this._content.points)
|
|
801
|
-
sceneNode.addChild(await this.loadPoint(point));
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// polylines
|
|
805
|
-
if (this._content.polylines) {
|
|
806
|
-
for (let line in this._content.polylines)
|
|
807
|
-
sceneNode.addChild(await this.loadPolyline(line));
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
// spheres
|
|
811
|
-
if (this._content.spheres)
|
|
812
|
-
sceneNode.addChild(await this.loadSpheres());
|
|
813
|
-
|
|
814
|
-
// surfacepatches
|
|
815
|
-
if (this._content.surfacepatches) {
|
|
816
|
-
for (let surfacepatch in this._content.surfacepatches)
|
|
817
|
-
sceneNode.addChild(await this.loadSurfacepatch(surfacepatch));
|
|
818
|
-
}
|
|
819
|
-
return sceneNode;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// #endregion Private Methods (6)
|
|
823
|
-
}
|