@navaramap/core 0.2.1 → 0.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/dist/index.d.ts +116 -91
- package/dist/index.js +273 -483
- package/dist/index.umd.cjs +1 -1
- package/package.json +1 -1
- package/src/color/ColorMap.test.ts +15 -0
- package/src/color/ColorMap.ts +7 -6
- package/src/event/JobDispatcher.test.ts +484 -0
- package/src/event/JobDispatcher.ts +387 -0
- package/src/event/index.ts +1 -2
- package/src/event/mock.ts +2 -2
- package/src/globe/Globe.ts +3 -26
- package/src/utils/ReturnedConstructedTerrainMeshLike.ts +5 -0
- package/src/utils/polyline/ConstructedPolylineGeometryLike.ts +23 -16
- package/src/event/EventManager.test.ts +0 -635
- package/src/event/EventManager.ts +0 -438
- package/src/event/TransactionManager.test.ts +0 -126
- package/src/event/TransactionManager.ts +0 -78
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { type Events } from "@navaramap/engine";
|
|
2
|
+
|
|
3
|
+
import { generate_id_from_entity, isEntityEvent } from "../id";
|
|
4
|
+
|
|
5
|
+
// The WASM `Events` class exposes each stack only through a move-out
|
|
6
|
+
// `take_<key>()` method (reading a getter would deep-clone the array and every
|
|
7
|
+
// element). Stack keys and value types are derived from those methods.
|
|
8
|
+
export type JsEvents = {
|
|
9
|
+
[
|
|
10
|
+
K in keyof Events as K extends `take_${infer P}` ? P : never
|
|
11
|
+
]: Events[K] extends (...args: never[]) => infer R ? R : never;
|
|
12
|
+
};
|
|
13
|
+
export type JsEventsKey = keyof JsEvents;
|
|
14
|
+
|
|
15
|
+
/** One element of a stack (the value itself for the `Option` stacks). */
|
|
16
|
+
export type JsEventValue<K extends JsEventsKey> = JsEvents[K] extends unknown[]
|
|
17
|
+
? JsEvents[K][number]
|
|
18
|
+
: JsEvents[K];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One kind of frontend job: the engine emits `requested` when it wants the
|
|
22
|
+
* frontend to run async work for an entity (fetch, worker task, mesh build),
|
|
23
|
+
* `changed` while the entity is alive, and `removed` when the entity is
|
|
24
|
+
* despawned — unconditionally, including while the job is still in flight.
|
|
25
|
+
*
|
|
26
|
+
* The dispatcher turns these into calls on this handler and owns the job
|
|
27
|
+
* table; the handler never sees ordering, dedupe or abort bookkeeping.
|
|
28
|
+
*/
|
|
29
|
+
export type JobHandler<Req, Chg, Rem, Product> = {
|
|
30
|
+
/** Used in error logs only. */
|
|
31
|
+
name: string;
|
|
32
|
+
events: {
|
|
33
|
+
requested: JsEventsKey;
|
|
34
|
+
changed?: JsEventsKey;
|
|
35
|
+
removed: JsEventsKey;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Called right away for every admitted `requested` event. After each
|
|
39
|
+
* `await`, check `abort.signal.aborted` before touching shared state or
|
|
40
|
+
* reporting to the engine: a removed job must not report. Resolving
|
|
41
|
+
* `undefined` means "done, no product" (an empty geometry, a fetch whose
|
|
42
|
+
* result went straight into the buffer store, ...); the job is then
|
|
43
|
+
* forgotten, like one whose `start` failed.
|
|
44
|
+
*/
|
|
45
|
+
start(ev: Req, abort: AbortController): Promise<Product | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* Applies a `changed` snapshot to a live product. Calls on one job never
|
|
48
|
+
* overlap: a change arriving while `start` or a previous change is in
|
|
49
|
+
* flight waits, and only the latest waiting one is applied.
|
|
50
|
+
*/
|
|
51
|
+
change?(product: Product, ev: Chg): void | Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Called exactly once per `removed` event, when nothing is in flight for
|
|
54
|
+
* the job any more: immediately for a live or unknown job (`product` is
|
|
55
|
+
* `undefined` for an unknown one or one whose `start` failed), or once the
|
|
56
|
+
* aborted `start` / `change` settles. The job's abort signal has fired by
|
|
57
|
+
* then, so continuations still running after `start` see the removal.
|
|
58
|
+
* `ev` is `undefined` only when the dispatcher itself is disposed while
|
|
59
|
+
* the job is in flight.
|
|
60
|
+
*/
|
|
61
|
+
teardown(product: Product | undefined, ev: Rem | undefined): void;
|
|
62
|
+
/** Reports a rejected / thrown `start` to the engine (kind specific); a
|
|
63
|
+
* kind without it gets the error logged instead. Not called once the job
|
|
64
|
+
* was removed or the dispatcher disposed; an abort the handler fires on
|
|
65
|
+
* its own still reports. */
|
|
66
|
+
failed?(ev: Req, error: unknown): void;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
type Job = {
|
|
70
|
+
abort: AbortController;
|
|
71
|
+
product?: unknown;
|
|
72
|
+
/** Whether `start` or a `change` is outstanding; at most one is. */
|
|
73
|
+
inFlight: boolean;
|
|
74
|
+
/** The `removed` event that arrived while something was in flight. Kept
|
|
75
|
+
* alive (not freed) until `teardown` has consumed it. */
|
|
76
|
+
removedEv?: object;
|
|
77
|
+
/** Latest `changed` event received while something was in flight. */
|
|
78
|
+
pendingChange?: object;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
type Registered = {
|
|
82
|
+
handler: JobHandler<unknown, unknown, unknown, unknown>;
|
|
83
|
+
jobs: Map<string, Job>;
|
|
84
|
+
/** Jobs of this kind with a call outstanding. */
|
|
85
|
+
inFlight: number;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** A registered kind, as returned by {@link JobDispatcher.register}. */
|
|
89
|
+
export type RegisteredJobKind = {
|
|
90
|
+
/** Jobs of this kind whose `start` or `change` has not settled yet. */
|
|
91
|
+
inFlight(): number;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type SyncHandler = { key: JsEventsKey; handle: (ev: unknown) => void };
|
|
95
|
+
|
|
96
|
+
export type JobDispatcherOptions = {
|
|
97
|
+
/** Called whenever a job's `start` settles with a product, i.e. something
|
|
98
|
+
* new is on screen. */
|
|
99
|
+
onSettled?: () => void;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const maybeFree = (ev: unknown) => {
|
|
103
|
+
if (
|
|
104
|
+
ev &&
|
|
105
|
+
typeof ev === "object" &&
|
|
106
|
+
"free" in ev &&
|
|
107
|
+
typeof ev.free === "function"
|
|
108
|
+
) {
|
|
109
|
+
ev.free();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const isThenable = (v: unknown): v is Promise<void> =>
|
|
114
|
+
typeof (v as { then?: unknown } | undefined)?.then === "function";
|
|
115
|
+
|
|
116
|
+
const idOf = (ev: unknown): string | undefined =>
|
|
117
|
+
isEntityEvent(ev) ? generate_id_from_entity(ev) : undefined;
|
|
118
|
+
|
|
119
|
+
const takeStack = <K extends JsEventsKey>(
|
|
120
|
+
events: Events,
|
|
121
|
+
key: K,
|
|
122
|
+
): (JsEventValue<K> & object)[] => {
|
|
123
|
+
const take = events[`take_${key}` as keyof Events] as unknown as (
|
|
124
|
+
this: Events,
|
|
125
|
+
) => JsEvents[K];
|
|
126
|
+
const taken = take.call(events);
|
|
127
|
+
if (taken === undefined || taken === null) return [];
|
|
128
|
+
return (Array.isArray(taken) ? taken : [taken]) as (JsEventValue<K> &
|
|
129
|
+
object)[];
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Consumes the per-frame engine events and dispatches them to the registered
|
|
134
|
+
* handlers with no queueing: every `requested` starts its job in the same
|
|
135
|
+
* tick (admission and priority are the engine's job), every `removed` aborts
|
|
136
|
+
* or tears down, every `changed` applies or waits for the in-flight `start`.
|
|
137
|
+
* Taken WASM event objects are freed here, once the handler that received
|
|
138
|
+
* them has settled, so handlers never call `free()` on an event.
|
|
139
|
+
*/
|
|
140
|
+
export class JobDispatcher {
|
|
141
|
+
private readonly sync: SyncHandler[] = [];
|
|
142
|
+
private readonly registered: Registered[] = [];
|
|
143
|
+
private readonly onSettled?: () => void;
|
|
144
|
+
private disposed = false;
|
|
145
|
+
private inFlightJobs = 0;
|
|
146
|
+
|
|
147
|
+
constructor(options?: JobDispatcherOptions) {
|
|
148
|
+
this.onSettled = options?.onSettled;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
register<Req, Chg, Rem, Product>(
|
|
152
|
+
handler: JobHandler<Req, Chg, Rem, Product>,
|
|
153
|
+
): RegisteredJobKind {
|
|
154
|
+
const r: Registered = {
|
|
155
|
+
handler: handler as JobHandler<unknown, unknown, unknown, unknown>,
|
|
156
|
+
jobs: new Map(),
|
|
157
|
+
inFlight: 0,
|
|
158
|
+
};
|
|
159
|
+
this.registered.push(r);
|
|
160
|
+
return { inFlight: () => r.inFlight };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** A synchronous, stateless handler; events are freed right after it. */
|
|
164
|
+
registerSync<K extends JsEventsKey>(
|
|
165
|
+
key: K,
|
|
166
|
+
handle: (ev: JsEventValue<K>) => void,
|
|
167
|
+
) {
|
|
168
|
+
this.sync.push({ key, handle: handle as (ev: unknown) => void });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Jobs whose `start` or `change` has not settled yet. */
|
|
172
|
+
inFlight(): number {
|
|
173
|
+
return this.inFlightJobs;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
tick(events: Events | undefined) {
|
|
177
|
+
if (!events || this.disposed) return;
|
|
178
|
+
|
|
179
|
+
for (const { key, handle } of this.sync) {
|
|
180
|
+
for (const ev of takeStack(events, key)) {
|
|
181
|
+
try {
|
|
182
|
+
handle(ev);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error(`Event handler for "${key}" failed:`, error);
|
|
185
|
+
} finally {
|
|
186
|
+
maybeFree(ev);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
for (const r of this.registered) {
|
|
192
|
+
const { events: keys } = r.handler;
|
|
193
|
+
const removed = takeStack(events, keys.removed);
|
|
194
|
+
const requested = takeStack(events, keys.requested);
|
|
195
|
+
const changed = keys.changed ? takeStack(events, keys.changed) : [];
|
|
196
|
+
|
|
197
|
+
// An add and a remove of the same entity in one frame cancel out.
|
|
198
|
+
const removedIds = new Set<string>();
|
|
199
|
+
for (const ev of removed) {
|
|
200
|
+
const id = idOf(ev);
|
|
201
|
+
if (id !== undefined) removedIds.add(id);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (const ev of requested) {
|
|
205
|
+
const id = idOf(ev);
|
|
206
|
+
if (id === undefined || removedIds.has(id) || r.jobs.has(id)) {
|
|
207
|
+
maybeFree(ev);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
this.start(r, id, ev);
|
|
211
|
+
}
|
|
212
|
+
for (const ev of removed) {
|
|
213
|
+
this.remove(r, idOf(ev), ev);
|
|
214
|
+
}
|
|
215
|
+
for (const ev of changed) {
|
|
216
|
+
this.change(r, idOf(ev), ev);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Aborts every in-flight job and forgets the table. Live products are the
|
|
222
|
+
* owner's to dispose (they are indexed outside the dispatcher). */
|
|
223
|
+
dispose() {
|
|
224
|
+
this.disposed = true;
|
|
225
|
+
for (const r of this.registered) {
|
|
226
|
+
for (const job of r.jobs.values()) {
|
|
227
|
+
job.abort.abort();
|
|
228
|
+
}
|
|
229
|
+
r.jobs.clear();
|
|
230
|
+
r.inFlight = 0;
|
|
231
|
+
}
|
|
232
|
+
this.inFlightJobs = 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private start(r: Registered, id: string, ev: object) {
|
|
236
|
+
const job: Job = {
|
|
237
|
+
abort: new AbortController(),
|
|
238
|
+
inFlight: true,
|
|
239
|
+
};
|
|
240
|
+
this.inFlightJobs++;
|
|
241
|
+
r.inFlight++;
|
|
242
|
+
r.jobs.set(id, job);
|
|
243
|
+
|
|
244
|
+
let promise: Promise<unknown>;
|
|
245
|
+
try {
|
|
246
|
+
promise = Promise.resolve(r.handler.start(ev, job.abort));
|
|
247
|
+
} catch (error) {
|
|
248
|
+
promise = Promise.reject(error);
|
|
249
|
+
}
|
|
250
|
+
promise.then(
|
|
251
|
+
(product) => {
|
|
252
|
+
job.product = product;
|
|
253
|
+
this.settleStart(r, id, job, ev);
|
|
254
|
+
},
|
|
255
|
+
(error) => {
|
|
256
|
+
// A kind with a `failed` hook treats failures as routine (a 404 tile
|
|
257
|
+
// is reported to the engine, not logged); only unexpected ones log.
|
|
258
|
+
if (job.removedEv === undefined && !this.disposed) {
|
|
259
|
+
if (r.handler.failed) {
|
|
260
|
+
try {
|
|
261
|
+
r.handler.failed(ev, error);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
console.error(`Job "${r.handler.name}" failed handler threw:`, e);
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
console.error(`Job "${r.handler.name}" failed to start:`, error);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
this.settleStart(r, id, job, ev);
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private settleStart(r: Registered, id: string, job: Job, ev: object) {
|
|
275
|
+
maybeFree(ev);
|
|
276
|
+
const product = job.product;
|
|
277
|
+
if (this.finish(r, id, job)) return;
|
|
278
|
+
if (product !== undefined) this.onSettled?.();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private remove(r: Registered, id: string | undefined, ev: object) {
|
|
282
|
+
const job = id === undefined ? undefined : r.jobs.get(id);
|
|
283
|
+
if (!job) {
|
|
284
|
+
this.teardown(r, undefined, ev);
|
|
285
|
+
maybeFree(ev);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
job.abort.abort();
|
|
289
|
+
if (job.inFlight) {
|
|
290
|
+
maybeFree(job.removedEv);
|
|
291
|
+
job.removedEv = ev;
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
r.jobs.delete(id as string);
|
|
295
|
+
this.teardown(r, job.product, ev);
|
|
296
|
+
maybeFree(ev);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private change(r: Registered, id: string | undefined, ev: object) {
|
|
300
|
+
const job = id === undefined ? undefined : r.jobs.get(id);
|
|
301
|
+
if (!job || !r.handler.change || job.removedEv !== undefined) {
|
|
302
|
+
maybeFree(ev);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (job.inFlight) {
|
|
306
|
+
maybeFree(job.pendingChange);
|
|
307
|
+
job.pendingChange = ev;
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (job.product === undefined) {
|
|
311
|
+
maybeFree(ev);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
this.applyChange(r, id as string, job, ev);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private applyChange(r: Registered, id: string, job: Job, ev: object) {
|
|
318
|
+
let result: void | Promise<void>;
|
|
319
|
+
try {
|
|
320
|
+
result = r.handler.change?.(job.product, ev);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error(`Job "${r.handler.name}" failed to change:`, error);
|
|
323
|
+
maybeFree(ev);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
// A synchronous change (a uniform or material update, the bulk case) is
|
|
327
|
+
// settled here; only one that returned a promise holds the job in flight.
|
|
328
|
+
if (!isThenable(result)) {
|
|
329
|
+
maybeFree(ev);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
job.inFlight = true;
|
|
333
|
+
this.inFlightJobs++;
|
|
334
|
+
r.inFlight++;
|
|
335
|
+
result
|
|
336
|
+
.catch((error) => {
|
|
337
|
+
console.error(`Job "${r.handler.name}" failed to change:`, error);
|
|
338
|
+
})
|
|
339
|
+
.finally(() => {
|
|
340
|
+
maybeFree(ev);
|
|
341
|
+
this.finish(r, id, job);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* The async call on `job` settled. Runs the deferred teardown when a
|
|
347
|
+
* `removed` arrived (or the dispatcher was disposed) meanwhile, otherwise
|
|
348
|
+
* applies the change that waited; returns whether the job is gone.
|
|
349
|
+
*/
|
|
350
|
+
private finish(r: Registered, id: string, job: Job): boolean {
|
|
351
|
+
job.inFlight = false;
|
|
352
|
+
if (!this.disposed) {
|
|
353
|
+
this.inFlightJobs--;
|
|
354
|
+
r.inFlight--;
|
|
355
|
+
}
|
|
356
|
+
if (job.removedEv === undefined && !this.disposed) {
|
|
357
|
+
const change = job.pendingChange;
|
|
358
|
+
job.pendingChange = undefined;
|
|
359
|
+
if (job.product === undefined) {
|
|
360
|
+
// Nothing to change or tear down: a later `removed` is handled as for
|
|
361
|
+
// an unknown id. Some entities are despawned without one, so keeping
|
|
362
|
+
// the entry would leak it.
|
|
363
|
+
maybeFree(change);
|
|
364
|
+
r.jobs.delete(id);
|
|
365
|
+
} else if (change !== undefined) {
|
|
366
|
+
this.applyChange(r, id, job, change);
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (r.jobs.get(id) === job) r.jobs.delete(id);
|
|
372
|
+
maybeFree(job.pendingChange);
|
|
373
|
+
job.pendingChange = undefined;
|
|
374
|
+
this.teardown(r, job.product, job.removedEv);
|
|
375
|
+
maybeFree(job.removedEv);
|
|
376
|
+
job.removedEv = undefined;
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private teardown(r: Registered, product: unknown, ev: object | undefined) {
|
|
381
|
+
try {
|
|
382
|
+
r.handler.teardown(product, ev);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.error(`Job "${r.handler.name}" failed to tear down:`, error);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
package/src/event/index.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./TransactionManager";
|
|
1
|
+
export * from "./JobDispatcher";
|
package/src/event/mock.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
} from "@navaramap/engine";
|
|
7
7
|
import { noop } from "lodash-es";
|
|
8
8
|
|
|
9
|
-
import type { JsEvents, JsEventsKey } from "./
|
|
9
|
+
import type { JsEvents, JsEventsKey } from "./JobDispatcher";
|
|
10
10
|
|
|
11
11
|
export const makeRenderableFeatures = <
|
|
12
12
|
Ev extends
|
|
@@ -19,7 +19,7 @@ export const makeRenderableFeatures = <
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// The real `Events` exposes each stack only via a `take_<key>()` method
|
|
22
|
-
// (see
|
|
22
|
+
// (see JobDispatcher.tick); mimic that shape for any key.
|
|
23
23
|
export const makeEvent = (events: { [K in JsEventsKey]?: JsEvents[K] }) =>
|
|
24
24
|
new Proxy(
|
|
25
25
|
{},
|
package/src/globe/Globe.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Globe as GlobeWasm } from "@navaramap/engine";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Color } from "../color";
|
|
4
4
|
import type { RemoveFreeRecursively } from "../types";
|
|
5
5
|
/**
|
|
6
6
|
* Handler for accessing individual Globe properties from WASM.
|
|
@@ -15,7 +15,6 @@ export type GlobeHandler = {
|
|
|
15
15
|
getUseNormal: () => boolean | undefined;
|
|
16
16
|
getOpacity: () => number | undefined;
|
|
17
17
|
getWireframe: () => boolean | undefined;
|
|
18
|
-
getElevationColormap: () => Float32Array | undefined;
|
|
19
18
|
setTransparent: (value: boolean) => void;
|
|
20
19
|
setMaxSse: (value: number) => void;
|
|
21
20
|
setSegments: (value: number) => void;
|
|
@@ -24,23 +23,14 @@ export type GlobeHandler = {
|
|
|
24
23
|
setUseNormal: (value: boolean) => void;
|
|
25
24
|
setOpacity: (value: number) => void;
|
|
26
25
|
setWireframe: (value: boolean) => void;
|
|
27
|
-
setElevationColormap: (value: ColorMap) => void;
|
|
28
26
|
};
|
|
29
27
|
|
|
30
28
|
// `isGeographicTiling` is engine-set output (the tiling scheme is dictated by
|
|
31
29
|
// the terrain source, not configurable), so it is excluded from both the
|
|
32
30
|
// options and the wrapper below.
|
|
33
31
|
export type GlobeOptions = Partial<
|
|
34
|
-
Omit<
|
|
35
|
-
GlobeWasm,
|
|
36
|
-
| "constructor"
|
|
37
|
-
| "free"
|
|
38
|
-
| "elevationColormap"
|
|
39
|
-
| "color"
|
|
40
|
-
| "isGeographicTiling"
|
|
41
|
-
>
|
|
32
|
+
Omit<GlobeWasm, "constructor" | "free" | "color" | "isGeographicTiling">
|
|
42
33
|
> & {
|
|
43
|
-
elevationColormap?: ColorMap;
|
|
44
34
|
color?: Color;
|
|
45
35
|
};
|
|
46
36
|
|
|
@@ -52,10 +42,9 @@ export type GlobeOptions = Partial<
|
|
|
52
42
|
*/
|
|
53
43
|
export class Globe implements Omit<
|
|
54
44
|
RemoveFreeRecursively<GlobeWasm>,
|
|
55
|
-
"
|
|
45
|
+
"color" | "isGeographicTiling"
|
|
56
46
|
> {
|
|
57
47
|
private handler: GlobeHandler;
|
|
58
|
-
private _elevationColormap?: ColorMap;
|
|
59
48
|
|
|
60
49
|
constructor(handler: GlobeHandler, options?: GlobeOptions) {
|
|
61
50
|
this.handler = handler;
|
|
@@ -87,9 +76,6 @@ export class Globe implements Omit<
|
|
|
87
76
|
if (options?.wireframe != null) {
|
|
88
77
|
this.wireframe = options.wireframe;
|
|
89
78
|
}
|
|
90
|
-
if (options?.elevationColormap != null) {
|
|
91
|
-
this.elevationColormap = options.elevationColormap;
|
|
92
|
-
}
|
|
93
79
|
}
|
|
94
80
|
|
|
95
81
|
get maxSse(): number {
|
|
@@ -154,13 +140,4 @@ export class Globe implements Omit<
|
|
|
154
140
|
set wireframe(value: boolean) {
|
|
155
141
|
this.handler.setWireframe(value);
|
|
156
142
|
}
|
|
157
|
-
|
|
158
|
-
get elevationColormap(): ColorMap | undefined {
|
|
159
|
-
return this._elevationColormap;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
set elevationColormap(value: ColorMap) {
|
|
163
|
-
this._elevationColormap = value;
|
|
164
|
-
this.handler.setElevationColormap(value);
|
|
165
|
-
}
|
|
166
143
|
}
|
|
@@ -17,6 +17,7 @@ export class ReturnedConstructedTerrainMeshLike implements RemoveFreeRecursively
|
|
|
17
17
|
skirt_uvs: Float32Array | undefined;
|
|
18
18
|
skirt_indices: Uint32Array | undefined;
|
|
19
19
|
skirt_normals: Float32Array | undefined;
|
|
20
|
+
skirt_heights: Float32Array | undefined;
|
|
20
21
|
watermask: Uint8Array | undefined;
|
|
21
22
|
|
|
22
23
|
// The transfer* methods return arrays copied out of WASM memory (owned by
|
|
@@ -40,6 +41,7 @@ export class ReturnedConstructedTerrainMeshLike implements RemoveFreeRecursively
|
|
|
40
41
|
this.skirt_uvs = t.transferSkirtUvs();
|
|
41
42
|
this.skirt_indices = t.transferSkirtIndices();
|
|
42
43
|
this.skirt_normals = t.transferSkirtNormals();
|
|
44
|
+
this.skirt_heights = t.transferSkirtHeights();
|
|
43
45
|
}
|
|
44
46
|
if (t.hasWatermask()) {
|
|
45
47
|
this.watermask = t.transferWatermask();
|
|
@@ -73,6 +75,9 @@ export class ReturnedConstructedTerrainMeshLike implements RemoveFreeRecursively
|
|
|
73
75
|
transferSkirtNormals(): Float32Array | undefined {
|
|
74
76
|
throw new Error();
|
|
75
77
|
}
|
|
78
|
+
transferSkirtHeights(): Float32Array | undefined {
|
|
79
|
+
throw new Error();
|
|
80
|
+
}
|
|
76
81
|
transferWatermask(): Uint8Array | undefined {
|
|
77
82
|
throw new Error();
|
|
78
83
|
}
|
|
@@ -22,17 +22,19 @@ export class ConstructedPolylineGeometryLike {
|
|
|
22
22
|
end_high_size: number | undefined;
|
|
23
23
|
end_low: Float32Array | undefined;
|
|
24
24
|
end_low_size: number | undefined;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
start_normal_and_length_high: Float32Array | undefined;
|
|
26
|
+
start_normal_and_length_high_size: number | undefined;
|
|
27
|
+
end_normal_and_segment_length: Float32Array | undefined;
|
|
28
|
+
end_normal_and_segment_length_size: number | undefined;
|
|
29
|
+
right_normal_and_line_length: Float32Array;
|
|
30
|
+
right_normal_and_line_length_size: number;
|
|
31
31
|
batch_id: Float32Array | undefined;
|
|
32
32
|
batch_id_size: number | undefined;
|
|
33
33
|
batch_index: Uint32Array | undefined;
|
|
34
34
|
batch_index_size: number | undefined;
|
|
35
35
|
indices: Uint32Array;
|
|
36
|
+
line_segments: Float32Array | undefined;
|
|
37
|
+
line_distance_and_ends: Float32Array | undefined;
|
|
36
38
|
|
|
37
39
|
constructor(t: ConstructedPolylineGeometry) {
|
|
38
40
|
const extent = t.extent;
|
|
@@ -56,22 +58,27 @@ export class ConstructedPolylineGeometryLike {
|
|
|
56
58
|
this.end_high_size = t.end_high_size();
|
|
57
59
|
this.end_low = t.end_low()?.slice();
|
|
58
60
|
this.end_low_size = t.end_low_size();
|
|
59
|
-
this.
|
|
60
|
-
|
|
61
|
-
this.end_normal_and_texture_coordinate_normalization_x = t
|
|
62
|
-
.end_normal_and_texture_coordinate_normalization_x()
|
|
61
|
+
this.start_normal_and_length_high = t
|
|
62
|
+
.start_normal_and_length_high()
|
|
63
63
|
?.slice();
|
|
64
|
-
this.
|
|
65
|
-
t.
|
|
66
|
-
this.
|
|
67
|
-
.
|
|
64
|
+
this.start_normal_and_length_high_size =
|
|
65
|
+
t.start_normal_and_length_high_size();
|
|
66
|
+
this.end_normal_and_segment_length = t
|
|
67
|
+
.end_normal_and_segment_length()
|
|
68
|
+
?.slice();
|
|
69
|
+
this.end_normal_and_segment_length_size =
|
|
70
|
+
t.end_normal_and_segment_length_size();
|
|
71
|
+
this.right_normal_and_line_length = t
|
|
72
|
+
.right_normal_and_line_length()
|
|
68
73
|
.slice();
|
|
69
|
-
this.
|
|
70
|
-
t.
|
|
74
|
+
this.right_normal_and_line_length_size =
|
|
75
|
+
t.right_normal_and_line_length_size();
|
|
71
76
|
this.batch_id = t.batch_id()?.slice();
|
|
72
77
|
this.batch_id_size = t.batch_id_size();
|
|
73
78
|
this.batch_index = t.batch_index()?.slice();
|
|
74
79
|
this.batch_index_size = t.batch_index_size();
|
|
75
80
|
this.indices = t.indices().slice();
|
|
81
|
+
this.line_segments = t.line_segments()?.slice();
|
|
82
|
+
this.line_distance_and_ends = t.line_distance_and_ends()?.slice();
|
|
76
83
|
}
|
|
77
84
|
}
|