@smarterplan/ngx-smarterplan-core 1.4.21 → 1.4.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.
Files changed (114) hide show
  1. package/README.md +24 -24
  2. package/esm2022/lib/components/csv-export/csv-export.component.mjs +3 -3
  3. package/esm2022/lib/components/loader/loader.component.mjs +3 -3
  4. package/esm2022/lib/components/menu-bar/avatar/avatar.component.mjs +1 -1
  5. package/esm2022/lib/components/menu-bar/menu-bar.component.mjs +3 -3
  6. package/esm2022/lib/components/menu-bar/navigation-bar/navigation-bar.component.mjs +3 -3
  7. package/esm2022/lib/components/modal-switch-visit/modal-switch-visit.component.mjs +3 -3
  8. package/esm2022/lib/components/search-bar/search-bar.component.mjs +3 -3
  9. package/esm2022/lib/components/splat-viewer/splat-viewer.component.mjs +361 -0
  10. package/esm2022/lib/components/support-modal/support-modal.component.mjs +3 -3
  11. package/esm2022/lib/config.mjs +1 -1
  12. package/esm2022/lib/helpers.service.mjs +1 -1
  13. package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasImage.mjs +1 -1
  14. package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasRenderer.mjs +1 -1
  15. package/esm2022/lib/matterport-extensions/nest-thermostat/NestThermostat.mjs +1 -1
  16. package/esm2022/lib/matterport-extensions/nest-thermostat/PlaneRenderer.mjs +1 -1
  17. package/esm2022/lib/matterport-extensions/scene-component/SceneComponent.mjs +1 -1
  18. package/esm2022/lib/matterport-extensions/security-camera/SecurityCamera.mjs +22 -22
  19. package/esm2022/lib/matterport-extensions/tv-player/TvPlayer.mjs +1 -1
  20. package/esm2022/lib/matterport-extensions/view-frustum-mesh/ViewFrustumMesh.mjs +22 -22
  21. package/esm2022/lib/mattertagData.mjs +1 -1
  22. package/esm2022/lib/ngx-smarterplan-core.module.mjs +9 -4
  23. package/esm2022/lib/ngx-smarterplan-core.service.mjs +1 -1
  24. package/esm2022/lib/pipes/duration-to-string.pipe.mjs +1 -1
  25. package/esm2022/lib/pipes/format-date-number-to-digits.pipe.mjs +1 -1
  26. package/esm2022/lib/pipes/hashtag-from-id.pipe.mjs +1 -1
  27. package/esm2022/lib/pipes/safe-url.pipe.mjs +1 -1
  28. package/esm2022/lib/pipes/time-date-to-local-string.pipe.mjs +1 -1
  29. package/esm2022/lib/pipes/username-from-id.pipe.mjs +1 -1
  30. package/esm2022/lib/services/amplify-cache.service.mjs +1 -1
  31. package/esm2022/lib/services/base-tab.service.mjs +1 -1
  32. package/esm2022/lib/services/baseVisibility.service.mjs +1 -1
  33. package/esm2022/lib/services/content.service.mjs +1 -1
  34. package/esm2022/lib/services/filter.service.mjs +1 -1
  35. package/esm2022/lib/services/intervention.service.mjs +1 -1
  36. package/esm2022/lib/services/locale.service.mjs +1 -1
  37. package/esm2022/lib/services/matterport-import.service.mjs +1 -1
  38. package/esm2022/lib/services/matterport-measurement.service.mjs +1 -1
  39. package/esm2022/lib/services/matterport-navigation.service.mjs +1 -1
  40. package/esm2022/lib/services/matterport-pointer.service.mjs +6 -6
  41. package/esm2022/lib/services/matterport-tag-copy.service.mjs +1 -1
  42. package/esm2022/lib/services/matterport-tag.service.mjs +12 -7
  43. package/esm2022/lib/services/matterport.service.mjs +17 -17
  44. package/esm2022/lib/services/models/affectation.service.mjs +1 -1
  45. package/esm2022/lib/services/models/base-object.service.mjs +1 -1
  46. package/esm2022/lib/services/models/capture.service.mjs +1 -1
  47. package/esm2022/lib/services/models/comment.service.mjs +1 -1
  48. package/esm2022/lib/services/models/domain.service.mjs +1 -1
  49. package/esm2022/lib/services/models/equipment.service.mjs +1 -1
  50. package/esm2022/lib/services/models/event.service.mjs +1 -1
  51. package/esm2022/lib/services/models/feature.service.mjs +1 -1
  52. package/esm2022/lib/services/models/hashtag.service.mjs +1 -1
  53. package/esm2022/lib/services/models/layer.service.mjs +1 -1
  54. package/esm2022/lib/services/models/measurement.service.mjs +1 -1
  55. package/esm2022/lib/services/models/mission.service.mjs +1 -1
  56. package/esm2022/lib/services/models/navigation.service.mjs +1 -1
  57. package/esm2022/lib/services/models/node.service.mjs +1 -1
  58. package/esm2022/lib/services/models/object3D.service.mjs +1 -1
  59. package/esm2022/lib/services/models/operation.service.mjs +1 -1
  60. package/esm2022/lib/services/models/organisation.service.mjs +1 -1
  61. package/esm2022/lib/services/models/plan.service.mjs +1 -1
  62. package/esm2022/lib/services/models/poi.service.mjs +27 -27
  63. package/esm2022/lib/services/models/profile.service.mjs +1 -1
  64. package/esm2022/lib/services/models/property.service.mjs +1 -1
  65. package/esm2022/lib/services/models/space.service.mjs +1 -1
  66. package/esm2022/lib/services/models/template.service.mjs +1 -1
  67. package/esm2022/lib/services/models/ticket.service.mjs +1 -1
  68. package/esm2022/lib/services/models/visit.service.mjs +1 -1
  69. package/esm2022/lib/services/models/zone.service.mjs +1 -1
  70. package/esm2022/lib/services/navigator.service.mjs +1 -1
  71. package/esm2022/lib/services/obj-to-glb.mjs +649 -0
  72. package/esm2022/lib/services/s3.service.mjs +43 -3
  73. package/esm2022/lib/services/search.service.mjs +1 -1
  74. package/esm2022/lib/services/support.service.mjs +1 -1
  75. package/esm2022/lib/services/sweep-locator.service.mjs +1 -1
  76. package/esm2022/lib/services/tag.service.mjs +16 -16
  77. package/esm2022/lib/services/threejs-import.service.mjs +6 -4
  78. package/esm2022/lib/services/threejs.service.mjs +867 -95
  79. package/esm2022/lib/services/user.service.mjs +1 -1
  80. package/esm2022/lib/services/utils/matterport-transform.util.mjs +1 -1
  81. package/esm2022/lib/services/validators.service.mjs +1 -1
  82. package/esm2022/lib/services/viewer.service.mjs +189 -7
  83. package/esm2022/lib/services/zone-drawer.service.mjs +1 -1
  84. package/esm2022/lib/services/zoneChange.service.mjs +1 -1
  85. package/esm2022/lib/tokens/matterport-sdk-key.token.mjs +1 -1
  86. package/esm2022/lib/validators/email.directive.mjs +1 -1
  87. package/esm2022/lib/validators/no-empty.directive.mjs +1 -1
  88. package/esm2022/lib/validators/number.directive.mjs +1 -1
  89. package/esm2022/lib/validators/text.directive.mjs +1 -1
  90. package/esm2022/public-api.mjs +3 -1
  91. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +2239 -233
  92. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
  93. package/lib/components/splat-viewer/splat-viewer.component.d.ts +98 -0
  94. package/lib/ngx-smarterplan-core.module.d.ts +7 -6
  95. package/lib/services/matterport-tag.service.d.ts +5 -5
  96. package/lib/services/obj-to-glb.d.ts +66 -0
  97. package/lib/services/s3.service.d.ts +7 -0
  98. package/lib/services/threejs.service.d.ts +336 -16
  99. package/lib/services/viewer.service.d.ts +110 -8
  100. package/package.json +1 -1
  101. package/public-api.d.ts +2 -0
  102. package/src/assets/viewers/splat/chunk-BYLI4YBI.js +17037 -0
  103. package/src/assets/viewers/splat/chunk-LDV6YPMG.js +1 -0
  104. package/src/assets/viewers/splat/chunk-WZ5Z4TU3.js +105719 -0
  105. package/src/assets/viewers/splat/convert-4DRLH77X.js +1 -0
  106. package/src/assets/viewers/splat/convert.html +11 -0
  107. package/src/assets/viewers/splat/converter-SLBB5MHG.js +1 -0
  108. package/src/assets/viewers/splat/index.html +90 -0
  109. package/src/assets/viewers/splat/spz-DEYRea_v-QE6YSGIB.js +5292 -0
  110. package/src/assets/viewers/splat/viewer-W4X3FWQJ.js +2704 -0
  111. package/src/assets/viewers/splat/viewer.css +1096 -0
  112. package/src/assets/viewers/splat/webp.wasm +0 -0
  113. package/src/assets/viewers/splat/worker.mjs +1383 -0
  114. package/src/assets/vs-app.json +67 -67
@@ -33,6 +33,35 @@ export interface ThreeJsTag {
33
33
  iconUrl?: string | null;
34
34
  /** Tint for the fallback disc, as a CSS colour. */
35
35
  color?: string;
36
+ /**
37
+ * Which way the surface the tag is on faces, in the tag's frame: Matterport's stem, which the
38
+ * splat viewer draws the tag at the end of.
39
+ */
40
+ normal?: {
41
+ x: number;
42
+ y: number;
43
+ z: number;
44
+ } | null;
45
+ }
46
+ /** A tag as a viewer drawing the scene elsewhere needs it - the splat viewer, in its iframe. */
47
+ export interface ThreeJsTagSnapshot {
48
+ id: string;
49
+ position: {
50
+ x: number;
51
+ y: number;
52
+ z: number;
53
+ };
54
+ label: string | null;
55
+ poiType: PoiType | null;
56
+ iconUrl: string | null;
57
+ /** In the model's own coordinates, so not moved by the calibration. */
58
+ inModelFrame: boolean;
59
+ /** Which way its surface faces, in the same frame as its position; null when not known. */
60
+ normal: {
61
+ x: number;
62
+ y: number;
63
+ z: number;
64
+ } | null;
36
65
  }
37
66
  /** What a click on a tag reports: enough to route to the element's detail page. */
38
67
  export interface ThreeJsTagClick {
@@ -112,6 +141,28 @@ export interface ThreeJsAlignmentPair {
112
141
  z: number;
113
142
  };
114
143
  }
144
+ /** A tag already matched in the calibration under way, as the panel lists it. */
145
+ export interface ThreeJsAlignmentMatch {
146
+ tagId: string;
147
+ label: string | null;
148
+ poiType: PoiType | null;
149
+ /** Where it was said to really be, in the model's own coordinates: for another viewer to draw its pin. */
150
+ target: {
151
+ x: number;
152
+ y: number;
153
+ z: number;
154
+ };
155
+ }
156
+ /** Where a calibration under way has got to, for the panel that drives it. */
157
+ export interface ThreeJsAlignmentProgress {
158
+ pairs: number;
159
+ /** What the next click is expected to be, or null when there is nothing left to click. */
160
+ awaiting: 'tag' | 'point' | null;
161
+ /** The tag whose place on the model is being asked for, while `awaiting` is 'point'. */
162
+ tagId?: string;
163
+ /** The tags matched so far, in the order they were matched - the order they are numbered in. */
164
+ matched: ThreeJsAlignmentMatch[];
165
+ }
115
166
  /**
116
167
  * Solves the transform that maps stored tag coordinates onto the loaded model, from as many matched
117
168
  * tags as there are - up to three.
@@ -134,6 +185,11 @@ export declare function solveThreeJsAlignment(pairs: ThreeJsAlignmentPair[], tar
134
185
  y: number;
135
186
  z: number;
136
187
  }): ThreeJsAlignment | null;
188
+ /**
189
+ * The 3D viewers' background where there is nothing to draw, unless the app sets its own as
190
+ * --smarterplan-viewer-background: the SmarterPlan app's light blue, from the POC.
191
+ */
192
+ export declare const VIEWER_BACKGROUND = "#e0f7ff";
137
193
  export interface ObjAdded {
138
194
  id: string;
139
195
  name: string;
@@ -173,6 +229,17 @@ export declare class ThreeJsService {
173
229
  objectClicked$: Subject<string>;
174
230
  /** Emits when the user clicks a tag, mirroring Matterport's tag click. */
175
231
  tagClicked$: Subject<ThreeJsTagClick>;
232
+ /**
233
+ * Emits the tag the camera is sent to (goToTag): for a viewer drawing the model elsewhere, the
234
+ * splat viewer, to point it out.
235
+ */
236
+ tagFocused$: Subject<string>;
237
+ /**
238
+ * Emits when the tags change - added, moved, removed, filtered, calibrated differently - at most
239
+ * once per turn of the event loop, however many changed in it.
240
+ */
241
+ tagsChanged$: Subject<void>;
242
+ private tagsChangeQueued;
176
243
  /** Emits a tag's label while the pointer is over it, and null when it leaves. */
177
244
  tagHovered$: Subject<{
178
245
  label: string;
@@ -183,6 +250,22 @@ export declare class ThreeJsService {
183
250
  private canvasResizeObserver?;
184
251
  /** Aborts the in-flight model download. Parsing cannot be interrupted, only not started. */
185
252
  private loadAbortController?;
253
+ /**
254
+ * Which load is the wanted one. Every load takes the next number as it starts, and anything that
255
+ * makes it unwanted - another load, the scene being rebuilt, the viewer closing - moves the
256
+ * number on.
257
+ *
258
+ * Aborting the download is not enough to stop a load. A model read from the cache has no
259
+ * download to abort, and one that has finished downloading still has seconds of work ahead of it
260
+ * before it reaches the screen. A load that finds the number has moved on drops what it has.
261
+ */
262
+ private loadGeneration;
263
+ /** Whether the wanted load is still on its way, so abandoning it can say that it stopped. */
264
+ private loadInProgress;
265
+ /** Whether a scene is up: started by init() and not yet taken down by destroy(). */
266
+ private live;
267
+ /** Takes off each listener init() put on the canvas. */
268
+ private canvasListeners;
186
269
  private modelRoot?;
187
270
  /** True while the next click on the model places a tag instead of orbiting. */
188
271
  private placingTag;
@@ -203,6 +286,12 @@ export declare class ThreeJsService {
203
286
  * placed in this one are told from those that came from elsewhere.
204
287
  */
205
288
  private currentCaptureID;
289
+ /**
290
+ * Whether the visit on screen is the only one the site has. A tag records the visit it was placed
291
+ * in, but some do not - placed before that was recorded, or in the development model. With
292
+ * another visit around, such a tag is taken to come from it. With none, it can only be this one's.
293
+ */
294
+ private soleVisit;
206
295
  /**
207
296
  * The model's surface as a grid: every cell some part of the surface passes through.
208
297
  *
@@ -250,6 +339,17 @@ export declare class ThreeJsService {
250
339
  points: number;
251
340
  distances: number[];
252
341
  }>;
342
+ /**
343
+ * True when a measurement starts taking clicks, false when it stops - finished or abandoned. For a
344
+ * viewer drawing the model elsewhere, which takes the clicks itself; see addMeasurePointAtModelPoint.
345
+ */
346
+ measuringChanged$: Subject<boolean>;
347
+ /**
348
+ * A measurement - under way or finished - was taken off the model. For a viewer drawing it
349
+ * elsewhere, the splat viewer: a finished one stays drawn while its form is open, which
350
+ * measurementProgress$ does not say the end of.
351
+ */
352
+ measurementCleared$: Subject<void>;
253
353
  /**
254
354
  * Layer carrying the model alone, so the depth pick can render it without the tags.
255
355
  *
@@ -257,8 +357,18 @@ export declare class ThreeJsService {
257
357
  * their parent passed, so marking the model's own meshes is enough - no re-parenting.
258
358
  */
259
359
  private static readonly PICK_LAYER;
360
+ /** How large a tag is drawn, in CSS pixels. About what Matterport draws its own at. */
361
+ private static readonly TAG_SCREEN_PX;
260
362
  /** The app's highlight colour, so a measurement reads as the active thing on screen. */
261
363
  private static readonly MEASURE_COLOR;
364
+ /** Green for the points of a calibration that are settled, as opposed to the one in hand. */
365
+ private static readonly CALIBRATION_DONE_COLOR;
366
+ /** Size on screen of the numbered pin left where a tag was matched: a little under a tag's. */
367
+ private static readonly CALIBRATION_PIN_PX;
368
+ /** How long a mark just dropped takes to settle to its size, in milliseconds. */
369
+ private static readonly CONFIRM_PULSE_MS;
370
+ /** How many matched tags a calibration takes. Three settle everything there is to settle. */
371
+ private static readonly CALIBRATION_PAIRS;
262
372
  /** Cache Storage bucket holding downloaded models, and how many to keep. */
263
373
  private static readonly MODEL_CACHE;
264
374
  private static readonly MODEL_CACHE_SIZE;
@@ -273,16 +383,36 @@ export declare class ThreeJsService {
273
383
  /** Translucent marker shown under the cursor while placing. */
274
384
  private placementPreview?;
275
385
  private aligning;
386
+ /**
387
+ * True from the moment the calibration panel opens, before the walkthrough is armed: the tags
388
+ * from elsewhere are all on show, as they are while calibrating, so that what there is to
389
+ * calibrate with can be seen while reading what calibrating involves.
390
+ */
391
+ private revealingCalibrationTags;
276
392
  private alignmentPairs;
277
393
  private alignmentSource;
278
394
  /** The tag `alignmentSource` was read from, kept so the same tag is not matched twice. */
279
395
  private alignmentSourceTagId;
396
+ /**
397
+ * Everything drawn for the calibration under way: a numbered pin where each tag was matched, a
398
+ * line from the pin to its tag, and a ring round the tag being matched.
399
+ *
400
+ * A sibling of the tag group rather than a child of it. The points clicked are where the tags are
401
+ * to end up, in the frame the calibration maps onto (see pickAlignmentTarget) - not in the tags'
402
+ * own frame, which is the one about to change.
403
+ */
404
+ private calibrationGroup;
405
+ /** Marks still settling after being dropped, advanced by the render loop. */
406
+ private pulses;
280
407
  /** Drives the alignment walkthrough's UI: how many pairs are done and what it wants next. */
281
- alignmentProgress$: Subject<{
282
- pairs: number;
283
- awaiting: 'tag' | 'point' | null;
284
- tagId?: string;
285
- }>;
408
+ alignmentProgress$: Subject<ThreeJsAlignmentProgress>;
409
+ /**
410
+ * Emits when a click during calibration did nothing, with what it was expected to land on.
411
+ *
412
+ * A click that changes nothing looks the same as a click that was not received. This lets the
413
+ * panel point at what it is waiting for instead.
414
+ */
415
+ alignmentClickIgnored$: Subject<"tag" | "point">;
286
416
  /** In-flight camera move started by goToTag, advanced by the render loop. */
287
417
  private cameraTween;
288
418
  /** Emits true while a heavy OBJ file is being parsed (in a worker, when available), false once done. */
@@ -338,6 +468,8 @@ export declare class ThreeJsService {
338
468
  y: number;
339
469
  z: number;
340
470
  }, cacheKey?: string, up?: ThreeJsModelUp): void;
471
+ /** Ends a load that failed, unless another load has replaced it in the meantime. */
472
+ private loadFailed;
341
473
  /**
342
474
  * Stops the model download in progress, if any.
343
475
  *
@@ -354,6 +486,13 @@ export declare class ThreeJsService {
354
486
  * scene is not something the person asked for, so it must not surface as "loading cancelled".
355
487
  */
356
488
  private discardCurrentLoad;
489
+ /**
490
+ * Starts a load, replacing whichever was under way, and returns the question it has to keep
491
+ * asking: is it still the one that is wanted?
492
+ */
493
+ private beginLoad;
494
+ /** Marks the wanted load as over, whichever way it ended. */
495
+ private endLoad;
357
496
  /**
358
497
  * Resolves once the browser has painted at least one frame.
359
498
  *
@@ -474,16 +613,25 @@ export declare class ThreeJsService {
474
613
  * not clear enough to act on.
475
614
  *
476
615
  * Models arrive in two conventions: Y up (glTF, and what this viewer assumes) and Z up (most CAD
477
- * and scanning exports). A Z-up model loads lying on its side. Two independent cues say which
478
- * axis is the vertical one, and both have to agree before anything is turned:
616
+ * and scanning exports). A Z-up model loads lying on its side. Three independent cues say which
617
+ * axis is the vertical one:
479
618
  *
480
619
  * - Surface area. Floors and ceilings all face along the vertical, while walls are shared out
481
620
  * between the two horizontal axes, so the vertical usually collects the most area.
482
621
  * - Extent. A building is normally wider than it is tall, so the vertical is its shortest side.
622
+ * - Openness. A capture made from outside has ground and roofs but nothing underneath them, so
623
+ * along the vertical nearly all of its surface faces one way; walls face both ways evenly.
483
624
  *
484
- * Either alone is wrong often enough to matter - a long corridor has more wall than floor, a
485
- * tower is taller than it is wide - and turning a model that was fine is worse than leaving one
486
- * that was not. A model that already has Y as its vertical is never touched.
625
+ * Each is wrong often enough on its own - a long corridor has more wall than floor, a tower is
626
+ * taller than it is wide - so a cue only counts when its answer is clear-cut, and the model is
627
+ * turned when the clear answers agree. It used to take area and extent agreeing with each other,
628
+ * which failed on exactly the models that need this most: in a whole building or a city block
629
+ * there is as much wall as floor, the area cue comes out a three-way tie, and a model 130 m wide
630
+ * and 34 m tall with 86% of its surface facing one way was left lying on its side.
631
+ *
632
+ * Turning a model that was fine is worse than leaving one that was not: when the clear answers
633
+ * contradict each other, or there is none, nothing is turned. A model that already has Y as its
634
+ * vertical is never touched.
487
635
  */
488
636
  private detectModelUp;
489
637
  /** The rotation that brings the given model axis to point up. */
@@ -516,6 +664,22 @@ export declare class ThreeJsService {
516
664
  * only has to supply the matching spot on the model. No new records are written; nothing is
517
665
  * applied until solveAlignmentFromPairs() succeeds.
518
666
  */
667
+ /**
668
+ * Shows every tag that came from elsewhere, whether or not it lands on the model, without arming
669
+ * anything: clicks still do what they always do.
670
+ *
671
+ * Calibrating shows them too, and ending a calibration - saved or abandoned - puts them back
672
+ * under the usual rule, so this only ever has to be switched on.
673
+ */
674
+ revealCalibrationTags(revealed?: boolean): void;
675
+ /**
676
+ * Whether the tags a calibration works with are on show - while one is under way, or its panel
677
+ * open - including those that do not land on the model. For another viewer showing the tags,
678
+ * which otherwise leaves out the ones from elsewhere until the model is calibrated.
679
+ */
680
+ showsCalibrationTags(): boolean;
681
+ /** Says a tag was clicked in a viewer drawing the model elsewhere, as a click on it here would. */
682
+ clickTag(elementId: string): void;
519
683
  startTagAlignment(): void;
520
684
  cancelTagAlignment(): void;
521
685
  isAligningTags(): boolean;
@@ -560,8 +724,66 @@ export declare class ThreeJsService {
560
724
  */
561
725
  selectAlignmentTag(elementId: string): boolean;
562
726
  private setAlignmentSource;
727
+ private clearAlignmentSource;
728
+ /** Whether the calibration still has room for a pair and a tag to make it from. */
729
+ private canMatchAnotherTag;
563
730
  /** Handles a click while the alignment walkthrough is running. */
564
731
  private handleAlignmentClick;
732
+ /**
733
+ * Records where the tag being matched really is, from a spot another viewer picked on the model -
734
+ * the splat viewer - in the model's own coordinates: the frame pickAlignmentTarget measures a
735
+ * click in, as placeTagAtModelPoint takes it. False when no tag is waiting for its spot.
736
+ */
737
+ matchAlignmentTagAtModelPoint(point: {
738
+ x: number;
739
+ y: number;
740
+ z: number;
741
+ }): boolean;
742
+ /**
743
+ * Takes back the last thing done in the calibration under way: the choice of tag while its place
744
+ * on the model is being asked for, the last matched pair otherwise.
745
+ *
746
+ * One step at a time, so a click made by mistake costs that click and not the whole calibration.
747
+ * Returns false when there is nothing to take back.
748
+ */
749
+ undoAlignmentStep(): boolean;
750
+ /**
751
+ * Removes one matched pair, whichever it is, putting its tag back on offer.
752
+ *
753
+ * For the point noticed to be wrong only after others were matched: taking steps back one by one
754
+ * to reach it would throw away the good ones made since.
755
+ */
756
+ removeAlignmentPair(index: number): boolean;
757
+ /** The tags matched so far in the calibration under way, in the order they are numbered in. */
758
+ getAlignmentPairs(): ThreeJsAlignmentMatch[];
759
+ /**
760
+ * Brings the scene and the panel in line with the calibration's state, after anything changed it.
761
+ *
762
+ * `dropped` names the mark the change put down, if it put one down, so that it can be shown
763
+ * arriving: that movement is what tells someone their click was taken.
764
+ */
765
+ private alignmentChanged;
766
+ /**
767
+ * Draws the calibration as it stands: what has been matched, and what is being matched.
768
+ *
769
+ * Redrawn whole on every change rather than patched. There are at most three pairs, and undoing
770
+ * or removing one renumbers the others.
771
+ */
772
+ private redrawCalibrationMarks;
773
+ /** Removes everything drawn for a calibration, and gives the tags it dimmed their look back. */
774
+ private clearCalibrationMarks;
775
+ /**
776
+ * A calibration mark: a fixed size on screen and showing through the model, as the tags do, and
777
+ * drawn in the colours it was painted in.
778
+ *
779
+ * The renderer's tone mapping and output conversion are there for the model's lighting. Put
780
+ * through them a mark comes out pale - the amber nearer to cream - and a mark that has to be
781
+ * picked out against a photograph of a building is the last thing that should be.
782
+ */
783
+ private createCalibrationMark;
784
+ /** Shows a mark arriving: it starts oversized and settles. */
785
+ private pulse;
786
+ private stepPulses;
565
787
  /**
566
788
  * Starts a measurement: every click on the model adds a point, and each pair of consecutive
567
789
  * points is a measured segment.
@@ -585,7 +807,23 @@ export declare class ThreeJsService {
585
807
  * The drawing stays on the model so it is still visible while the person names the measurement;
586
808
  * cancelMeasuring() takes it away afterwards.
587
809
  */
588
- finishMeasuring(): ThreeJsMeasurement | null;
810
+ finishMeasuring(screenshot?: string): ThreeJsMeasurement | null;
811
+ /**
812
+ * Adds a point to the measurement under way from a spot another viewer picked on the model - the
813
+ * splat viewer - in the model's own coordinates. Into the frame the measurement is kept in, the
814
+ * tags', through the calibration, as placeTagAtModelPoint does. False when not measuring.
815
+ */
816
+ addMeasurePointAtModelPoint(point: {
817
+ x: number;
818
+ y: number;
819
+ z: number;
820
+ }): boolean;
821
+ /** The measurement's points, under way or finished, in the model's own coordinates: for a viewer drawing it elsewhere. */
822
+ getMeasurePointsInModelFrame(): {
823
+ x: number;
824
+ y: number;
825
+ z: number;
826
+ }[];
589
827
  isMeasuring(): boolean;
590
828
  /** The measurement finishMeasuring() last produced, for the form that saves it. */
591
829
  getLastMeasurement(): ThreeJsMeasurement | null;
@@ -614,8 +852,28 @@ export declare class ThreeJsService {
614
852
  * browser presents it, and scaled down since it is uploaded and shown as a thumbnail.
615
853
  */
616
854
  private captureMeasurementScreenshot;
855
+ /**
856
+ * True when tag placement is armed, false when it ends - placed or abandoned. For a viewer drawing
857
+ * the model instead of this scene, the splat viewer, which picks the spot itself; see
858
+ * placeTagAtModelPoint.
859
+ */
860
+ readonly placementChanged$: Subject<boolean>;
617
861
  /** Arms tag placement: the next click on the model drops a tag instead of being ignored. */
618
862
  startTagPlacement(poiType?: PoiType | null): void;
863
+ /**
864
+ * Places the armed tag at a spot another viewer picked on the model - the splat viewer - given
865
+ * in the model's own coordinates, as a click on the model in this scene would. Into the frame tag
866
+ * coordinates are stored in, through the calibration, as pickPlacementOnModel does.
867
+ */
868
+ placeTagAtModelPoint(point: {
869
+ x: number;
870
+ y: number;
871
+ z: number;
872
+ }, normal?: {
873
+ x: number;
874
+ y: number;
875
+ z: number;
876
+ } | null): ThreeJsTagPlacement | null;
619
877
  /** Leaves placement mode without placing anything. */
620
878
  cancelTagPlacement(): void;
621
879
  /**
@@ -650,6 +908,8 @@ export declare class ThreeJsService {
650
908
  * filter that happens to match nothing.
651
909
  */
652
910
  setVisibleTagTypes(types: PoiType[] | null): void;
911
+ /** Says whether the visit on screen is the site's only one; see soleVisit. */
912
+ setSoleVisit(sole: boolean): void;
653
913
  /** Says which capture is on screen, so the tags placed in it can be told from the rest. */
654
914
  setCurrentCapture(captureID: string | null): void;
655
915
  /** Every tag registered in the scene, shown or not. */
@@ -779,6 +1039,18 @@ export declare class ThreeJsService {
779
1039
  * on each of those would wipe the types that came before.
780
1040
  */
781
1041
  upsertTag(tag: ThreeJsTag): void;
1042
+ /**
1043
+ * The tags another viewer should show, and the calibration they are drawn under.
1044
+ *
1045
+ * The same ones this scene would offer, short of the test against the model's surface, which needs
1046
+ * the model here: the type filter applies, and a tag placed in another model before it was
1047
+ * calibrated is left out, its coordinates meaning nothing in this one.
1048
+ */
1049
+ getTagSnapshot(): {
1050
+ tags: ThreeJsTagSnapshot[];
1051
+ alignment: ThreeJsAlignment;
1052
+ };
1053
+ private announceTagsChanged;
782
1054
  /** Removes the tag registered for an element, if there is one. */
783
1055
  removeTag(elementId: string): void;
784
1056
  /** Removes every tag from the scene. */
@@ -787,14 +1059,32 @@ export declare class ThreeJsService {
787
1059
  private applyTagIcon;
788
1060
  /** Draws the default tag marker: a filled disc with a white ring, so it reads on any background. */
789
1061
  private createTagTexture;
1062
+ /** The default marker with a number on it: the nth point of a calibration. */
1063
+ private createNumberedTexture;
1064
+ /** A ring with nothing in the middle, to go round a tag and leave it showing. */
1065
+ private createRingTexture;
790
1066
  /**
791
- * Sizes a tag relative to the model.
1067
+ * Gives a tag its size: the same number of pixels on screen whatever the model.
792
1068
  *
793
- * A sprite inherits the model's scale and the alignment's, so a fixed size would come out tiny on
794
- * a large model and huge on a small one. Dividing by the group's world scale keeps tags the same
795
- * size on screen whatever the model's units are.
1069
+ * It used to be a fixed fraction of the model instead. That reads fine on a room, but on a model
1070
+ * the size of a city block it is a tag several metres across, which fills the view as soon as
1071
+ * the camera moves in to look at anything.
796
1072
  */
797
1073
  private scaleTagForModel;
1074
+ /**
1075
+ * Fixes a sprite's size on screen, in CSS pixels.
1076
+ *
1077
+ * The sprite must be drawn without size attenuation, which makes its size a proportion of the
1078
+ * viewport instead of something that shrinks with distance. Its scale is then worked back from
1079
+ * the pixels wanted, the viewport's height and the scale it inherits from its parents - the
1080
+ * model's normalisation and, for tags, the calibration - so none of those show in the result.
1081
+ * The size asked for is kept on the sprite, so it can be worked out again when any of them changes.
1082
+ */
1083
+ private setScreenSize;
1084
+ /** What one screen pixel is worth in the scale of a sprite drawn without size attenuation. */
1085
+ private worldUnitsPerPixel;
1086
+ /** Re-applies every marker's on-screen size: the viewport, the model or the calibration changed. */
1087
+ private refreshScreenSizes;
798
1088
  /**
799
1089
  * Adds secondary interactive objects (e.g., POIs, sensors) to the scene.
800
1090
  */
@@ -802,13 +1092,43 @@ export declare class ThreeJsService {
802
1092
  private onMouseMove;
803
1093
  private onMouseClick;
804
1094
  /**
805
- * Escape cancels whatever the pointer is currently committed to.
1095
+ * Escape cancels whatever the pointer is currently committed to. While calibrating, the undo keys
1096
+ * take back one step of it instead of all of it.
806
1097
  *
807
1098
  * Emits through the same subjects the explicit Cancel buttons use, so the UI driving them follows
808
1099
  * along instead of being left showing a mode that is no longer armed.
809
1100
  */
810
1101
  private onKeyDown;
1102
+ /**
1103
+ * Ctrl+Z (Cmd+Z on a Mac) or Backspace, unless typed into a field - where they mean something
1104
+ * else, to whatever the field is.
1105
+ */
1106
+ private isUndoKey;
811
1107
  private animate;
1108
+ /**
1109
+ * Stops drawing the scene, or starts again. For while another viewer covers it - the splat viewer
1110
+ * - where it would otherwise go on drawing, unseen, every frame, on the graphics card the other
1111
+ * viewer needs. The scene keeps its tags and calibration all the same.
1112
+ */
1113
+ setRenderingPaused(paused: boolean): void;
1114
+ /** Stops the render loop, if one is running. */
1115
+ private stopRendering;
1116
+ /**
1117
+ * Takes the model out of the scene and frees what it holds on the graphics card.
1118
+ *
1119
+ * The tags are kept. They hang from the model's group so as to share its frame, and are moved out
1120
+ * of it first: they belong to the visit, not to the file that was drawn under them.
1121
+ */
1122
+ private removeModel;
1123
+ /**
1124
+ * Frees a model's geometry, materials and textures.
1125
+ *
1126
+ * Dropping the last reference to a model does not do this. What it uploaded stays on the graphics
1127
+ * card until the page is closed - hundreds of megabytes for a captured building - and on a
1128
+ * machine whose graphics memory is shared with the rest of the system, everything slows down
1129
+ * long before anything fails.
1130
+ */
1131
+ private disposeModel;
812
1132
  destroy(): void;
813
1133
  static ɵfac: i0.ɵɵFactoryDeclaration<ThreeJsService, never>;
814
1134
  static ɵprov: i0.ɵɵInjectableDeclaration<ThreeJsService>;
@@ -8,6 +8,24 @@ import { PoiService } from './models/poi.service';
8
8
  import { ThreeJsModelUp } from '../helpers.service';
9
9
  import { Config } from '../config';
10
10
  import * as i0 from "@angular/core";
11
+ /**
12
+ * What a Gaussian splat file is named with, when it is a .ply: the content is what tells it from
13
+ * another .ply, and the key is all a visit stores (see isGaussianSplatPly).
14
+ */
15
+ export declare const GAUSSIAN_SPLAT_PLY_SUFFIX = ".splat.ply";
16
+ /**
17
+ * Whether a 3D model file holds Gaussian splats, which the Three.js viewer cannot draw: .spz,
18
+ * .splat, .ksplat, SuperSplat's .sog, a .ply named with GAUSSIAN_SPLAT_PLY_SUFFIX, or the
19
+ * lod-meta.json of a Streamed SOG - SuperSplat's levels of detail, in pieces beside it.
20
+ */
21
+ export declare function isGaussianSplatFile(name: string): boolean;
22
+ /**
23
+ * Whether a .ply holds Gaussian splats: what splat tools export carries, for each splat, its colour
24
+ * as spherical harmonics (f_dc_0...) and its size (scale_0...). Only the header is read.
25
+ */
26
+ export declare function isGaussianSplatPly(file: Blob): Promise<boolean>;
27
+ /** Whether a 3D model file is the lod-meta.json of a Streamed SOG; see isGaussianSplatFile. */
28
+ export declare function isStreamedSplatFile(name: string): boolean;
11
29
  export declare class ViewerService {
12
30
  private readonly sdkKey;
13
31
  private readonly config;
@@ -155,6 +173,22 @@ export declare class ViewerService {
155
173
  private defaultTagIconUrl;
156
174
  /** Moves the Three.js camera to frame a tag, mirroring Matterport's goToTag. */
157
175
  goToThreeJsTag(elementId: string): void;
176
+ /** The tag the Three.js camera is sent to, for the splat viewer to point out; see goToThreeJsTag. */
177
+ get threeJsTagFocused$(): Subject<string>;
178
+ /** A tag clicked in the splat viewer, said as threeJsTagClicked$ says one clicked in the scene. */
179
+ clickThreeJsTag(elementId: string): void;
180
+ /** Whether the visit's 3D model has a calibration, from its capture's metadata. */
181
+ isThreeJsCalibrated(): boolean;
182
+ /** Whether the tags a calibration works with are on show; see ThreeJsService.showsCalibrationTags. */
183
+ isThreeJsShowingCalibrationTags(): boolean;
184
+ /** Whether a calibration is under way in the Three.js scene. */
185
+ isThreeJsAligningTags(): boolean;
186
+ /** Whether a measurement is taking clicks in the Three.js scene. */
187
+ isThreeJsMeasuring(): boolean;
188
+ /** True when a measurement starts taking clicks, false when it stops; see ThreeJsService.measuringChanged$. */
189
+ get threeJsMeasuringChanged$(): Subject<boolean>;
190
+ /** Says a click in the splat viewer was of no use to the calibration, as one in the scene would. */
191
+ ignoreThreeJsAlignmentClick(expected: 'tag' | 'point'): void;
158
192
  /** Shows only tags of the given POI types; null clears the filter. */
159
193
  setVisibleThreeJsTagTypes(types: PoiType[] | null): void;
160
194
  /**
@@ -165,11 +199,17 @@ export declare class ViewerService {
165
199
  */
166
200
  startThreeJsTagAlignment(): void;
167
201
  cancelThreeJsTagAlignment(): void;
168
- get threeJsAlignmentProgress$(): Subject<{
169
- pairs: number;
170
- awaiting: "tag" | "point";
171
- tagId?: string;
172
- }>;
202
+ /**
203
+ * Says whether the 3D model on screen is the site's only visit. Then there is nowhere else for a
204
+ * tag to have come from, and the tags that do not record where they were placed are its own.
205
+ */
206
+ setThreeJsSoleVisit(sole: boolean): void;
207
+ /**
208
+ * Shows the tags a calibration would work with, including those hidden for not landing on the
209
+ * model, before anything is armed. Cancelling or saving the calibration hides them again.
210
+ */
211
+ revealThreeJsCalibrationTags(): void;
212
+ get threeJsAlignmentProgress$(): Subject<import("./threejs.service").ThreeJsAlignmentProgress>;
173
213
  /**
174
214
  * Solves the alignment and applies it to the scene, returning it as the JSON to store in the
175
215
  * capture's metadata. Null means the three tags were collinear and nothing was applied.
@@ -224,8 +264,28 @@ export declare class ViewerService {
224
264
  points: number;
225
265
  distances: number[];
226
266
  }>;
227
- /** Ends the Three.js measurement in progress, or returns null when it has fewer than two points. */
228
- finishThreeJsMeasurement(): ThreeJsMeasurement | null;
267
+ /**
268
+ * Ends the Three.js measurement in progress, or returns null when it has fewer than two points.
269
+ * `screenshot` is the picture of it, when the model is drawn by another viewer than the scene.
270
+ */
271
+ finishThreeJsMeasurement(screenshot?: string): ThreeJsMeasurement | null;
272
+ /** A measurement was taken off the model, finished or not; see ThreeJsService.measurementCleared$. */
273
+ get threeJsMeasurementCleared$(): Subject<void>;
274
+ /**
275
+ * Adds a point to the measurement under way, picked on the model in another viewer - the splat
276
+ * viewer - in the model's own coordinates. False when no measurement is under way.
277
+ */
278
+ addThreeJsMeasurePointAtModelPoint(point: {
279
+ x: number;
280
+ y: number;
281
+ z: number;
282
+ }): boolean;
283
+ /** The points of the measurement on the model, in the model's own coordinates, for another viewer to draw. */
284
+ getThreeJsMeasurePointsInModelFrame(): {
285
+ x: number;
286
+ y: number;
287
+ z: number;
288
+ }[];
229
289
  /** The measurement last finished in the Three.js viewer, for the form that saves it. */
230
290
  getThreeJsLastMeasurement(): ThreeJsMeasurement | null;
231
291
  /**
@@ -259,6 +319,22 @@ export declare class ViewerService {
259
319
  } | null;
260
320
  /** Chooses the tag for the calibration pair being matched by id, instead of by clicking it. */
261
321
  selectThreeJsAlignmentTag(elementId: string): boolean;
322
+ /**
323
+ * Gives the tag being matched in the calibration under way its real place, picked on the model in
324
+ * another viewer - the splat viewer - in the model's own coordinates. False when no tag was waiting.
325
+ */
326
+ matchThreeJsAlignmentTagAtModelPoint(point: {
327
+ x: number;
328
+ y: number;
329
+ z: number;
330
+ }): boolean;
331
+ /**
332
+ * Takes back the last step of the calibration under way: the tag just chosen, or else the last
333
+ * pair matched. False when there was nothing to take back.
334
+ */
335
+ undoThreeJsAlignmentStep(): boolean;
336
+ /** Removes one matched pair of the calibration under way, by its place in the list. */
337
+ removeThreeJsAlignmentPair(index: number): boolean;
262
338
  /** How far the visible tags sit from the 3D model, in model radii. Null without both. */
263
339
  getThreeJsTagDistanceFromModel(): number | null;
264
340
  /** How many tags the Three.js scene is showing. */
@@ -281,11 +357,37 @@ export declare class ViewerService {
281
357
  *
282
358
  * Returns null when there is no pending placement, which is the normal case in Matterport mode.
283
359
  */
284
- createPoiForThreeJsPlacement(element: DbObjectType, poiType: PoiType): Promise<POI | null>;
360
+ createPoiForThreeJsPlacement(element: DbObjectType, poiType: PoiType, extra?: Partial<POI>): Promise<POI | null>;
285
361
  /** Emits when a tag is dropped on the model in the Three.js scene. */
286
362
  get threeJsTagPlaced$(): Subject<import("./threejs.service").ThreeJsTagPlacement>;
287
363
  /** Emits when the calibration walkthrough is abandoned, including via Escape. */
288
364
  get threeJsAlignmentCancelled$(): Subject<void>;
365
+ /** Emits when the Three.js tags change; see getThreeJsTagSnapshot. */
366
+ get threeJsTagsChanged$(): Subject<void>;
367
+ /** The tags, and their calibration, as a viewer drawing the scene elsewhere needs them. */
368
+ getThreeJsTagSnapshot(): {
369
+ tags: import("./threejs.service").ThreeJsTagSnapshot[];
370
+ alignment: import("../helpers.service").ThreeJsAlignment;
371
+ };
372
+ /** Stops drawing the Three.js scene while another viewer covers it, or starts again. */
373
+ setThreeJsRenderingPaused(paused: boolean): void;
374
+ /** Emits when a click during calibration landed on nothing it could use: a tag, or the model. */
375
+ get threeJsAlignmentClickIgnored$(): Subject<"tag" | "point">;
376
+ /** Emits when Three.js tag placement is armed (true) and when it ends (false). */
377
+ get threeJsPlacementChanged$(): Subject<boolean>;
378
+ /**
379
+ * Completes an armed Three.js tag placement at a spot the splat viewer picked, in the model's own
380
+ * coordinates: the creation form then opens as for a click in the Three.js scene.
381
+ */
382
+ placeThreeJsTagAtModelPoint(point: {
383
+ x: number;
384
+ y: number;
385
+ z: number;
386
+ }, normal?: {
387
+ x: number;
388
+ y: number;
389
+ z: number;
390
+ } | null): void;
289
391
  /** Leaves Three.js tag placement mode without placing anything. */
290
392
  cancelThreeJsTagPlacement(): void;
291
393
  editOnlyTagStyleForPoi(poi: POI, object: DbObjectType): void;