@smarterplan/ngx-smarterplan-core 1.4.16 → 1.4.18

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 (107) 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/support-modal/support-modal.component.mjs +3 -3
  10. package/esm2022/lib/config.mjs +1 -1
  11. package/esm2022/lib/helpers.service.mjs +1 -1
  12. package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasImage.mjs +1 -1
  13. package/esm2022/lib/matterport-extensions/nest-thermostat/CanvasRenderer.mjs +1 -1
  14. package/esm2022/lib/matterport-extensions/nest-thermostat/NestThermostat.mjs +1 -1
  15. package/esm2022/lib/matterport-extensions/nest-thermostat/PlaneRenderer.mjs +1 -1
  16. package/esm2022/lib/matterport-extensions/scene-component/SceneComponent.mjs +1 -1
  17. package/esm2022/lib/matterport-extensions/security-camera/SecurityCamera.mjs +22 -22
  18. package/esm2022/lib/matterport-extensions/tv-player/TvPlayer.mjs +1 -1
  19. package/esm2022/lib/matterport-extensions/view-frustum-mesh/ViewFrustumMesh.mjs +22 -22
  20. package/esm2022/lib/mattertagData.mjs +10 -1
  21. package/esm2022/lib/ngx-smarterplan-core.module.mjs +1 -1
  22. package/esm2022/lib/ngx-smarterplan-core.service.mjs +1 -1
  23. package/esm2022/lib/pipes/duration-to-string.pipe.mjs +1 -1
  24. package/esm2022/lib/pipes/format-date-number-to-digits.pipe.mjs +1 -1
  25. package/esm2022/lib/pipes/hashtag-from-id.pipe.mjs +1 -1
  26. package/esm2022/lib/pipes/safe-url.pipe.mjs +1 -1
  27. package/esm2022/lib/pipes/time-date-to-local-string.pipe.mjs +1 -1
  28. package/esm2022/lib/pipes/username-from-id.pipe.mjs +1 -1
  29. package/esm2022/lib/services/amplify-cache.service.mjs +1 -1
  30. package/esm2022/lib/services/base-tab.service.mjs +1 -1
  31. package/esm2022/lib/services/baseVisibility.service.mjs +1 -1
  32. package/esm2022/lib/services/content.service.mjs +1 -1
  33. package/esm2022/lib/services/filter.service.mjs +11 -1
  34. package/esm2022/lib/services/intervention.service.mjs +1 -1
  35. package/esm2022/lib/services/locale.service.mjs +1 -1
  36. package/esm2022/lib/services/matterport-import.service.mjs +10 -3
  37. package/esm2022/lib/services/matterport-measurement.service.mjs +1 -1
  38. package/esm2022/lib/services/matterport-navigation.service.mjs +1 -1
  39. package/esm2022/lib/services/matterport-object3d.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 +455 -9
  42. package/esm2022/lib/services/matterport-tag.service.mjs +99 -10
  43. package/esm2022/lib/services/matterport.service.mjs +95 -49
  44. package/esm2022/lib/services/models/affectation.service.mjs +1 -1
  45. package/esm2022/lib/services/models/base-object.service.mjs +31 -4
  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 +14 -13
  50. package/esm2022/lib/services/models/event.service.mjs +1 -1
  51. package/esm2022/lib/services/models/feature.service.mjs +8 -7
  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 +62 -50
  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 +25 -2
  66. package/esm2022/lib/services/models/template.service.mjs +1 -1
  67. package/esm2022/lib/services/models/ticket.service.mjs +27 -8
  68. package/esm2022/lib/services/models/visit.service.mjs +1 -1
  69. package/esm2022/lib/services/models/zone.service.mjs +9 -5
  70. package/esm2022/lib/services/navigator.service.mjs +14 -1
  71. package/esm2022/lib/services/s3.service.mjs +1 -1
  72. package/esm2022/lib/services/search.service.mjs +1 -1
  73. package/esm2022/lib/services/support.service.mjs +1 -1
  74. package/esm2022/lib/services/tag.service.mjs +16 -16
  75. package/esm2022/lib/services/threejs-import.service.mjs +1 -1
  76. package/esm2022/lib/services/threejs.service.mjs +316 -35
  77. package/esm2022/lib/services/user.service.mjs +1 -1
  78. package/esm2022/lib/services/utils/matterport-transform.util.mjs +1 -1
  79. package/esm2022/lib/services/validators.service.mjs +1 -1
  80. package/esm2022/lib/services/viewer.service.mjs +147 -8
  81. package/esm2022/lib/services/zone-drawer.service.mjs +1 -1
  82. package/esm2022/lib/services/zoneChange.service.mjs +10 -1
  83. package/esm2022/lib/tokens/matterport-sdk-key.token.mjs +1 -1
  84. package/esm2022/lib/types.service.mjs +1 -1
  85. package/esm2022/lib/validators/email.directive.mjs +1 -1
  86. package/esm2022/lib/validators/no-empty.directive.mjs +1 -1
  87. package/esm2022/lib/validators/number.directive.mjs +1 -1
  88. package/esm2022/lib/validators/text.directive.mjs +1 -1
  89. package/esm2022/public-api.mjs +1 -1
  90. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +5150 -4022
  91. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
  92. package/lib/mattertagData.d.ts +4 -0
  93. package/lib/services/matterport-tag-copy.service.d.ts +128 -2
  94. package/lib/services/matterport-tag.service.d.ts +24 -1
  95. package/lib/services/matterport.service.d.ts +12 -3
  96. package/lib/services/models/base-object.service.d.ts +11 -1
  97. package/lib/services/models/equipment.service.d.ts +2 -1
  98. package/lib/services/models/feature.service.d.ts +2 -1
  99. package/lib/services/models/poi.service.d.ts +1 -0
  100. package/lib/services/models/space.service.d.ts +7 -0
  101. package/lib/services/models/ticket.service.d.ts +4 -1
  102. package/lib/services/threejs.service.d.ts +103 -5
  103. package/lib/services/viewer.service.d.ts +39 -1
  104. package/lib/services/zoneChange.service.d.ts +9 -0
  105. package/lib/types.service.d.ts +8 -0
  106. package/package.json +1 -1
  107. package/src/assets/vs-app.json +67 -67
@@ -52,6 +52,10 @@ export declare class MattertagData {
52
52
  b: number;
53
53
  };
54
54
  };
55
+ /**
56
+ * Safely retrieves the display name depending on object properties (name, title)
57
+ */
58
+ getDisplayName(): string;
55
59
  /**
56
60
  * Get the descriptor for sdk.Tag.add(...descriptor)
57
61
  * Format : [{ label, description, anchorPosition, stemVector, color, id? }]
@@ -1,5 +1,6 @@
1
1
  import { BehaviorSubject } from 'rxjs';
2
2
  import { TranslateService } from '@ngx-translate/core';
3
+ import { POI } from '../types.service';
3
4
  import { NavigationService } from './models/navigation.service';
4
5
  import { PoiService } from './models/poi.service';
5
6
  import { TicketsService } from './models/ticket.service';
@@ -12,12 +13,13 @@ import { HashtagService } from './models/hashtag.service';
12
13
  import { MissionService } from './models/mission.service';
13
14
  import { OperationService } from './models/operation.service';
14
15
  import { DomainService } from './models/domain.service';
16
+ import { ZoneService } from './models/zone.service';
15
17
  import { BaseUserService } from './user.service';
16
18
  import { Vec3 } from './utils/matterport-transform.util';
17
19
  import * as i0 from "@angular/core";
18
20
  /** Progress snapshot emitted during copyTagsFromVisit(), so the UI can show a live status. */
19
21
  export interface CopyProgress {
20
- phase: 'collecting' | 'tickets' | 'equipments' | 'pois' | 'objects3d' | 'features' | 'measurements' | 'done';
22
+ phase: 'collecting' | 'tickets' | 'equipments' | 'pois' | 'objects3d' | 'features' | 'measurements' | 'recalibrating' | 'done';
21
23
  processedInPhase: number;
22
24
  totalInPhase: number;
23
25
  processedOverall: number;
@@ -36,6 +38,44 @@ export interface CopyLogEntry {
36
38
  type: 'step' | 'error' | 'healed';
37
39
  text: string;
38
40
  }
41
+ /** A tag listed for recalibration, with what the UI needs to identify it. */
42
+ export type RecalibrationTag = POI & {
43
+ elementName: string;
44
+ elementDescription?: string;
45
+ /** pass to getTagImageUrl() to get a displayable (signed) URL */
46
+ elementImageKey?: string;
47
+ /** floor zone (layer FLOOR) of the tag's sweep in the target space */
48
+ floorName?: string;
49
+ /** most specific other zone of the tag's sweep in the target space */
50
+ zoneName?: string;
51
+ };
52
+ /**
53
+ * Which tags of a space (location) a recalibration lists. A tag belongs to a location (the
54
+ * space of the element it points at; a standalone tag belongs to every location showing it)
55
+ * and is displayed in one or several virtual visits of that location. Tags of another
56
+ * location are never listed, even when both locations use the same visit.
57
+ * - SPACE: every tag of the location, whichever of its visits it sits in;
58
+ * - VISIT: the tags of the location placed on the sweeps of the selected visit.
59
+ */
60
+ export type RecalibrationTagScope = 'SPACE' | 'VISIT';
61
+ /** Both lists getRecalibrationTagSets() offers, see there. */
62
+ export interface RecalibrationTagSets {
63
+ space: RecalibrationTag[];
64
+ visit: RecalibrationTag[];
65
+ }
66
+ export interface RecalibrationTagOptions {
67
+ /** Node of the selected target visit (visit.node.id): drives the VISIT list. */
68
+ targetNodeId?: string | null;
69
+ /** Only keep the tags that also exist in the source location (ignored when source = target). */
70
+ onlyTagsInSource?: boolean;
71
+ }
72
+ /** Outcome of recalibrateTagsFromVisit(): how many of the selected tags were moved. */
73
+ export interface RecalibrationResult {
74
+ updated: number;
75
+ /** selected tags not found anymore, or without a position to move */
76
+ skipped: number;
77
+ failed: number;
78
+ }
39
79
  export declare class MatterportTagCopyService {
40
80
  private navigationService;
41
81
  private userService;
@@ -51,6 +91,7 @@ export declare class MatterportTagCopyService {
51
91
  private operationService;
52
92
  private domainService;
53
93
  private translate;
94
+ private zoneService;
54
95
  copyProgress$: BehaviorSubject<CopyProgress | null>;
55
96
  copyLog$: BehaviorSubject<CopyLogEntry[]>;
56
97
  private spModule;
@@ -91,7 +132,7 @@ export declare class MatterportTagCopyService {
91
132
  private targetDomainIdsByTypeAndName;
92
133
  /** Target space id of the run in progress — used to re-home copied tag icons. */
93
134
  private targetSpaceId;
94
- constructor(navigationService: NavigationService, userService: BaseUserService, poiService: PoiService, ticketService: TicketsService, equipmentService: EquipmentService, object3DService: Object3DService, featureService: FeatureService, measurementService: MeasurementService, commentService: CommentService, hashtagService: HashtagService, missionService: MissionService, operationService: OperationService, domainService: DomainService, translate: TranslateService);
135
+ constructor(navigationService: NavigationService, userService: BaseUserService, poiService: PoiService, ticketService: TicketsService, equipmentService: EquipmentService, object3DService: Object3DService, featureService: FeatureService, measurementService: MeasurementService, commentService: CommentService, hashtagService: HashtagService, missionService: MissionService, operationService: OperationService, domainService: DomainService, translate: TranslateService, zoneService: ZoneService);
95
136
  copyTagsFromVisit(sourceSpaceId: string, targetSpaceId: string, landmarkSourceA: Vec3, landmarkTargetA: Vec3, landmarkSourceB: Vec3, landmarkTargetB: Vec3): Promise<boolean>;
96
137
  /**
97
138
  * Serialises the current copy log (step lines as last emitted, plus every error and
@@ -362,6 +403,13 @@ export declare class MatterportTagCopyService {
362
403
  private buildNavigationPositionMap;
363
404
  /** Applies the rigid transform to a POI coordinate (position + orientation). */
364
405
  private getAdjustedCoordinates;
406
+ /**
407
+ * Reads a stored coordinate (JSON string or object, whatever its spacing) as a position.
408
+ * Null for a virtual POI or an unreadable value.
409
+ */
410
+ private parseCoordinate;
411
+ /** Two positions within 1 cm are the same (two virtual POIs, both null, are too). */
412
+ private isSamePosition;
365
413
  /**
366
414
  * Applies the rigid transform's translation+rotation to a plain {x,y,z} position,
367
415
  * WITHOUT adding xRotation/yRotation keys. Used for measurements, whose stored
@@ -425,6 +473,84 @@ export declare class MatterportTagCopyService {
425
473
  * existed on S3, resulting in a NoSuchKey error.
426
474
  */
427
475
  private extractS3KeyFromValue;
476
+ /**
477
+ * Both tag lists a recalibration can offer for a target space, computed in one pass. Only
478
+ * the target location's own tags are ever listed (see RecalibrationTagScope); tags whose
479
+ * element was deleted — orphan POIs — never are.
480
+ * - `space`: every tag of the location, in any of its visits;
481
+ * - `visit`: the tags of the location sitting on the sweeps of the selected target visit
482
+ * (`options.targetNodeId`); empty when no visit is given.
483
+ * With `options.onlyTagsInSource` and a source other than the target, both lists only keep
484
+ * the tags that also exist in the source location (same identity as the copy's duplicate
485
+ * detection): typically the tags an earlier copy brought over.
486
+ *
487
+ * A POI carries no name of its own: each tag gets `elementName`, the name of the element
488
+ * it points at (ticket title, equipment name, ...).
489
+ */
490
+ getRecalibrationTagSets(sourceSpaceId: string, targetSpaceId: string, options?: RecalibrationTagOptions): Promise<RecalibrationTagSets>;
491
+ /**
492
+ * Signed, displayable URL of a tag's picture (`elementImageKey`). Meant to be called on
493
+ * demand — when the tag is previewed — rather than for the whole list.
494
+ */
495
+ getTagImageUrl(imageKey: string): Promise<string | null>;
496
+ /**
497
+ * Loads the POIs placed on the sweeps of a space whose element still exists, each with a
498
+ * display name, an identity key and whether its element belongs to that space. The key
499
+ * follows the same rules as the copy's duplicate detection (findExisting), so a tag and its
500
+ * copy in another space share the same key. With a visit node, `inVisit` tells whether the
501
+ * tag sits on one of that visit's sweeps.
502
+ */
503
+ private loadLiveTagsForSpace;
504
+ /**
505
+ * Sweeps of a virtual visit (a Node): those of the space's zones attached to that node,
506
+ * else — zones not filled in for this visit — the sweeps of the node's navigations.
507
+ */
508
+ private getSweepsOfVisit;
509
+ /**
510
+ * Maps each sweep of a space to the names of its floor (zone of layer FLOOR) and of its
511
+ * most specific other zone (the one holding the fewest sweeps, typically a room, else the
512
+ * visit's BUILDING zone).
513
+ */
514
+ private getSweepZones;
515
+ /**
516
+ * Indexes, by ID, every element of a space a POI can point at. Each list is fetched
517
+ * independently: one failing (module not enabled, missing permission) must not hide the
518
+ * others — their POIs are then resolved one by one by fetchTagElementsById().
519
+ */
520
+ private getTagElementsForSpace;
521
+ /**
522
+ * Fetches by ID the elements the space-wide lists did not return. The IDs are packed into
523
+ * a few GraphQL requests using aliases (`e0: getTicket(id: ...) e1: getEquipment(...)`),
524
+ * instead of one request per element: a space can hold over a thousand orphan POIs.
525
+ * An element that no longer exists comes back as null and is simply not indexed.
526
+ */
527
+ private fetchTagElementsById;
528
+ /**
529
+ * Moves a stored coordinate. Only the position and the horizontal orientation change:
530
+ * every other key is kept as is. A coordinate often carries the tag's orientation next to
531
+ * its position ({x, y, z, xRotation, yRotation}); rebuilding it from the position alone
532
+ * silently erased that orientation.
533
+ */
534
+ private getRecalibratedCoordinate;
535
+ /**
536
+ * Reads POIs by ID, 100 per GraphQL request (aliases). Missing POIs are skipped. Amplify
537
+ * rejects a request when ANY alias errors, but still hands over the data of the others:
538
+ * those are kept, so one unreadable POI does not hide the 99 others of its batch.
539
+ */
540
+ private fetchPoisById;
541
+ private tagElementTypeOf;
542
+ /** Display name + identity fields of an element, per the copy's duplicate-detection rules. */
543
+ private toTagElement;
544
+ private stripHtml;
545
+ /**
546
+ * Recalibrates a specific list of existing tags in the target space by applying the rigid
547
+ * transformation calculated from the selected landmark points.
548
+ *
549
+ * Each tag is updated on its own: a failing update is logged and counted, it no longer
550
+ * stops the remaining tags. Progress and log go through copyProgress$ / copyLog$, like a
551
+ * copy (phase 'recalibrating'). `tagLabels` (tag id -> name) only makes the log readable.
552
+ */
553
+ recalibrateTagsFromVisit(targetSpaceId: string, selectedTagIds: string[], landmarkSourceA: Vec3, landmarkTargetA: Vec3, landmarkSourceB: Vec3, landmarkTargetB: Vec3, tagLabels?: Record<string, string>): Promise<RecalibrationResult>;
428
554
  static ɵfac: i0.ɵɵFactoryDeclaration<MatterportTagCopyService, never>;
429
555
  static ɵprov: i0.ɵɵInjectableDeclaration<MatterportTagCopyService>;
430
556
  }
@@ -18,6 +18,13 @@ export declare class MatterportTagService {
18
18
  tagService: BaseTagService | null;
19
19
  private tagsCurrentOpacity;
20
20
  private tagsCurrentEnabled;
21
+ /** tagId -> icon name last applied, so an unchanged icon is not re-applied. */
22
+ private tagsCurrentIcon;
23
+ /** Ids of the global SDK Tag collection, and the tags waiting to appear in it, see waitForTagInSdk(). */
24
+ private sdkTagIds;
25
+ private sdkTagWaiters;
26
+ private sdkTagSubscription;
27
+ private sdkTagSubscriptionSdk;
21
28
  /**
22
29
  * Single layer holding every Smarterplan tag, added to every view of the space so a
23
30
  * tag stays in place — same sid, same content — when the user switches between the
@@ -45,9 +52,25 @@ export declare class MatterportTagService {
45
52
  * A layer-scoped Tag module only exposes the *replayable* mutations, meant to build
46
53
  * the layer's own content; applying them to an already-created tag silently does
47
54
  * nothing — which is what left every pin white instead of carrying its icon. Only
48
- * `add` has to go through the layer, see getTagCreationModule().
55
+ * `add` has to go through the layer, see getTagCreationModule(). The global module
56
+ * only knows a layer-created pin once it is rendered: see waitForTagInSdk().
49
57
  */
50
58
  getTagModule(sdk: any, tagId: string): any;
59
+ /** Icon name last applied to a tag, if any. */
60
+ getCachedTagIcon(tagId: string): string | undefined;
61
+ /** Applies an icon to a tag through its own module and remembers it on success. */
62
+ editTagIcon(sdk: any, tagId: string, iconName: string): Promise<void>;
63
+ /**
64
+ * Resolves once the global SDK Tag collection — the one edits go through — contains the
65
+ * tag, so edits do not hit a pin that is not rendered yet ("setPinRenderOverrides on a pin
66
+ * that doesn't exist"). Gives up after `timeoutMs` and resolves anyway; falls back to a
67
+ * short wait when the collection cannot be observed. One subscription is shared by every
68
+ * waiting tag: a space loads hundreds of them.
69
+ */
70
+ private waitForTagInSdk;
71
+ /** Keeps sdkTagIds in sync with the global SDK Tag collection; false when it cannot be observed. */
72
+ private observeSdkTags;
73
+ private stopObservingSdkTags;
51
74
  /**
52
75
  * Returns the Tag module every new tag must be created through: the shared layer
53
76
  * when the View API is available, the global sdk.Tag otherwise.
@@ -106,6 +106,12 @@ export declare class MatterportService {
106
106
  }>;
107
107
  /** Views (furnished, defurnished...) exposed by the SDK for the current space. */
108
108
  private viewsByType;
109
+ /** Settles once every static icon texture has been registered (or failed). */
110
+ private iconsRegistered;
111
+ /** Names of the textures successfully registered in the current SDK session. */
112
+ private registeredIcons;
113
+ /** tagId -> signed source last registered as a custom texture, and its texture name. */
114
+ private customIconCache;
109
115
  private currentView;
110
116
  private viewSubscriptions;
111
117
  /** Emits the active view every time the user switches between furnished/defurnished. */
@@ -193,11 +199,14 @@ export declare class MatterportService {
193
199
  addNewIconAndSetForTag(mattertagID: string, iconPath: string): Promise<void>;
194
200
  /** Applies a pre-registered icon to a Mattertag. */
195
201
  setRegistredIconForTag(mattertagID: string, iconName: string): Promise<void>;
196
- /** Sets the appropriate icon and opacity for a tag based on its type and POI metadata. */
202
+ /** Registers a static texture and remembers its name once the SDK accepted it. */
203
+ private registerIcon;
204
+ /** Sets the appropriate icon for a tag based on its type and POI metadata. */
197
205
  setTagIconAndOpacity(mattertagID: string, mattertagData: MattertagData): Promise<void>;
198
206
  /**
199
- * Applies an icon to a tag. The call is awaited and its rejection reported: a
200
- * silently dropped promise here leaves the pin with its default white look.
207
+ * Applies an icon to a tag, unless that icon is already the one applied. The call is
208
+ * awaited and its rejection reported: a silently dropped promise here leaves the pin
209
+ * with its default white look.
201
210
  */
202
211
  private editTagIcon;
203
212
  /** Navigates the camera to the most recently created tag. */
@@ -1,11 +1,13 @@
1
1
  import { Equipment, Feature, POI, Ticket } from "../../types.service";
2
2
  import { NavigationService } from "./navigation.service";
3
3
  import { PoiService } from "./poi.service";
4
+ import { VisitService } from "./visit.service";
4
5
  import * as i0 from "@angular/core";
5
6
  export declare class BaseObjectService {
6
7
  protected poiService: PoiService;
7
8
  private navigationService;
8
- constructor(poiService: PoiService, navigationService: NavigationService);
9
+ private visitService;
10
+ constructor(poiService: PoiService, navigationService: NavigationService, visitService: VisitService);
9
11
  getModel3dAndSweep(object: Feature | Ticket | Equipment): Promise<{
10
12
  model3D: string;
11
13
  sweep: string;
@@ -14,6 +16,14 @@ export declare class BaseObjectService {
14
16
  y: number;
15
17
  };
16
18
  } | void>;
19
+ /**
20
+ * The space's 3D visit, or null when it has none.
21
+ *
22
+ * Takes the first one the database returns. That is not the space's chosen default - the
23
+ * default ordering lives in SpaceService, which cannot be injected here. The POI does not record
24
+ * which capture it was placed in, so with several 3D models this is a guess either way.
25
+ */
26
+ private getThreeJsVisitForSpace;
17
27
  updateIconForAllObjects(objects: Ticket[] | Feature[] | Equipment[], tagIcon: string): Promise<POI[]>;
18
28
  static ɵfac: i0.ɵɵFactoryDeclaration<BaseObjectService, never>;
19
29
  static ɵprov: i0.ɵɵInjectableDeclaration<BaseObjectService>;
@@ -10,6 +10,7 @@ import { BaseObjectService } from './base-object.service';
10
10
  import { NavigationService } from './navigation.service';
11
11
  import { OperationService } from './operation.service';
12
12
  import { PoiService } from './poi.service';
13
+ import { VisitService } from './visit.service';
13
14
  import { TicketsService } from './ticket.service';
14
15
  import { ZoneChangeService } from "../zoneChange.service";
15
16
  import * as i0 from "@angular/core";
@@ -49,7 +50,7 @@ export declare class EquipmentService extends BaseObjectService {
49
50
  awsKinesisAnalytics: any;
50
51
  isMuseumUser: boolean;
51
52
  private destroy$;
52
- constructor(apiInjected: any, awsKinesisAnalyticsInjected: any, poiService: PoiService, navigationService: NavigationService, operationService: OperationService, ticketsService: TicketsService, navigatorService: NavigatorService, filterService: FilterService, userService: BaseUserService, viewerService: ViewerService, modalService: NgbModal, zoneChangeService: ZoneChangeService);
53
+ constructor(apiInjected: any, awsKinesisAnalyticsInjected: any, poiService: PoiService, navigationService: NavigationService, visitService: VisitService, operationService: OperationService, ticketsService: TicketsService, navigatorService: NavigatorService, filterService: FilterService, userService: BaseUserService, viewerService: ViewerService, modalService: NgbModal, zoneChangeService: ZoneChangeService);
53
54
  readEquipment(id: string): Promise<Equipment>;
54
55
  createEquipment(equip: Equipment, imageFile: File, documentFile: File): Promise<Equipment | void>;
55
56
  getSignedUrlsForEquipment(equip: Equipment): Promise<Equipment>;
@@ -9,6 +9,7 @@ import { CommentService } from "./comment.service";
9
9
  import { HashtagService } from "./hashtag.service";
10
10
  import { NavigationService } from "./navigation.service";
11
11
  import { PoiService } from "./poi.service";
12
+ import { VisitService } from "./visit.service";
12
13
  import { ZoneChangeService } from "../zoneChange.service";
13
14
  import * as i0 from "@angular/core";
14
15
  export declare class FeatureService extends BaseObjectService {
@@ -40,7 +41,7 @@ export declare class FeatureService extends BaseObjectService {
40
41
  currentHashtags: Hashtag[];
41
42
  createObservable: Subject<Feature>;
42
43
  deleteObservable: Subject<Feature>;
43
- constructor(apiInjected: any, navigatorService: NavigatorService, filterService: FilterService, poiService: PoiService, commentService: CommentService, userService: BaseUserService, navigationService: NavigationService, hashtagService: HashtagService, zoneChangeService: ZoneChangeService);
44
+ constructor(apiInjected: any, navigatorService: NavigatorService, filterService: FilterService, poiService: PoiService, commentService: CommentService, userService: BaseUserService, navigationService: NavigationService, visitService: VisitService, hashtagService: HashtagService, zoneChangeService: ZoneChangeService);
44
45
  createFeature(feature: Feature): Promise<Feature>;
45
46
  deleteFeature(feature: Feature): Promise<Feature>;
46
47
  updateFeature(feature: any): Promise<Feature>;
@@ -33,6 +33,7 @@ export declare class PoiService {
33
33
  * splitting keeps each request well within safe limits regardless of space size.
34
34
  */
35
35
  getPoisByMatterportSweeps(sweeps: string[]): Promise<POI[]>;
36
+ private scanPoisForSweepChunk;
36
37
  unsubscribe(): void;
37
38
  static ɵfac: i0.ɵɵFactoryDeclaration<PoiService, never>;
38
39
  static ɵprov: i0.ɵɵInjectableDeclaration<PoiService>;
@@ -47,6 +47,13 @@ export declare class SpaceService {
47
47
  * viewer offers them as a list, so the caller needs all of them rather than just the first.
48
48
  */
49
49
  getAllowedVisitsForSpace(spaceID: string): Promise<Visit[]>;
50
+ /**
51
+ * Sets which capture a visitor opens by default for this space.
52
+ *
53
+ * Pass null to clear it. Writing a single field on the space is what keeps the answer unique:
54
+ * there is nothing to clear elsewhere, and no way for two captures to both claim it.
55
+ */
56
+ setDefaultCapture(spaceID: string, captureID: string | null): Promise<Space>;
50
57
  getAllowedModel3DForSpace(spaceID: string): Promise<string>;
51
58
  softDeleteSpace(spaceID: string): Promise<void>;
52
59
  /**
@@ -10,6 +10,7 @@ import { BaseObjectService } from './base-object.service';
10
10
  import { NavigationService } from './navigation.service';
11
11
  import { OperationService } from './operation.service';
12
12
  import { PoiService } from './poi.service';
13
+ import { VisitService } from './visit.service';
13
14
  import { EventService } from './event.service';
14
15
  import { InterventionService } from '../intervention.service';
15
16
  import { AffectationService } from './affectation.service';
@@ -38,6 +39,8 @@ export declare class TicketsService extends BaseObjectService {
38
39
  }>;
39
40
  currentSpaceID: string;
40
41
  zoneIDFilter: string;
42
+ /** Set while a viewer without zone navigation (Three.js) is showing a space. */
43
+ private spaceSubscription;
41
44
  dateFilter: Date[];
42
45
  ticketTypeFilter: TicketType[];
43
46
  reportingIcon: import("@iconify/types").IconifyIcon;
@@ -55,7 +58,7 @@ export declare class TicketsService extends BaseObjectService {
55
58
  floorsPerSpace: Zone[];
56
59
  selectedFloor: Zone;
57
60
  private destroy$;
58
- constructor(awsKinesisAnalyticsInjected: any, apiInjected: any, operationService: OperationService, eventService: EventService, affectationService: AffectationService, poiService: PoiService, userService: BaseUserService, navigatorService: NavigatorService, filterService: FilterService, interventionService: InterventionService, navigationService: NavigationService, viewerService: ViewerService, zoneChangeService: ZoneChangeService, modalService: NgbModal);
61
+ constructor(awsKinesisAnalyticsInjected: any, apiInjected: any, operationService: OperationService, eventService: EventService, affectationService: AffectationService, poiService: PoiService, userService: BaseUserService, navigatorService: NavigatorService, filterService: FilterService, interventionService: InterventionService, navigationService: NavigationService, visitService: VisitService, viewerService: ViewerService, zoneChangeService: ZoneChangeService, modalService: NgbModal);
59
62
  initTickets(): Promise<void>;
60
63
  adaptTicket(ticket: Ticket): Promise<Ticket>;
61
64
  getPriorityColor(ticket: Ticket): string;
@@ -20,6 +20,8 @@ export interface ThreeJsTag {
20
20
  };
21
21
  /** Drives both the click route and type filtering, so it travels with the tag. */
22
22
  poiType?: PoiType | null;
23
+ /** Shown on hover. A marker with no identity is just a dot on a wall. */
24
+ label?: string | null;
23
25
  /** Icon drawn on the tag. Falls back to a plain disc when absent or it fails to load. */
24
26
  iconUrl?: string | null;
25
27
  /** Tint for the fallback disc, as a CSS colour. */
@@ -49,6 +51,8 @@ export interface ThreeJsTagPlacement {
49
51
  y: number;
50
52
  z: number;
51
53
  };
54
+ /** What the placement was armed for, so the caller knows which creation form to open. */
55
+ poiType?: PoiType | null;
52
56
  }
53
57
  /** One tag seen in both spaces: where it is stored, and where it really sits on the model. */
54
58
  export interface ThreeJsAlignmentPair {
@@ -114,6 +118,11 @@ export declare class ThreeJsService {
114
118
  objectClicked$: Subject<string>;
115
119
  /** Emits when the user clicks a tag, mirroring Matterport's tag click. */
116
120
  tagClicked$: Subject<ThreeJsTagClick>;
121
+ /** Emits a tag's label while the pointer is over it, and null when it leaves. */
122
+ tagHovered$: Subject<{
123
+ label: string;
124
+ event: MouseEvent;
125
+ }>;
117
126
  private tagGroup;
118
127
  private tagSprites;
119
128
  private canvasResizeObserver?;
@@ -122,10 +131,30 @@ export declare class ThreeJsService {
122
131
  private modelRoot?;
123
132
  /** True while the next click on the model places a tag instead of orbiting. */
124
133
  private placingTag;
134
+ /** What the armed placement is for, echoed back when the spot is picked. */
135
+ private placementPoiType;
125
136
  /** Position and normal of the last placed tag, in model space, awaiting commit to a POI. */
126
137
  private pendingTagPlacement;
138
+ /** Pointer position waiting for a preview pick, coalesced to one per frame. */
139
+ private pendingPreviewEvent;
140
+ /**
141
+ * Layer carrying the model alone, so the depth pick can render it without the tags.
142
+ *
143
+ * Layers are tested per object at render time and children are traversed regardless of whether
144
+ * their parent passed, so marking the model's own meshes is enough - no re-parenting.
145
+ */
146
+ private static readonly PICK_LAYER;
147
+ /** Cache Storage bucket holding downloaded models, and how many to keep. */
148
+ private static readonly MODEL_CACHE;
149
+ private static readonly MODEL_CACHE_SIZE;
150
+ private pickTarget?;
151
+ private pickCamera?;
152
+ private pickDepthMaterial?;
153
+ private readonly pickPixel;
127
154
  /** Emits once a tag is dropped on the model, so the UI can confirm and persist it. */
128
155
  tagPlaced$: Subject<ThreeJsTagPlacement>;
156
+ /** Emits when the calibration walkthrough is abandoned, so the panel driving it can close. */
157
+ alignmentCancelled$: Subject<void>;
129
158
  /** Translucent marker shown under the cursor while placing. */
130
159
  private placementPreview?;
131
160
  private aligning;
@@ -191,7 +220,7 @@ export declare class ThreeJsService {
191
220
  x: number;
192
221
  y: number;
193
222
  z: number;
194
- }): void;
223
+ }, cacheKey?: string): void;
195
224
  /**
196
225
  * Stops the model download in progress, if any.
197
226
  *
@@ -225,6 +254,25 @@ export declare class ThreeJsService {
225
254
  * stream reports it as it happens rather than in one jump at the end.
226
255
  */
227
256
  private fetchWithProgress;
257
+ /**
258
+ * The model store, or null where the browser will not give us one.
259
+ *
260
+ * Cache Storage needs a secure context, so it is absent over plain http and in some embedded
261
+ * webviews. Every caller treats that as a miss - caching is an optimisation, never a requirement.
262
+ */
263
+ private openModelCache;
264
+ /**
265
+ * A cached copy of this model, if one was stored.
266
+ *
267
+ * Keyed by the S3 key rather than the URL it is fetched from: that URL is signed, so it carries a
268
+ * fresh signature and expiry every time and would never match twice. The browser's own HTTP cache
269
+ * misses for the same reason, which is why this exists at all.
270
+ */
271
+ private readModelFromCache;
272
+ /** Stores a model for next time, evicting the oldest once a few are held. */
273
+ private writeModelToCache;
274
+ /** Cache Storage keys on a URL, so the S3 key is expressed as one. It is never requested. */
275
+ private modelCacheUrl;
228
276
  /**
229
277
  * Fits the camera's clipping planes to how big the model actually is.
230
278
  *
@@ -326,6 +374,16 @@ export declare class ThreeJsService {
326
374
  startTagAlignment(): void;
327
375
  cancelTagAlignment(): void;
328
376
  isAligningTags(): boolean;
377
+ /**
378
+ * Whether the pointer should be showing the placement ghost.
379
+ *
380
+ * True while placing a tag, and while calibrating once a tag has been picked - that second click
381
+ * is the same question ("where on the model?") and deserves the same aiming aid. Not true for the
382
+ * first half of a pair, which is a click on a tag, not on the model.
383
+ */
384
+ private isPreviewingPlacement;
385
+ /** Whether a tag is currently registered for this element. */
386
+ hasTag(elementId: string): boolean;
329
387
  /**
330
388
  * Solves and applies the alignment collected so far, returning it so the caller can persist it.
331
389
  *
@@ -336,7 +394,7 @@ export declare class ThreeJsService {
336
394
  /** Handles a click while the alignment walkthrough is running. */
337
395
  private handleAlignmentClick;
338
396
  /** Arms tag placement: the next click on the model drops a tag instead of being ignored. */
339
- startTagPlacement(): void;
397
+ startTagPlacement(poiType?: PoiType | null): void;
340
398
  /** Leaves placement mode without placing anything. */
341
399
  cancelTagPlacement(): void;
342
400
  /**
@@ -346,6 +404,21 @@ export declare class ThreeJsService {
346
404
  * sprite that gets removed the moment the real tag takes its place.
347
405
  */
348
406
  private updatePlacementPreview;
407
+ /**
408
+ * The point under the cursor, read from the depth buffer instead of raycast, in tag space.
409
+ *
410
+ * A raycast walks every triangle of the mesh it hits: on a captured model that is millions of
411
+ * them, tens of milliseconds, every time the pointer moves. Coalescing to one per frame did not
412
+ * help, because the cost is the pick itself - it simply became one slow frame instead of several.
413
+ *
414
+ * Rendering the model's depth into a single pixel under the cursor answers the same question on
415
+ * the GPU in constant time, whatever the model's size. The camera's view offset is what narrows
416
+ * the whole image down to that one pixel, so the value read back is the depth the cursor is over.
417
+ *
418
+ * Used for the ghost only. The click that actually places a tag still raycasts: it is one pick,
419
+ * its cost does not matter, and it yields the surface normal, which depth alone cannot give.
420
+ */
421
+ private pickPointOnGpu;
349
422
  private removePlacementPreview;
350
423
  /** Shows or hides one tag, leaving it registered so it can be brought back without reloading. */
351
424
  setTagVisibility(elementId: string, visible: boolean): void;
@@ -370,12 +443,30 @@ export declare class ThreeJsService {
370
443
  /** The spot picked by the last placement, for whoever commits it to a POI. */
371
444
  getPendingTagPlacement(): ThreeJsTagPlacement | null;
372
445
  /**
373
- * Turns a click into a point on the model, in model space.
446
+ * Raycasts a click against the model's geometry and returns the hit, in world space.
374
447
  *
375
- * Returns null when the click missed the geometry, which is a normal outcome - the user clicked
376
- * the sky - and leaves placement mode armed so they can simply try again.
448
+ * Returns null when the click missed, which is a normal outcome - the user clicked the sky - and
449
+ * leaves whatever mode is armed still armed, so they can simply try again.
450
+ */
451
+ private raycastModel;
452
+ /**
453
+ * Turns a click into a point on the model, in the frame tag coordinates are persisted in.
454
+ *
455
+ * That frame is the tag group's, not the model's. A stored coordinate is read back as a sprite
456
+ * position inside that group, so a coordinate captured in any other frame comes back displaced by
457
+ * exactly however far the alignment moves the group. The two frames agree only while the
458
+ * alignment is identity, which is why this stayed invisible until a model was calibrated.
377
459
  */
378
460
  private pickPlacementOnModel;
461
+ /**
462
+ * Where the user says a tag really belongs, in the space the solved alignment maps onto.
463
+ *
464
+ * setTagAlignment writes the solution to the tag group's own transform, which is expressed
465
+ * relative to its parent - so the target has to be in the parent's frame. Measuring it in the
466
+ * group's own frame instead would fold the current alignment into the answer, making each
467
+ * calibration depend on the one before it.
468
+ */
469
+ private pickAlignmentTarget;
379
470
  /**
380
471
  * Sets the transform mapping captured tag coordinates onto this model's space.
381
472
  *
@@ -416,6 +507,13 @@ export declare class ThreeJsService {
416
507
  updateObjsToScene(objsAdded: ObjAdded[]): void;
417
508
  private onMouseMove;
418
509
  private onMouseClick;
510
+ /**
511
+ * Escape cancels whatever the pointer is currently committed to.
512
+ *
513
+ * Emits through the same subjects the explicit Cancel buttons use, so the UI driving them follows
514
+ * along instead of being left showing a mode that is no longer armed.
515
+ */
516
+ private onKeyDown;
419
517
  private animate;
420
518
  destroy(): void;
421
519
  static ɵfac: i0.ɵɵFactoryDeclaration<ThreeJsService, never>;