@smarterplan/ngx-smarterplan-core 1.4.20 → 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 (41) hide show
  1. package/esm2022/lib/components/splat-viewer/splat-viewer.component.mjs +361 -0
  2. package/esm2022/lib/matterport-extensions/security-camera/SecurityCamera.mjs +28 -7
  3. package/esm2022/lib/ngx-smarterplan-core.module.mjs +9 -4
  4. package/esm2022/lib/services/matterport-object3d.service.mjs +657 -133
  5. package/esm2022/lib/services/matterport-tag.service.mjs +12 -7
  6. package/esm2022/lib/services/matterport.service.mjs +330 -9
  7. package/esm2022/lib/services/obj-to-glb.mjs +649 -0
  8. package/esm2022/lib/services/s3.service.mjs +43 -3
  9. package/esm2022/lib/services/threejs-import.service.mjs +6 -4
  10. package/esm2022/lib/services/threejs.service.mjs +867 -95
  11. package/esm2022/lib/services/utils/matterport-framing.util.mjs +63 -0
  12. package/esm2022/lib/services/viewer.service.mjs +189 -7
  13. package/esm2022/lib/types.service.mjs +3 -1
  14. package/esm2022/public-api.mjs +3 -1
  15. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +3217 -282
  16. package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
  17. package/lib/components/splat-viewer/splat-viewer.component.d.ts +98 -0
  18. package/lib/ngx-smarterplan-core.module.d.ts +7 -6
  19. package/lib/services/matterport-object3d.service.d.ts +125 -5
  20. package/lib/services/matterport-tag.service.d.ts +5 -5
  21. package/lib/services/matterport.service.d.ts +106 -7
  22. package/lib/services/obj-to-glb.d.ts +66 -0
  23. package/lib/services/s3.service.d.ts +7 -0
  24. package/lib/services/threejs.service.d.ts +336 -16
  25. package/lib/services/utils/matterport-framing.util.d.ts +40 -0
  26. package/lib/services/viewer.service.d.ts +110 -8
  27. package/lib/types.service.d.ts +42 -1
  28. package/package.json +1 -1
  29. package/public-api.d.ts +2 -0
  30. package/src/assets/viewers/splat/chunk-BYLI4YBI.js +17037 -0
  31. package/src/assets/viewers/splat/chunk-LDV6YPMG.js +1 -0
  32. package/src/assets/viewers/splat/chunk-WZ5Z4TU3.js +105719 -0
  33. package/src/assets/viewers/splat/convert-4DRLH77X.js +1 -0
  34. package/src/assets/viewers/splat/convert.html +11 -0
  35. package/src/assets/viewers/splat/converter-SLBB5MHG.js +1 -0
  36. package/src/assets/viewers/splat/index.html +90 -0
  37. package/src/assets/viewers/splat/spz-DEYRea_v-QE6YSGIB.js +5292 -0
  38. package/src/assets/viewers/splat/viewer-W4X3FWQJ.js +2704 -0
  39. package/src/assets/viewers/splat/viewer.css +1096 -0
  40. package/src/assets/viewers/splat/webp.wasm +0 -0
  41. package/src/assets/viewers/splat/worker.mjs +1383 -0
@@ -0,0 +1,98 @@
1
+ import { ElementRef, EventEmitter, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
2
+ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
3
+ import { TranslateService } from '@ngx-translate/core';
4
+ import { ThreeJsModelUp } from '../../helpers.service';
5
+ import { ViewerService } from '../../services/viewer.service';
6
+ import * as i0 from "@angular/core";
7
+ /** How the splat viewer is moved through: around the model, or inside it. */
8
+ export type SplatViewerMode = 'orbit' | 'walk';
9
+ /**
10
+ * Gaussian splats, drawn by SuperSplat's viewer (PlayCanvas) in an iframe, as Matterport's showcase
11
+ * is: the page built from projects/splat-viewer, which each app serves from assets/viewers/splat.
12
+ *
13
+ * The visit's Three.js scene stays underneath, unseen, holding the tags, their calibration and the
14
+ * measurement, as it does for a model it draws itself; this hands the viewer what the scene holds,
15
+ * and turns what is clicked in it into what a click in the scene does - through ViewerService, so
16
+ * that whatever drives the scene (the add buttons, the calibration panel, the measuring tool, the
17
+ * tag lists) drives this as well. Tags clicked come out of ViewerService.threeJsTagClicked$, as
18
+ * clicks in the scene do.
19
+ *
20
+ * What it says of loading is for the app's own loading overlay; see the outputs.
21
+ */
22
+ export declare class SplatViewerComponent implements OnInit, OnChanges, OnDestroy {
23
+ private viewerService;
24
+ private host;
25
+ private sanitizer;
26
+ private translate;
27
+ /** The model: the S3 key - or assets/ path - of a splat file, or of a Streamed SOG's lod-meta.json. */
28
+ modelKey: string | null;
29
+ /** Which of the model's axes is up, from its capture's placement; null for the viewer's own idea. */
30
+ up: ThreeJsModelUp | null;
31
+ /** How far loading has got, from 0 to 1, or null when the size is not known. 0 when it starts. */
32
+ loadProgress: EventEmitter<number>;
33
+ loaded: EventEmitter<void>;
34
+ loadFailed: EventEmitter<string>;
35
+ /** Said whenever the mode changes, the viewer's own buttons included. */
36
+ modeChange: EventEmitter<SplatViewerMode>;
37
+ frame: ElementRef<HTMLIFrameElement>;
38
+ /**
39
+ * The viewer's page, made once, in ngOnInit: a new object, even for the same address, would make
40
+ * Angular set the iframe's src again, which loads the viewer afresh with nothing in it.
41
+ */
42
+ page: SafeResourceUrl;
43
+ /** Whether the page has said it is ready; it says so again each time it starts over. */
44
+ private ready;
45
+ /** The model handed to the page, so the same one is not downloaded twice. */
46
+ private loadedKey;
47
+ /** Set by cancelLoad: the page, starting over empty, waits to be asked again (reload). */
48
+ private cancelled;
49
+ /** Whether the page was last asked to take a click for a calibration. */
50
+ private pickingForCalibration;
51
+ /** The calibration under way, as ViewerService last said. */
52
+ private alignment;
53
+ /** Each segment's length of the measurement on the model, as ViewerService last said. */
54
+ private measureDistances;
55
+ /** The last lod-meta.json handed to the page, as a link of this page's own. */
56
+ private streamedMeta;
57
+ /** Pictures asked of the page, by the number they were asked with, until it answers. */
58
+ private snapshots;
59
+ private snapshotCount;
60
+ private destroyed$;
61
+ constructor(viewerService: ViewerService, host: ElementRef<HTMLElement>, sanitizer: DomSanitizer, translate: TranslateService);
62
+ ngOnInit(): void;
63
+ ngOnChanges(changes: SimpleChanges): void;
64
+ ngOnDestroy(): void;
65
+ /** Stops the model loading; nothing is loaded again until reload(). */
66
+ cancelLoad(): void;
67
+ /** Loads the model again, after cancelLoad. */
68
+ reload(): void;
69
+ setMode(mode: SplatViewerMode): void;
70
+ /**
71
+ * The scene as it is on screen, with the measurement drawn on it and no tags, as a JPEG data URL;
72
+ * null when there is no scene to take, or the page does not answer within ten seconds.
73
+ */
74
+ snapshot(): Promise<string | null>;
75
+ /** What the page says: that it is ready, how loading goes, what was clicked in it. */
76
+ onMessage(event: MessageEvent): void;
77
+ private load;
78
+ /**
79
+ * The lod-meta.json of a Streamed SOG, with its pieces named so that the page asks for each of
80
+ * them when it needs it ('sign').
81
+ *
82
+ * The pieces sit beside lod-meta.json in S3 and are named relative to it, which a signed link -
83
+ * its signature in the query - does not survive. And they are fetched while the visit lasts, as the
84
+ * camera reaches them, long after any link signed up front has run out.
85
+ */
86
+ private streamedEntry;
87
+ private postTags;
88
+ /**
89
+ * The calibration under way, for the page to draw - the pins dropped, the tag being matched - and,
90
+ * while the place of a tag is asked for, to take the click on the model that says where ('picked').
91
+ */
92
+ private postCalibration;
93
+ /** The measurement for the page to draw - its points, each segment's length - or nothing. */
94
+ private postMeasurement;
95
+ private post;
96
+ static ɵfac: i0.ɵɵFactoryDeclaration<SplatViewerComponent, never>;
97
+ static ɵcmp: i0.ɵɵComponentDeclaration<SplatViewerComponent, "lib-splat-viewer", never, { "modelKey": { "alias": "modelKey"; "required": false; }; "up": { "alias": "up"; "required": false; }; }, { "loadProgress": "loadProgress"; "loaded": "loaded"; "loadFailed": "loadFailed"; "modeChange": "modeChange"; }, never, never, false, never>;
98
+ }
@@ -15,14 +15,15 @@ import * as i11 from "./components/menu-bar/navigation-bar/navigation-bar.compon
15
15
  import * as i12 from "./components/loader/loader.component";
16
16
  import * as i13 from "./components/support-modal/support-modal.component";
17
17
  import * as i14 from "./pipes/format-date-number-to-digits.pipe";
18
- import * as i15 from "@angular/forms";
19
- import * as i16 from "@angular/common";
20
- import * as i17 from "@angular/router";
21
- import * as i18 from "@ng-bootstrap/ng-bootstrap";
22
- import * as i19 from "@ngx-translate/core";
18
+ import * as i15 from "./components/splat-viewer/splat-viewer.component";
19
+ import * as i16 from "@angular/forms";
20
+ import * as i17 from "@angular/common";
21
+ import * as i18 from "@angular/router";
22
+ import * as i19 from "@ng-bootstrap/ng-bootstrap";
23
+ import * as i20 from "@ngx-translate/core";
23
24
  export declare class NgxSmarterplanCoreModule {
24
25
  static forRoot(config: Config): ModuleWithProviders<NgxSmarterplanCoreModule>;
25
26
  static ɵfac: i0.ɵɵFactoryDeclaration<NgxSmarterplanCoreModule, never>;
26
- static ɵmod: i0.ɵɵNgModuleDeclaration<NgxSmarterplanCoreModule, [typeof i1.TimeDateToLocalStringPipe, typeof i2.SafeUrlPipe, typeof i3.HashtagFromIdPipe, typeof i4.DurationToStringPipe, typeof i5.CsvExportComponent, typeof i6.SearchBarComponent, typeof i7.UsernameFromIdPipe, typeof i8.ModalSwitchVisitComponent, typeof i9.MenuBarComponent, typeof i10.AvatarComponent, typeof i11.NavigationBarComponent, typeof i12.LoaderComponent, typeof i13.SupportModalComponent, typeof i14.FormatDateNumberToDigitsPipe], [typeof i15.FormsModule, typeof i15.ReactiveFormsModule, typeof i16.CommonModule, typeof i17.RouterModule, typeof i18.NgbModule, typeof i19.TranslateModule], [typeof i5.CsvExportComponent, typeof i6.SearchBarComponent, typeof i1.TimeDateToLocalStringPipe, typeof i2.SafeUrlPipe, typeof i3.HashtagFromIdPipe, typeof i4.DurationToStringPipe, typeof i7.UsernameFromIdPipe, typeof i9.MenuBarComponent, typeof i12.LoaderComponent, typeof i13.SupportModalComponent, typeof i10.AvatarComponent]>;
27
+ static ɵmod: i0.ɵɵNgModuleDeclaration<NgxSmarterplanCoreModule, [typeof i1.TimeDateToLocalStringPipe, typeof i2.SafeUrlPipe, typeof i3.HashtagFromIdPipe, typeof i4.DurationToStringPipe, typeof i5.CsvExportComponent, typeof i6.SearchBarComponent, typeof i7.UsernameFromIdPipe, typeof i8.ModalSwitchVisitComponent, typeof i9.MenuBarComponent, typeof i10.AvatarComponent, typeof i11.NavigationBarComponent, typeof i12.LoaderComponent, typeof i13.SupportModalComponent, typeof i14.FormatDateNumberToDigitsPipe, typeof i15.SplatViewerComponent], [typeof i16.FormsModule, typeof i16.ReactiveFormsModule, typeof i17.CommonModule, typeof i18.RouterModule, typeof i19.NgbModule, typeof i20.TranslateModule], [typeof i5.CsvExportComponent, typeof i6.SearchBarComponent, typeof i1.TimeDateToLocalStringPipe, typeof i2.SafeUrlPipe, typeof i3.HashtagFromIdPipe, typeof i4.DurationToStringPipe, typeof i7.UsernameFromIdPipe, typeof i9.MenuBarComponent, typeof i12.LoaderComponent, typeof i13.SupportModalComponent, typeof i10.AvatarComponent, typeof i15.SplatViewerComponent]>;
27
28
  static ɵinj: i0.ɵɵInjectorDeclaration<NgxSmarterplanCoreModule>;
28
29
  }
@@ -1,4 +1,5 @@
1
- import { IObject3D, PoiType, POI, DbObjectType } from '../types.service';
1
+ import { Subject } from 'rxjs';
2
+ import { IObject3D, PoiType, POI, DbObjectType, GizmoMode, GizmoSnap, Object3DBoundingBox, Object3DTransform, Object3DTransformChange, Point3D } from '../types.service';
2
3
  import * as i0 from "@angular/core";
3
4
  export declare class MatterportObject3DService {
4
5
  dictionnaryObjects3D: Map<string, any>;
@@ -9,22 +10,141 @@ export declare class MatterportObject3DService {
9
10
  azimuthalCrown: any;
10
11
  threeJSScene: any;
11
12
  noLightForObjects: boolean;
13
+ /** Max time (ms) to wait for a model to be loaded by the SDK */
14
+ loadTimeoutMs: number;
15
+ /** Max distance (m) an object can travel from where a translate drag started */
16
+ maxDragDistance: number;
17
+ /** Max vertical travel (m, up and down) during a translate drag, so an object cannot jump to another floor */
18
+ maxDragHeight: number;
19
+ /** Emits on every gizmo change and on setObject3DTransform */
20
+ readonly object3DTransformChanged$: Subject<Object3DTransformChange>;
21
+ /** Security camera animators by object uuid (`securityCameraAnimator` stays the last loaded one) */
22
+ securityCameraAnimators: Map<string, any>;
23
+ private viewFrustumVisible;
24
+ private lastSecurityCameraUuid;
25
+ /** Loader component of each model (outputs.objectRoot is set once loaded) */
26
+ private loaderComponents;
27
+ private gizmos;
28
+ private activeGizmoUuid;
29
+ private gizmoSnap;
30
+ /** Sweeps disabled by setNavigationLocked(true), re-enabled on unlock */
31
+ private sweepsDisabledByLock;
32
+ /** Sweeps re-enabled by the last unlock (the SDK may still report them disabled for a moment) */
33
+ private sweepsEnabledByUnlock;
34
+ private readonly tmpBox;
12
35
  constructor();
13
36
  init3DObjectViewer(sdk: any): Promise<void>;
14
- add3DObject(sdk: any, obj: IObject3D, mode?: 'translate' | 'rotate'): Promise<any>;
37
+ /** SDK loader component name for a model format, null when the format is not supported */
38
+ private getLoaderComponentName;
39
+ /** Resolves once the loader component has produced its objectRoot, rejects after `timeoutMs` */
40
+ private waitForModelLoaded;
41
+ /**
42
+ * Adds a 3D model to the scene.
43
+ * The promise resolves with the three.js object once the model is actually loaded, and rejects
44
+ * (after cleaning the scene) when the format is unknown or the load times out.
45
+ * The position / rotation / scale of `obj` are applied to the model origin, as stored in DB.
46
+ */
47
+ add3DObject(sdk: any, obj: IObject3D, mode?: GizmoMode): Promise<any>;
48
+ /**
49
+ * Removes a 3D object for good: detaches its gizmo, stops its scene object and forgets it.
50
+ */
15
51
  deleteObject3D(uuid: string): Promise<void>;
16
52
  getObject3DModelNodeFromDictionnary(uuid: string): any;
17
53
  toggleObjectVisibility(objectId: any): void;
18
54
  isObjectVisible(objectId: any): boolean;
55
+ /** Shows / hides a model (used by the placement preview) */
56
+ setObject3DVisible(uuid: string, visible: boolean): void;
57
+ /** Enables / disables the pointer collider of a model (disabled while it follows the cursor) */
58
+ setObject3DColliderEnabled(uuid: string, enabled: boolean): void;
59
+ /**
60
+ * Moves the camera next to a 3D object by creating a temporary tag on the object centre.
61
+ * @returns false when the object is unknown or no tag could be reached
62
+ */
19
63
  pointCameraTo3DObject(sdk: any, objectId: any, createTagCallback: (tagType: PoiType, object: DbObjectType, poi: POI) => Promise<any>, goToTagCallback: (sid: string) => Promise<any>, deleteLastTagCallback: () => void, getTagFromElementId: (id: string) => {
20
64
  tag: string;
21
65
  sweep: string;
22
- }): Promise<void>;
66
+ }): Promise<boolean>;
23
67
  getSceneNodeFromObject3DId(uuid: string): any;
24
68
  displayAzimutalCrown(poseCamera: any): Promise<void>;
25
- attachGizmoControlTo3DObject(sdk: any, modelNode: any, sceneObject: any, mode: 'translate' | 'rotate' | 'scale', visible: boolean, isNewObject: boolean): Promise<any>;
69
+ private toPoint;
70
+ /**
71
+ * Geometry of the model itself (the loader output): the node also holds the helpers added by other
72
+ * components, like the view frustum of a security camera, which must not count in its size.
73
+ */
74
+ private modelRoot;
75
+ /** World-space bounding box of the model, null when unknown or when nothing is loaded yet */
76
+ getObject3DBoundingBox(uuid: string): Object3DBoundingBox | null;
77
+ /**
78
+ * Real dimensions of the model in meters (width x, height y, depth z), scale included but not
79
+ * its rotation: the world bounding box of a rotated object is larger than the object itself.
80
+ */
81
+ getObject3DDimensions(uuid: string): Point3D | null;
82
+ /**
83
+ * Uniform scale so that the largest bounding box dimension equals `targetSizeMeters`.
84
+ * The node position is untouched, so call placeObject3DOnSurface afterwards.
85
+ * @returns the new scale, null when the object is unknown / not loaded / `targetSizeMeters` invalid
86
+ */
87
+ normalizeObject3DSize(uuid: string, targetSizeMeters: number): Point3D | null;
88
+ /**
89
+ * Places the model on a surface point without touching its pivot: the node position is
90
+ * adjusted so that the bounding box bottom-center lies on `point`.
91
+ * - floor (normal pointing up, or no normal): bottom-center on the point
92
+ * - wall (mostly horizontal normal): model turned around Y so its +Z faces away from the wall,
93
+ * and pushed along the normal by half its depth so it does not cut the wall
94
+ * - ceiling (normal pointing down): the model hangs, top-center on the point
95
+ * @returns the new transform, null when the object is unknown or not loaded
96
+ */
97
+ /**
98
+ * @param frontYawOffset rotation (radians, around Y) that turns the front of the model toward its +Z
99
+ * axis, for models whose front is another axis (e.g. -PI/2 when it is +X)
100
+ */
101
+ placeObject3DOnSurface(uuid: string, point: Point3D, normal?: Point3D, frontYawOffset?: number): Object3DTransform | null;
102
+ getObject3DTransform(uuid: string): Object3DTransform | null;
103
+ /** Applies a (partial) transform. Rotation is in radians. */
104
+ setObject3DTransform(uuid: string, transform: Partial<Object3DTransform>): boolean;
105
+ private emitTransformChanged;
106
+ /** Creates the mp.transformControls node of a model and wires it (events, snap) */
107
+ private createGizmo;
108
+ /** Keeps a translate drag within maxDragDistance / maxDragHeight of where it started, then notifies */
109
+ private onGizmoObjectChange;
110
+ private applySnap;
111
+ /**
112
+ * Shows the transform gizmo on an object (any previous gizmo is detached first).
113
+ * Re-attaching to the object that already has the gizmo only changes its mode.
114
+ */
115
+ attachGizmo(uuid: string, mode: GizmoMode, sdk?: any): Promise<boolean>;
116
+ /** Switches the active gizmo between translate / rotate / scale without re-attaching it */
117
+ setGizmoMode(mode: GizmoMode): void;
118
+ /** Really removes the gizmo from the scene (default: the active one) */
119
+ detachGizmo(uuid?: string): void;
120
+ isGizmoAttached(uuid?: string): boolean;
121
+ /** Snap steps for all gizmos (null / missing value = no snap) */
122
+ setGizmoSnap(snap: GizmoSnap | null): void;
123
+ setGizmoMaxDragDistance(maxDistance: number, maxHeight?: number): void;
124
+ /**
125
+ * Prevents camera navigation to other sweeps while a gizmo is edited.
126
+ * The SDK has no "freeze camera" switch, so every enabled sweep except the current one is
127
+ * disabled (Sweep.disable); exactly those sweeps are re-enabled on unlock. Sweeps already
128
+ * disabled (forbidden sweeps, edit mode) are never touched, and `keepDisabled` lists sweeps
129
+ * that must stay disabled on unlock.
130
+ * @returns false when the lock could not be applied (SDK without Sweep.disable, unknown current sweep)
131
+ */
132
+ setNavigationLocked(sdk: any, locked: boolean, sweepCollection?: Record<string, any> | null, currentSweepId?: string | null, keepDisabled?: string[]): Promise<boolean>;
133
+ isNavigationLocked(): boolean;
134
+ /** Sweeps currently disabled by the navigation lock */
135
+ getSweepsDisabledByLock(): string[];
136
+ /**
137
+ * Legacy API: attaches a gizmo to a model node. Prefer attachGizmo(uuid, mode).
138
+ */
139
+ attachGizmoControlTo3DObject(sdk: any, modelNode: any, sceneObject: any, mode: GizmoMode, visible: boolean, isNewObject: boolean): Promise<any>;
140
+ /** Removes the gizmo of the last added / edited object */
26
141
  removeGizmoFromLastObject(): void;
27
- toggleViewFrustum(): void;
142
+ private applyViewFrustum;
143
+ /** Shows / hides the view frustum of the security camera `uuid` */
144
+ setViewFrustum(uuid: string, visible: boolean): boolean;
145
+ isViewFrustumVisible(uuid: string): boolean;
146
+ /** Toggles the frustum of `uuid`, or of the last loaded security camera when omitted */
147
+ toggleViewFrustum(uuid?: string): void;
28
148
  clear(): void;
29
149
  static ɵfac: i0.ɵɵFactoryDeclaration<MatterportObject3DService, never>;
30
150
  static ɵprov: i0.ɵɵInjectableDeclaration<MatterportObject3DService>;
@@ -121,11 +121,11 @@ export declare class MatterportTagService {
121
121
  * floor and room context. Must be called after each sweep, floor or mode change.
122
122
  *
123
123
  * Rules:
124
- * - DOLLHOUSE / FLOORPLAN → all tags hidden (opacity 0).
125
- * - INSIDE → only tags whose sweep belongs to the current floor are shown;
126
- * proximity-based opacity is applied via computeTagOpacity().
127
- * Tags on other floors are hidden (opacity 0).
128
- * - TRANSITIONING → no change (skip update to avoid flickering).
124
+ * - A tag shows when its sweep is on the floor being displayed, in every mode. Tags on
125
+ * other floors are hidden (opacity 0) and cannot be opened.
126
+ * - While all floors are displayed - the usual state of DOLLHOUSE and FLOORPLAN - every
127
+ * tag shows.
128
+ * - A tag with no sweep belongs to no floor and always shows.
129
129
  *
130
130
  * @param sdk Matterport SDK instance.
131
131
  * @param poseCamera Current camera pose.
@@ -1,8 +1,8 @@
1
- import { NgZone } from '@angular/core';
1
+ import { NgZone, OnDestroy } from '@angular/core';
2
2
  import { ActivatedRoute, Router } from '@angular/router';
3
3
  import { Subject } from 'rxjs';
4
4
  import { MattertagData } from '../mattertagData';
5
- import { DbObjectType, IObject3D, MattertagActionMode, MatterportView, POI, PoiType, SpModule } from '../types.service';
5
+ import { DbObjectType, GizmoMode, GizmoSnap, IObject3D, MattertagActionMode, MatterportView, Object3DBoundingBox, Object3DPlacementResult, Object3DTransform, Object3DTransformChange, POI, PoiType, Point3D, SpModule } from '../types.service';
6
6
  import { BaseTagService } from './tag.service';
7
7
  import { BaseVisibilityService } from './baseVisibility.service';
8
8
  import { Config } from '../config';
@@ -42,7 +42,7 @@ declare global {
42
42
  };
43
43
  }
44
44
  }
45
- export declare class MatterportService {
45
+ export declare class MatterportService implements OnDestroy {
46
46
  private readonly sdkKey;
47
47
  private router;
48
48
  private activeRoute;
@@ -65,6 +65,18 @@ export declare class MatterportService {
65
65
  private isMeasureModeOn;
66
66
  private interactionMode;
67
67
  private cameraMode;
68
+ /** Emitted when a placement (tag following the cursor, or 3D object preview) is cancelled by right click or Escape */
69
+ readonly placementCancelled$: Subject<void>;
70
+ /** Pending interactive placement of a 3D object (see startObject3DPlacement) */
71
+ private object3DPlacement;
72
+ /** Sweeps snapshot taken when navigation is locked (disabled sweeps vanish from Sweep.data) */
73
+ private lockedSweepsSnapshot;
74
+ /**
75
+ * Every sweep seen in Sweep.data. After an unlock the SDK re-emits the re-enabled sweeps little by
76
+ * little: a lock asked meanwhile must still know all of them (it found nothing to disable).
77
+ */
78
+ private knownSweeps;
79
+ private keydownTargets;
68
80
  get mattertagIDs(): Array<string>;
69
81
  set mattertagIDs(value: Array<string>);
70
82
  get dictionnaryTags(): Map<string, MattertagData>;
@@ -414,15 +426,102 @@ export declare class MatterportService {
414
426
  clearAll(): Promise<void>;
415
427
  removeForbiddenSweeps(forbiddenSweeps: string[]): Promise<void>;
416
428
  init3DObjectViewer(): Promise<void>;
417
- add3DObject(obj: IObject3D, mode?: 'translate' | 'rotate'): Promise<any>;
429
+ /**
430
+ * Adds a 3D model; resolves once it is loaded, rejects on unknown format or load timeout (~15 s).
431
+ */
432
+ add3DObject(obj: IObject3D, mode?: GizmoMode): Promise<any>;
418
433
  toggleObjectVisibility(objectId: any): void;
419
434
  isObjectVisible(objectId: any): boolean;
420
- pointCameraTo3DObject(objectId: any): Promise<void>;
435
+ /** Moves the camera to the object (centered on its bounding box). Resolves false when the object is unknown. */
436
+ /**
437
+ * Moves the camera to the sweep closest to a 3D object and turns it toward the object.
438
+ * @param visibleArea client X bounds of the part of the viewer not covered by other panels
439
+ * (the lateral menu covers the right of the viewer): the object is centered there.
440
+ * Falls back to the temporary tag navigation when no sweep can be used.
441
+ */
442
+ pointCameraTo3DObject(objectId: any, visibleArea?: {
443
+ left: number;
444
+ right: number;
445
+ }): Promise<boolean>;
421
446
  getSceneNodeFromObject3DId(uuid: string): any;
422
447
  displayAzimutalCrown(): Promise<void>;
423
- attachGizmoControlTo3DObject(modelNode: any, sceneObject: any, mode: 'translate' | 'rotate' | 'scale', visible: boolean, isNewObject: boolean): Promise<any>;
448
+ attachGizmoControlTo3DObject(modelNode: any, sceneObject: any, mode: GizmoMode, visible: boolean, isNewObject: boolean): Promise<any>;
424
449
  removeGizmoFromLastObject(): void;
425
- toggleViewFrustum(): void;
450
+ /** Toggles the frustum of the security camera `uuid` (default: the last loaded one) */
451
+ toggleViewFrustum(uuid?: string): void;
452
+ setViewFrustum(uuid: string, visible: boolean): boolean;
453
+ isViewFrustumVisible(uuid: string): boolean;
454
+ /** Emits on gizmo changes and on setObject3DTransform / placeObject3DOnSurface / normalizeObject3DSize */
455
+ get object3DTransformChanged$(): Subject<Object3DTransformChange>;
456
+ /** World-space bounding box, null when the object is unknown or not loaded */
457
+ getObject3DBoundingBox(uuid: string): Object3DBoundingBox | null;
458
+ /** Dimensions of the model in meters, without its rotation */
459
+ getObject3DDimensions(uuid: string): Point3D | null;
460
+ /** Uniform scale so the largest dimension equals `targetSizeMeters`; returns the new scale or null */
461
+ normalizeObject3DSize(uuid: string, targetSizeMeters: number): Point3D | null;
462
+ /** Moves the object so its bounding box bottom-center (top-center on a ceiling) lies on `point` */
463
+ placeObject3DOnSurface(uuid: string, point: Point3D, normal?: Point3D, frontYawOffset?: number): Object3DTransform | null;
464
+ getObject3DTransform(uuid: string): Object3DTransform | null;
465
+ /** Rotation in radians */
466
+ setObject3DTransform(uuid: string, transform: Partial<Object3DTransform>): boolean;
467
+ attachGizmo(uuid: string, mode: GizmoMode): Promise<boolean>;
468
+ setGizmoMode(mode: GizmoMode): void;
469
+ detachGizmo(uuid?: string): void;
470
+ isGizmoAttached(uuid?: string): boolean;
471
+ /** null disables snapping (default) */
472
+ setGizmoSnap(snap: GizmoSnap | null): void;
473
+ /** Limits of a translate drag from its start (default 2 m, +/- 1.5 m vertically) */
474
+ setGizmoMaxDragDistance(maxDistance: number, maxHeight?: number): void;
475
+ /**
476
+ * Locks / unlocks camera navigation to other sweeps while a gizmo is edited: every enabled sweep
477
+ * except the current one is disabled, and exactly those are re-enabled on unlock.
478
+ * @returns false when the lock could not be applied (SDK not ready, current sweep unknown)
479
+ */
480
+ setNavigationLocked(locked: boolean): Promise<boolean>;
481
+ isNavigationLocked(): boolean;
482
+ /**
483
+ * Makes an already loaded model follow the cursor on the surfaces of the visit.
484
+ * Left click resolves with the surface point / normal under the cursor (read the object origin
485
+ * with getObject3DTransform); right click or Escape hides the model and resolves null
486
+ * (deleting it is up to the caller). Resolves null right away if another interaction is running.
487
+ */
488
+ startObject3DPlacement(uuid: string, options?: {
489
+ frontYawOffset?: number;
490
+ }): Promise<Object3DPlacementResult | null>;
491
+ isPlacingObject3D(): boolean;
492
+ /** Cancels the running object placement (model hidden, promise resolves null) */
493
+ cancelObject3DPlacement(): void;
494
+ /**
495
+ * Drops the object where it is previewed (same as a left click). Touch screens have no hover: each
496
+ * tap moves the preview, and the app confirms with a button.
497
+ * @returns false when no surface was pointed yet
498
+ */
499
+ confirmObject3DPlacement(): boolean;
500
+ /** True once the preview stands on a surface (the placement can be confirmed) */
501
+ hasObject3DPlacementPoint(): boolean;
502
+ private validateObject3DPlacement;
503
+ private endObject3DPlacement;
504
+ private updateObject3DPlacementPreview;
505
+ /** Token for the pointer trick: truthy while something follows the cursor (tag or 3D object) */
506
+ private getFollowTarget;
507
+ /**
508
+ * Cancels whatever follows the cursor (right click / Escape): the 3D object preview, or the tag.
509
+ * Emits placementCancelled$ when something was actually running.
510
+ */
511
+ private cancelCurrentPlacement;
512
+ /** Escape cancels any placement. Listens on the page and on the (same-origin) Showcase iframe, which takes the focus on click. */
513
+ private registerEscapeListener;
514
+ private removeEscapeListener;
515
+ ngOnDestroy(): void;
516
+ /**
517
+ * Closest enabled sweep to a world position (for instance to re-assign the zone of a moved object).
518
+ * `sweepId` is the DB-format id (like currentSweep), `sid` the SDK id. null when no sweep is known.
519
+ */
520
+ findNearestSweep(position: Point3D): {
521
+ sweepId: string;
522
+ sid: string;
523
+ floorSequence: number | null;
524
+ } | null;
426
525
  static ɵfac: i0.ɵɵFactoryDeclaration<MatterportService, never>;
427
526
  static ɵprov: i0.ɵɵInjectableDeclaration<MatterportService>;
428
527
  }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Converts an .obj model, with its .mtl and textures, into the .glb the Three.js viewer loads - in
3
+ * the browser, as the model is added, with nothing to install.
4
+ *
5
+ * It does what obj2gltf did in converte-modelo.sh, and the reason is the same. An .obj lists every
6
+ * corner of every triangle; loaded as it is, a captured model's 2.6 million distinct vertices become
7
+ * 12.6 million, one per corner. Here each position and texture coordinate pair becomes one vertex,
8
+ * shared by every triangle that uses it, so what reaches the graphics card is the 2.6 million.
9
+ *
10
+ * Textures go in as they are, their bytes untouched: a JPEG re-encoded would lose quality and gain
11
+ * nothing. Normals are only written when the .obj has them; without, the viewer works them out as
12
+ * it loads the model. The axes are left as the .obj has them - the viewer finds which way is up.
13
+ *
14
+ * The .obj is read as a stream, so a file of hundreds of megabytes is never held whole.
15
+ */
16
+ export interface ConvertedModel {
17
+ /** The model as a .glb. */
18
+ file: File;
19
+ vertices: number;
20
+ triangles: number;
21
+ materials: number;
22
+ /** Textures the .mtl names that were not among the files given; those materials go untextured. */
23
+ missingTextures: string[];
24
+ }
25
+ export interface ObjConversionOptions {
26
+ /** Called as the conversion goes, with the share done so far. */
27
+ onProgress?: (fraction: number) => void;
28
+ /** Stops the conversion; it then rejects with an AbortError. */
29
+ signal?: AbortSignal;
30
+ }
31
+ /** Whether a set of files holds an .obj model to convert. */
32
+ export declare function hasObjModel(files: {
33
+ name: string;
34
+ }[]): boolean;
35
+ /**
36
+ * Converts the .obj among `files` into a .glb, using the .mtl and the images found with it.
37
+ */
38
+ export declare function convertObjToGlb(files: File[], options?: ObjConversionOptions): Promise<ConvertedModel>;
39
+ /** A growable typed array: an .obj does not say up front how many of anything it holds. */
40
+ declare class Growable<T extends Float64Array | Float32Array | Int32Array> {
41
+ data: T;
42
+ length: number;
43
+ constructor(data: T);
44
+ push(value: number): void;
45
+ view(): T;
46
+ }
47
+ /** The triangles that use one material, as corners: position, texture and normal index each. */
48
+ interface FaceGroup {
49
+ material: string | null;
50
+ corners: Growable<Int32Array>;
51
+ }
52
+ export interface ParsedObj {
53
+ positions: Float64Array;
54
+ uvs: Float64Array;
55
+ normals: Float64Array;
56
+ groups: FaceGroup[];
57
+ materialLibraries: string[];
58
+ triangleCount: number;
59
+ }
60
+ /**
61
+ * Reads an .obj from a stream of its bytes: positions, texture coordinates, normals, and triangles
62
+ * grouped by material. Polygons are split into triangles; negative indices, counting back from the
63
+ * end, are resolved; anything else (objects, groups, smoothing) is skipped.
64
+ */
65
+ export declare function readObj(stream: ReadableStream<Uint8Array>, size: number, options?: ObjConversionOptions): Promise<ParsedObj>;
66
+ export {};
@@ -7,6 +7,13 @@ export declare const uploadFileToS3: (path: string, file: File, objectId: string
7
7
  * uploadFileToS3 above swallows progress, which is fine for a photo and unusable for a 3D model:
8
8
  * these run to hundreds of megabytes, and an upload with no feedback is indistinguishable from a
9
9
  * frozen page. Returns the stored key, which is what gets saved on the record.
10
+ *
11
+ * A large file is sent in parts, each signed when it is sent. Left to itself, Storage.put signs
12
+ * them all with whatever credentials Amplify last handed the S3 provider, for any call - credentials
13
+ * that last an hour at most, and an upload of a few gigabytes takes longer: every part after they
14
+ * expire is refused with "The provided token has expired", and fetching new ones does not help, the
15
+ * upload never asks for them. Passing no credentials at all makes it ask Amplify for them part by
16
+ * part, and Amplify renews them as they age. Should they run out anyway, it starts once more.
10
17
  */
11
18
  export declare const uploadFileToS3WithProgress: (path: string, file: File, onProgress?: (fraction: number) => void) => Promise<string>;
12
19
  export declare const getSignedImageUrlForEquipment: (equip: Equipment) => Promise<string | null>;