@multisetai/vps 1.0.7-beta.2 → 1.0.7-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +2 -5
- package/dist/core/index.js +9 -29
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +99 -92
- package/dist/index.js.map +1 -1
- package/dist/webxr/index.js +90 -63
- package/dist/webxr/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.d.ts
CHANGED
|
@@ -14,11 +14,7 @@ interface ILocalizeResponse {
|
|
|
14
14
|
poseFound: boolean;
|
|
15
15
|
position: IPosition;
|
|
16
16
|
rotation: IRotation;
|
|
17
|
-
retrieval_scores: number[];
|
|
18
|
-
num_matches: number[];
|
|
19
17
|
confidence: number;
|
|
20
|
-
retreived_imgs: string[];
|
|
21
|
-
retrieved_imgs?: string[];
|
|
22
18
|
mapIds: string[];
|
|
23
19
|
mapCodes: string[];
|
|
24
20
|
responseTime: number;
|
|
@@ -142,6 +138,8 @@ interface IMultisetSdkConfig {
|
|
|
142
138
|
endpoints?: Partial<IMultisetSdkEndpoints>;
|
|
143
139
|
/** If true, show the mesh in the AR session. Default is false. */
|
|
144
140
|
showMesh?: boolean;
|
|
141
|
+
/** If true, show the coordinate gizmo when a pose is found. Defaults to true. */
|
|
142
|
+
showGizmo?: boolean;
|
|
145
143
|
/** If true, automatically start a localization run when the AR session starts. */
|
|
146
144
|
autoLocalize?: boolean;
|
|
147
145
|
/** If true, automatically re-localize when tracking is lost and then recovered. */
|
|
@@ -236,7 +234,6 @@ declare class MultisetClient {
|
|
|
236
234
|
private getGeoPoseComponents;
|
|
237
235
|
private queryLocalization;
|
|
238
236
|
private fetchMapDetails;
|
|
239
|
-
private fetchMapSetDetails;
|
|
240
237
|
}
|
|
241
238
|
|
|
242
239
|
export { DEFAULT_ENDPOINTS, type ICameraIntrinsicsEvent, type IFrameCaptureEvent, type IGetMapsDetailsResponse, type ILocalizeAndMapDetails, type ILocalizeResponse, type ILocalizeResultEvent, type IMapSetMapsResponse, type IMultisetSdkConfig as IMultisetClientOptions, type IMultisetPublicConfig, type IMultisetSdkConfig, type IMultisetSdkEndpoints, type IPoseResultEvent, type MapType, MultisetClient };
|
package/dist/core/index.js
CHANGED
|
@@ -46,7 +46,6 @@ var MultisetClient = class {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
async authorize() {
|
|
49
|
-
var _a, _b, _c, _d, _e;
|
|
50
49
|
try {
|
|
51
50
|
const response = await axios.post(
|
|
52
51
|
this.endpoints.authUrl,
|
|
@@ -58,12 +57,12 @@ var MultisetClient = class {
|
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
);
|
|
61
|
-
const token =
|
|
60
|
+
const token = response.data?.token ?? response.data?.access_token;
|
|
62
61
|
if (!token) {
|
|
63
62
|
throw new Error("Authorization succeeded but no token was returned.");
|
|
64
63
|
}
|
|
65
64
|
this.accessToken = token;
|
|
66
|
-
|
|
65
|
+
this.config.onAuthorize?.(token);
|
|
67
66
|
return token;
|
|
68
67
|
} catch (error) {
|
|
69
68
|
this.handleError(error);
|
|
@@ -71,24 +70,22 @@ var MultisetClient = class {
|
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
handleError(error) {
|
|
74
|
-
var _a, _b, _c, _d;
|
|
75
73
|
if (axios.isAxiosError(error)) {
|
|
76
74
|
const axiosError = error;
|
|
77
|
-
|
|
75
|
+
this.config.onError?.(axiosError);
|
|
78
76
|
} else {
|
|
79
|
-
|
|
77
|
+
this.config.onError?.(error);
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
async localizeWithFrame(frame, intrinsics) {
|
|
83
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
84
81
|
if (!this.accessToken) {
|
|
85
82
|
throw new Error("Access token is missing. Call authorize() first.");
|
|
86
83
|
}
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
this.config.onFrameCaptured?.(frame);
|
|
85
|
+
this.config.onCameraIntrinsics?.(intrinsics);
|
|
89
86
|
const queryResult = await this.queryLocalization(frame, intrinsics);
|
|
90
|
-
if (
|
|
91
|
-
|
|
87
|
+
if (queryResult?.localizeData?.poseFound) {
|
|
88
|
+
this.config.onPoseResult?.(queryResult.localizeData);
|
|
92
89
|
}
|
|
93
90
|
return queryResult;
|
|
94
91
|
}
|
|
@@ -112,7 +109,6 @@ var MultisetClient = class {
|
|
|
112
109
|
}
|
|
113
110
|
}
|
|
114
111
|
async queryLocalization(frame, intrinsics) {
|
|
115
|
-
var _a;
|
|
116
112
|
const formData = new FormData();
|
|
117
113
|
if (this.config.mapType === "map") {
|
|
118
114
|
formData.append("mapCode", this.config.code);
|
|
@@ -155,7 +151,7 @@ var MultisetClient = class {
|
|
|
155
151
|
const result = {
|
|
156
152
|
localizeData: data
|
|
157
153
|
};
|
|
158
|
-
if (this.config.showMesh &&
|
|
154
|
+
if (this.config.showMesh && data.mapCodes?.length) {
|
|
159
155
|
const mapCode = data.mapCodes[0];
|
|
160
156
|
const cached = this.mapDetailsCache[mapCode];
|
|
161
157
|
if (cached) {
|
|
@@ -190,22 +186,6 @@ var MultisetClient = class {
|
|
|
190
186
|
return null;
|
|
191
187
|
}
|
|
192
188
|
}
|
|
193
|
-
async fetchMapSetDetails(mapSetId) {
|
|
194
|
-
try {
|
|
195
|
-
const response = await axios.get(
|
|
196
|
-
`${this.endpoints.mapSetDetailsUrl}${mapSetId}`,
|
|
197
|
-
{
|
|
198
|
-
headers: {
|
|
199
|
-
Authorization: `Bearer ${this.accessToken}`
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
);
|
|
203
|
-
return response.data;
|
|
204
|
-
} catch (error) {
|
|
205
|
-
this.handleError(error);
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
189
|
};
|
|
210
190
|
|
|
211
191
|
export { DEFAULT_ENDPOINTS, MultisetClient };
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/core/config.ts","../../src/lib/core/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ILocalizeAndMapDetails, MapType } from './types';\n\n/** The subset of config that is safe to expose publicly (no credentials). */\nexport type IMultisetPublicConfig = Omit<IMultisetSdkConfig, 'clientId' | 'clientSecret'>;\n\nexport interface IMultisetSdkConfig {\n clientId: string;\n clientSecret: string;\n /** Map or map-set code used for localization. */\n code: string;\n /** Map or map-set type ('map' or 'map-set'). */\n mapType: MapType;\n endpoints?: Partial<IMultisetSdkEndpoints>;\n /** If true, show the mesh in the AR session. Default is false. */\n showMesh?: boolean;\n /** If true, automatically start a localization run when the AR session starts. */\n autoLocalize?: boolean;\n /** If true, automatically re-localize when tracking is lost and then recovered. */\n relocalization?: boolean;\n /** When enabled, only accept a localization result if confidence >= confidenceThreshold. */\n confidenceCheck?: boolean;\n /** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */\n confidenceThreshold?: number;\n /** Total single-frame attempts per localization run (1–5). */\n requestAttempts?: number;\n /** Time in seconds between attempts in a localization run (1–5). */\n localizationInterval?: number;\n /** Include device geo pose as a hint in localization requests. */\n passGeoPose?: boolean;\n /** Request geo coordinates in the localization response (if supported by backend). */\n geoCoordinatesInResponse?: boolean;\n /** Max time in ms to wait for a valid viewer pose before failing. Default 10000. */\n localizationTrackingTimeoutMs?: number;\n\n /** Invoked at the start of a localization run. */\n onLocalizationInit?: () => void;\n /** Invoked after a successful localization that meets confidence criteria (if enabled). */\n onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;\n /** Invoked when all attempts fail or the best result is below the confidence threshold. */\n onLocalizationFailure?: (reason?: string) => void;\n\n /** Called after a successful authorization with the access token. */\n onAuthorize?: (token: string) => void;\n /** Called whenever a camera frame is captured and sent for localization. */\n onFrameCaptured?: (payload: IFrameCaptureEvent) => void;\n /** Called with the camera intrinsics used for a localization request. */\n onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;\n /** Called with the raw pose/localization result returned by the backend. */\n onPoseResult?: (payload: IPoseResultEvent) => void;\n /** Called when any error occurs during authorization or localization. */\n onError?: (error: unknown) => void;\n}\n\nexport interface IMultisetSdkEndpoints {\n authUrl: string;\n queryUrl: string;\n mapDetailsUrl: string;\n fileDownloadUrl: string;\n mapSetDetailsUrl: string;\n}\n\nexport interface IFrameCaptureEvent {\n blob: Blob;\n width: number;\n height: number;\n}\n\nexport interface ICameraIntrinsicsEvent {\n fx: number;\n fy: number;\n px: number;\n py: number;\n width: number;\n height: number;\n}\n\nexport interface IPoseResultEvent {\n poseFound: boolean;\n position: {\n x: number;\n y: number;\n z: number;\n };\n rotation: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n mapIds: string[];\n confidence?: number;\n}\n\nexport interface ILocalizeResultEvent {\n frame: IFrameCaptureEvent;\n intrinsics: ICameraIntrinsicsEvent;\n response: ILocalizeAndMapDetails | null;\n}\n\nexport const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints = {\n authUrl: 'https://api.multiset.ai/v1/m2m/token',\n queryUrl: 'https://api.multiset.ai/v1/vps/map/query-form',\n mapDetailsUrl: 'https://api.multiset.ai/v1/vps/map/',\n mapSetDetailsUrl: 'https://api.multiset.ai/v1/vps/map-set/',\n fileDownloadUrl: 'https://api.multiset.ai/v1/file',\n};\n","import axios, { AxiosError } from 'axios';\nimport type {\n IMultisetSdkConfig,\n IMultisetPublicConfig,\n IMultisetSdkEndpoints,\n IFrameCaptureEvent,\n ICameraIntrinsicsEvent,\n} from './config';\nimport { DEFAULT_ENDPOINTS } from './config';\nimport type {\n ILocalizeAndMapDetails,\n ILocalizeResponse,\n IGetMapsDetailsResponse,\n IMapSetMapsResponse,\n} from './types';\n\nexport class MultisetClient {\n private readonly credentials: { clientId: string; clientSecret: string };\n private readonly config: IMultisetPublicConfig;\n private readonly endpoints: IMultisetSdkEndpoints;\n private accessToken: string | null = null;\n private mapDetailsCache: Record<string, IGetMapsDetailsResponse> = {};\n\n constructor(input: IMultisetSdkConfig) {\n const { clientId, clientSecret, ...rest } = input;\n this.credentials = { clientId, clientSecret };\n this.config = rest;\n this.endpoints = {\n ...DEFAULT_ENDPOINTS,\n ...rest.endpoints,\n };\n }\n\n get token(): string | null {\n return this.accessToken;\n }\n\n getConfig(): IMultisetPublicConfig {\n return this.config;\n }\n\n async downloadFile(key: string): Promise<string> {\n if (!this.accessToken || !key) {\n return '';\n }\n\n try {\n const response = await axios.get<{ url: string }>(\n `${this.endpoints.fileDownloadUrl}?key=${encodeURIComponent(key)}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n return response.status === 200 ? response.data.url : '';\n } catch (error) {\n this.handleError(error);\n return '';\n }\n }\n\n async authorize(): Promise<string> {\n try {\n const response = await axios.post(\n this.endpoints.authUrl,\n {},\n {\n auth: {\n username: this.credentials.clientId,\n password: this.credentials.clientSecret,\n },\n }\n );\n\n const token: string | undefined =\n response.data?.token ?? response.data?.access_token;\n\n if (!token) {\n throw new Error('Authorization succeeded but no token was returned.');\n }\n\n this.accessToken = token;\n this.config.onAuthorize?.(token);\n return token;\n } catch (error) {\n this.handleError(error);\n throw error;\n }\n }\n\n private handleError(error: unknown): void {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n this.config.onError?.(axiosError);\n } else {\n this.config.onError?.(error);\n }\n }\n\n async localizeWithFrame(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n if (!this.accessToken) {\n throw new Error('Access token is missing. Call authorize() first.');\n }\n\n this.config.onFrameCaptured?.(frame);\n this.config.onCameraIntrinsics?.(intrinsics);\n\n const queryResult = await this.queryLocalization(frame, intrinsics);\n\n if (queryResult?.localizeData?.poseFound) {\n this.config.onPoseResult?.(queryResult.localizeData);\n }\n\n return queryResult;\n }\n\n private async getGeoPoseComponents(): Promise<\n { latitude: number, longitude: number, altitude: number } | null\n > {\n if (\n typeof navigator === 'undefined' ||\n !('geolocation' in navigator) ||\n !navigator.geolocation\n ) {\n return null;\n }\n\n try {\n const position = await new Promise<GeolocationPosition>((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(resolve, reject, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: 0,\n });\n });\n\n const { latitude, longitude, altitude } = position.coords;\n const safeAltitude =\n typeof altitude === 'number' && !Number.isNaN(altitude) ? altitude : 0.0;\n\n return { latitude, longitude, altitude: safeAltitude };\n } catch {\n return null;\n }\n }\n\n private async queryLocalization(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n const formData = new FormData();\n\n if (this.config.mapType === 'map') {\n formData.append('mapCode', this.config.code);\n } else {\n formData.append('mapSetCode', this.config.code);\n }\n formData.append('isRightHanded', 'true');\n formData.append('fx', `${intrinsics.fx}`);\n formData.append('fy', `${intrinsics.fy}`);\n formData.append('px', `${intrinsics.px}`);\n formData.append('py', `${intrinsics.py}`);\n formData.append('width', `${frame.width}`);\n formData.append('height', `${frame.height}`);\n formData.append('queryImage', frame.blob);\n if (this.config.geoCoordinatesInResponse) {\n formData.append('geoCoordinatesInResponse', 'true');\n }\n if (this.config.passGeoPose) {\n const components = await this.getGeoPoseComponents();\n if (components) {\n const { latitude, longitude, altitude } = components;\n const geoHint = `${latitude},${longitude},${altitude}`;\n formData.append('geoHint', geoHint);\n }\n }\n\n try {\n const response = await axios.post<ILocalizeResponse>(\n this.endpoints.queryUrl,\n formData,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n const data = response.data;\n if (!data.poseFound) {\n return null;\n }\n\n const result: ILocalizeAndMapDetails = {\n localizeData: data,\n };\n\n if (\n this.config.showMesh &&\n this.config.mapType === 'map' &&\n data.mapCodes?.length\n ) {\n const mapCode = data.mapCodes[0];\n const cached = this.mapDetailsCache[mapCode];\n if (cached) {\n result.mapDetails = cached;\n } else {\n const mapDetails = await this.fetchMapDetails(mapCode);\n if (mapDetails) {\n this.mapDetailsCache[mapCode] = mapDetails;\n result.mapDetails = mapDetails;\n }\n }\n }\n\n return result;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapDetails(mapCode: string): Promise<IGetMapsDetailsResponse | null> {\n try {\n const response = await axios.get<IGetMapsDetailsResponse>(\n `${this.endpoints.mapDetailsUrl}${mapCode}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapSetDetails(mapSetId: string): Promise<IMapSetMapsResponse | null> {\n try {\n const response = await axios.get<IMapSetMapsResponse>(\n `${this.endpoints.mapSetDetailsUrl}${mapSetId}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/core/config.ts","../../src/lib/core/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ILocalizeAndMapDetails, MapType } from './types';\n\n/** The subset of config that is safe to expose publicly (no credentials). */\nexport type IMultisetPublicConfig = Omit<IMultisetSdkConfig, 'clientId' | 'clientSecret'>;\n\nexport interface IMultisetSdkConfig {\n clientId: string;\n clientSecret: string;\n /** Map or map-set code used for localization. */\n code: string;\n /** Map or map-set type ('map' or 'map-set'). */\n mapType: MapType;\n endpoints?: Partial<IMultisetSdkEndpoints>;\n /** If true, show the mesh in the AR session. Default is false. */\n showMesh?: boolean;\n /** If true, show the coordinate gizmo when a pose is found. Defaults to true. */\n showGizmo?: boolean;\n /** If true, automatically start a localization run when the AR session starts. */\n autoLocalize?: boolean;\n /** If true, automatically re-localize when tracking is lost and then recovered. */\n relocalization?: boolean;\n /** When enabled, only accept a localization result if confidence >= confidenceThreshold. */\n confidenceCheck?: boolean;\n /** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */\n confidenceThreshold?: number;\n /** Total single-frame attempts per localization run (1–5). */\n requestAttempts?: number;\n /** Time in seconds between attempts in a localization run (1–5). */\n localizationInterval?: number;\n /** Include device geo pose as a hint in localization requests. */\n passGeoPose?: boolean;\n /** Request geo coordinates in the localization response (if supported by backend). */\n geoCoordinatesInResponse?: boolean;\n /** Max time in ms to wait for a valid viewer pose before failing. Default 10000. */\n localizationTrackingTimeoutMs?: number;\n\n /** Invoked at the start of a localization run. */\n onLocalizationInit?: () => void;\n /** Invoked after a successful localization that meets confidence criteria (if enabled). */\n onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;\n /** Invoked when all attempts fail or the best result is below the confidence threshold. */\n onLocalizationFailure?: (reason?: string) => void;\n\n /** Called after a successful authorization with the access token. */\n onAuthorize?: (token: string) => void;\n /** Called whenever a camera frame is captured and sent for localization. */\n onFrameCaptured?: (payload: IFrameCaptureEvent) => void;\n /** Called with the camera intrinsics used for a localization request. */\n onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;\n /** Called with the raw pose/localization result returned by the backend. */\n onPoseResult?: (payload: IPoseResultEvent) => void;\n /** Called when any error occurs during authorization or localization. */\n onError?: (error: unknown) => void;\n}\n\nexport interface IMultisetSdkEndpoints {\n authUrl: string;\n queryUrl: string;\n mapDetailsUrl: string;\n fileDownloadUrl: string;\n mapSetDetailsUrl: string;\n}\n\nexport interface IFrameCaptureEvent {\n blob: Blob;\n width: number;\n height: number;\n}\n\nexport interface ICameraIntrinsicsEvent {\n fx: number;\n fy: number;\n px: number;\n py: number;\n width: number;\n height: number;\n}\n\nexport interface IPoseResultEvent {\n poseFound: boolean;\n position: {\n x: number;\n y: number;\n z: number;\n };\n rotation: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n mapIds: string[];\n confidence?: number;\n}\n\nexport interface ILocalizeResultEvent {\n frame: IFrameCaptureEvent;\n intrinsics: ICameraIntrinsicsEvent;\n response: ILocalizeAndMapDetails | null;\n}\n\nexport const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints = {\n authUrl: 'https://api.multiset.ai/v1/m2m/token',\n queryUrl: 'https://api.multiset.ai/v1/vps/map/query-form',\n mapDetailsUrl: 'https://api.multiset.ai/v1/vps/map/',\n mapSetDetailsUrl: 'https://api.multiset.ai/v1/vps/map-set/',\n fileDownloadUrl: 'https://api.multiset.ai/v1/file',\n};\n","import axios, { AxiosError } from 'axios';\nimport type {\n IMultisetSdkConfig,\n IMultisetPublicConfig,\n IMultisetSdkEndpoints,\n IFrameCaptureEvent,\n ICameraIntrinsicsEvent,\n} from './config';\nimport { DEFAULT_ENDPOINTS } from './config';\nimport type {\n ILocalizeAndMapDetails,\n ILocalizeResponse,\n IGetMapsDetailsResponse,\n} from './types';\n\nexport class MultisetClient {\n private readonly credentials: { clientId: string; clientSecret: string };\n private readonly config: IMultisetPublicConfig;\n private readonly endpoints: IMultisetSdkEndpoints;\n private accessToken: string | null = null;\n private mapDetailsCache: Record<string, IGetMapsDetailsResponse> = {};\n\n constructor(input: IMultisetSdkConfig) {\n const { clientId, clientSecret, ...rest } = input;\n this.credentials = { clientId, clientSecret };\n this.config = rest;\n this.endpoints = {\n ...DEFAULT_ENDPOINTS,\n ...rest.endpoints,\n };\n }\n\n get token(): string | null {\n return this.accessToken;\n }\n\n getConfig(): IMultisetPublicConfig {\n return this.config;\n }\n\n async downloadFile(key: string): Promise<string> {\n if (!this.accessToken || !key) {\n return '';\n }\n\n try {\n const response = await axios.get<{ url: string }>(\n `${this.endpoints.fileDownloadUrl}?key=${encodeURIComponent(key)}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n return response.status === 200 ? response.data.url : '';\n } catch (error) {\n this.handleError(error);\n return '';\n }\n }\n\n async authorize(): Promise<string> {\n try {\n const response = await axios.post(\n this.endpoints.authUrl,\n {},\n {\n auth: {\n username: this.credentials.clientId,\n password: this.credentials.clientSecret,\n },\n }\n );\n\n const token: string | undefined =\n response.data?.token ?? response.data?.access_token;\n\n if (!token) {\n throw new Error('Authorization succeeded but no token was returned.');\n }\n\n this.accessToken = token;\n this.config.onAuthorize?.(token);\n return token;\n } catch (error) {\n this.handleError(error);\n throw error;\n }\n }\n\n private handleError(error: unknown): void {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n this.config.onError?.(axiosError);\n } else {\n this.config.onError?.(error);\n }\n }\n\n async localizeWithFrame(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n if (!this.accessToken) {\n throw new Error('Access token is missing. Call authorize() first.');\n }\n\n this.config.onFrameCaptured?.(frame);\n this.config.onCameraIntrinsics?.(intrinsics);\n\n const queryResult = await this.queryLocalization(frame, intrinsics);\n\n if (queryResult?.localizeData?.poseFound) {\n this.config.onPoseResult?.(queryResult.localizeData);\n }\n\n return queryResult;\n }\n\n private async getGeoPoseComponents(): Promise<\n { latitude: number, longitude: number, altitude: number } | null\n > {\n if (\n typeof navigator === 'undefined' ||\n !('geolocation' in navigator) ||\n !navigator.geolocation\n ) {\n return null;\n }\n\n try {\n const position = await new Promise<GeolocationPosition>((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(resolve, reject, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: 0,\n });\n });\n\n const { latitude, longitude, altitude } = position.coords;\n const safeAltitude =\n typeof altitude === 'number' && !Number.isNaN(altitude) ? altitude : 0.0;\n\n return { latitude, longitude, altitude: safeAltitude };\n } catch {\n return null;\n }\n }\n\n private async queryLocalization(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n const formData = new FormData();\n\n if (this.config.mapType === 'map') {\n formData.append('mapCode', this.config.code);\n } else {\n formData.append('mapSetCode', this.config.code);\n }\n formData.append('isRightHanded', 'true');\n formData.append('fx', `${intrinsics.fx}`);\n formData.append('fy', `${intrinsics.fy}`);\n formData.append('px', `${intrinsics.px}`);\n formData.append('py', `${intrinsics.py}`);\n formData.append('width', `${frame.width}`);\n formData.append('height', `${frame.height}`);\n formData.append('queryImage', frame.blob);\n if (this.config.geoCoordinatesInResponse) {\n formData.append('geoCoordinatesInResponse', 'true');\n }\n if (this.config.passGeoPose) {\n const components = await this.getGeoPoseComponents();\n if (components) {\n const { latitude, longitude, altitude } = components;\n const geoHint = `${latitude},${longitude},${altitude}`;\n formData.append('geoHint', geoHint);\n }\n }\n\n try {\n const response = await axios.post<ILocalizeResponse>(\n this.endpoints.queryUrl,\n formData,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n const data = response.data;\n if (!data.poseFound) {\n return null;\n }\n\n const result: ILocalizeAndMapDetails = {\n localizeData: data,\n };\n\n if (\n this.config.showMesh &&\n data.mapCodes?.length\n ) {\n const mapCode = data.mapCodes[0];\n const cached = this.mapDetailsCache[mapCode];\n if (cached) {\n result.mapDetails = cached;\n } else {\n const mapDetails = await this.fetchMapDetails(mapCode);\n if (mapDetails) {\n this.mapDetailsCache[mapCode] = mapDetails;\n result.mapDetails = mapDetails;\n }\n }\n }\n\n return result;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapDetails(mapCode: string): Promise<IGetMapsDetailsResponse | null> {\n try {\n const response = await axios.get<IGetMapsDetailsResponse>(\n `${this.endpoints.mapDetailsUrl}${mapCode}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as THREE3 from 'three';
|
|
|
3
3
|
import { ARButton } from 'three/examples/jsm/webxr/ARButton.js';
|
|
4
4
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
5
5
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
6
|
+
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
|
6
7
|
|
|
7
8
|
// src/lib/core/config.ts
|
|
8
9
|
var DEFAULT_ENDPOINTS = {
|
|
@@ -50,7 +51,6 @@ var MultisetClient = class {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
async authorize() {
|
|
53
|
-
var _a, _b, _c, _d, _e;
|
|
54
54
|
try {
|
|
55
55
|
const response = await axios.post(
|
|
56
56
|
this.endpoints.authUrl,
|
|
@@ -62,12 +62,12 @@ var MultisetClient = class {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
);
|
|
65
|
-
const token =
|
|
65
|
+
const token = response.data?.token ?? response.data?.access_token;
|
|
66
66
|
if (!token) {
|
|
67
67
|
throw new Error("Authorization succeeded but no token was returned.");
|
|
68
68
|
}
|
|
69
69
|
this.accessToken = token;
|
|
70
|
-
|
|
70
|
+
this.config.onAuthorize?.(token);
|
|
71
71
|
return token;
|
|
72
72
|
} catch (error) {
|
|
73
73
|
this.handleError(error);
|
|
@@ -75,24 +75,22 @@ var MultisetClient = class {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
handleError(error) {
|
|
78
|
-
var _a, _b, _c, _d;
|
|
79
78
|
if (axios.isAxiosError(error)) {
|
|
80
79
|
const axiosError = error;
|
|
81
|
-
|
|
80
|
+
this.config.onError?.(axiosError);
|
|
82
81
|
} else {
|
|
83
|
-
|
|
82
|
+
this.config.onError?.(error);
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
85
|
async localizeWithFrame(frame, intrinsics) {
|
|
87
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
88
86
|
if (!this.accessToken) {
|
|
89
87
|
throw new Error("Access token is missing. Call authorize() first.");
|
|
90
88
|
}
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
this.config.onFrameCaptured?.(frame);
|
|
90
|
+
this.config.onCameraIntrinsics?.(intrinsics);
|
|
93
91
|
const queryResult = await this.queryLocalization(frame, intrinsics);
|
|
94
|
-
if (
|
|
95
|
-
|
|
92
|
+
if (queryResult?.localizeData?.poseFound) {
|
|
93
|
+
this.config.onPoseResult?.(queryResult.localizeData);
|
|
96
94
|
}
|
|
97
95
|
return queryResult;
|
|
98
96
|
}
|
|
@@ -116,7 +114,6 @@ var MultisetClient = class {
|
|
|
116
114
|
}
|
|
117
115
|
}
|
|
118
116
|
async queryLocalization(frame, intrinsics) {
|
|
119
|
-
var _a;
|
|
120
117
|
const formData = new FormData();
|
|
121
118
|
if (this.config.mapType === "map") {
|
|
122
119
|
formData.append("mapCode", this.config.code);
|
|
@@ -159,7 +156,7 @@ var MultisetClient = class {
|
|
|
159
156
|
const result = {
|
|
160
157
|
localizeData: data
|
|
161
158
|
};
|
|
162
|
-
if (this.config.showMesh &&
|
|
159
|
+
if (this.config.showMesh && data.mapCodes?.length) {
|
|
163
160
|
const mapCode = data.mapCodes[0];
|
|
164
161
|
const cached = this.mapDetailsCache[mapCode];
|
|
165
162
|
if (cached) {
|
|
@@ -194,22 +191,6 @@ var MultisetClient = class {
|
|
|
194
191
|
return null;
|
|
195
192
|
}
|
|
196
193
|
}
|
|
197
|
-
async fetchMapSetDetails(mapSetId) {
|
|
198
|
-
try {
|
|
199
|
-
const response = await axios.get(
|
|
200
|
-
`${this.endpoints.mapSetDetailsUrl}${mapSetId}`,
|
|
201
|
-
{
|
|
202
|
-
headers: {
|
|
203
|
-
Authorization: `Bearer ${this.accessToken}`
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
);
|
|
207
|
-
return response.data;
|
|
208
|
-
} catch (error) {
|
|
209
|
-
this.handleError(error);
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
194
|
};
|
|
214
195
|
|
|
215
196
|
// src/lib/webxr/internal/cameraIntrinsics.ts
|
|
@@ -239,7 +220,7 @@ async function compressToJpeg(buffer, width, height, quality = 0.8) {
|
|
|
239
220
|
const imageData = new ImageData(new Uint8ClampedArray(buffer), width, height);
|
|
240
221
|
ctx.putImageData(imageData, 0, 0);
|
|
241
222
|
return new Promise((resolve) => {
|
|
242
|
-
canvas.toBlob((blob) => resolve(blob
|
|
223
|
+
canvas.toBlob((blob) => resolve(blob ?? new Blob()), "image/jpeg", quality);
|
|
243
224
|
});
|
|
244
225
|
}
|
|
245
226
|
async function getCameraTextureAsImage(renderer, webGLTexture, width, height) {
|
|
@@ -425,21 +406,20 @@ void main() {
|
|
|
425
406
|
}
|
|
426
407
|
`;
|
|
427
408
|
function createGridMaterial(options = {}) {
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
const
|
|
431
|
-
const
|
|
432
|
-
const
|
|
433
|
-
const
|
|
434
|
-
const
|
|
435
|
-
const
|
|
436
|
-
const
|
|
437
|
-
const
|
|
438
|
-
const
|
|
439
|
-
const
|
|
440
|
-
const
|
|
441
|
-
const
|
|
442
|
-
const lightDirection = (_n = options.lightDirection) != null ? _n : new THREE3.Vector3(0.3, 1, 0.3).normalize();
|
|
409
|
+
const color = options.color ?? "#7B2CBF";
|
|
410
|
+
const opacity = options.opacity ?? 150 / 255;
|
|
411
|
+
const gridColor = options.gridColor ?? "#ffeb3b";
|
|
412
|
+
const gridScale = options.gridScale ?? 2;
|
|
413
|
+
const gridLineWidth = options.gridLineWidth ?? 0.02;
|
|
414
|
+
const showGrid = options.showGrid ?? 1;
|
|
415
|
+
const center = options.center ?? new THREE3.Vector3(0, 0, 0);
|
|
416
|
+
const radius = options.radius ?? 1;
|
|
417
|
+
const progress = options.progress ?? 1;
|
|
418
|
+
const glowColor = options.glowColor ?? "#FF3A00";
|
|
419
|
+
const glowWidth = options.glowWidth ?? 0.05;
|
|
420
|
+
const glowIntensity = options.glowIntensity ?? 2;
|
|
421
|
+
const lightColor = options.lightColor ?? "#ffffff";
|
|
422
|
+
const lightDirection = options.lightDirection ?? new THREE3.Vector3(0.3, 1, 0.3).normalize();
|
|
443
423
|
return new THREE3.ShaderMaterial({
|
|
444
424
|
vertexShader: VERTEX,
|
|
445
425
|
fragmentShader: FRAGMENT,
|
|
@@ -473,9 +453,13 @@ function createGridMaterial(options = {}) {
|
|
|
473
453
|
// src/lib/webxr/mapMeshVisualizer.ts
|
|
474
454
|
var LARGE_MAP_THRESHOLD = 50;
|
|
475
455
|
var MapMeshVisualizer = class {
|
|
476
|
-
constructor(scene, client) {
|
|
456
|
+
constructor(scene, client, renderer, camera) {
|
|
477
457
|
this.scene = scene;
|
|
478
458
|
this.client = client;
|
|
459
|
+
this.renderer = renderer;
|
|
460
|
+
this.camera = camera;
|
|
461
|
+
this.gizmoControl = null;
|
|
462
|
+
this.gizmoHelper = null;
|
|
479
463
|
this.meshMaterial = null;
|
|
480
464
|
this.localCenter = new THREE3.Vector3();
|
|
481
465
|
this.localRadius = 0;
|
|
@@ -497,12 +481,29 @@ var MapMeshVisualizer = class {
|
|
|
497
481
|
getMeshGroup() {
|
|
498
482
|
return this.meshGroup;
|
|
499
483
|
}
|
|
484
|
+
async ensureGizmoLoaded() {
|
|
485
|
+
const cfg = this.client.getConfig();
|
|
486
|
+
if (cfg.showGizmo === false) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (!this.gizmoControl) {
|
|
490
|
+
const gizmo = new TransformControls(this.camera, this.renderer.domElement);
|
|
491
|
+
gizmo.setMode("translate");
|
|
492
|
+
gizmo.setSpace("local");
|
|
493
|
+
gizmo.enabled = false;
|
|
494
|
+
const helper = gizmo.getHelper();
|
|
495
|
+
this.scene.add(helper);
|
|
496
|
+
gizmo.attach(this.meshGroup);
|
|
497
|
+
this.gizmoControl = gizmo;
|
|
498
|
+
this.gizmoHelper = helper;
|
|
499
|
+
}
|
|
500
|
+
this.gizmoHelper.visible = true;
|
|
501
|
+
}
|
|
500
502
|
async ensureMeshLoaded(mapDetails) {
|
|
501
|
-
var _a, _b;
|
|
502
503
|
if (this.scene.getObjectByName(mapDetails._id)) {
|
|
503
504
|
return;
|
|
504
505
|
}
|
|
505
|
-
const meshKey =
|
|
506
|
+
const meshKey = mapDetails.mapMesh?.rawMesh?.meshLink;
|
|
506
507
|
if (!meshKey) {
|
|
507
508
|
return;
|
|
508
509
|
}
|
|
@@ -525,7 +526,7 @@ var MapMeshVisualizer = class {
|
|
|
525
526
|
this.localRadius = Math.max(size / 2, 1e-3);
|
|
526
527
|
const meshMaterial = createGridMaterial({
|
|
527
528
|
color: "#7B2CBF",
|
|
528
|
-
opacity: 0.
|
|
529
|
+
opacity: 0.58,
|
|
529
530
|
gridColor: "#ffeb3b",
|
|
530
531
|
gridScale: 2,
|
|
531
532
|
gridLineWidth: 0.02,
|
|
@@ -533,7 +534,7 @@ var MapMeshVisualizer = class {
|
|
|
533
534
|
center: this.localCenter.clone(),
|
|
534
535
|
radius: this.localRadius,
|
|
535
536
|
progress: 0,
|
|
536
|
-
glowColor: "#
|
|
537
|
+
glowColor: "#FF3A00",
|
|
537
538
|
glowWidth: 0.05,
|
|
538
539
|
glowIntensity: 2
|
|
539
540
|
});
|
|
@@ -586,7 +587,6 @@ var MapMeshVisualizer = class {
|
|
|
586
587
|
}
|
|
587
588
|
}
|
|
588
589
|
update(deltaSeconds, viewerWorldPosition) {
|
|
589
|
-
var _a;
|
|
590
590
|
if (!this.meshMaterial) {
|
|
591
591
|
return;
|
|
592
592
|
}
|
|
@@ -597,7 +597,7 @@ var MapMeshVisualizer = class {
|
|
|
597
597
|
if (!uniforms.uProgress) {
|
|
598
598
|
return;
|
|
599
599
|
}
|
|
600
|
-
const current =
|
|
600
|
+
const current = uniforms.uProgress.value ?? 0;
|
|
601
601
|
if (current === 0 && uniforms.uCenter && this.lastViewerWorldPosition.lengthSq() > 0) {
|
|
602
602
|
uniforms.uCenter.value.copy(this.lastViewerWorldPosition);
|
|
603
603
|
}
|
|
@@ -631,13 +631,22 @@ var MapMeshVisualizer = class {
|
|
|
631
631
|
});
|
|
632
632
|
this.scene.remove(this.meshGroup);
|
|
633
633
|
this.dracoLoader.dispose();
|
|
634
|
+
if (this.gizmoHelper) {
|
|
635
|
+
this.scene.remove(this.gizmoHelper);
|
|
636
|
+
}
|
|
637
|
+
if (this.gizmoControl) {
|
|
638
|
+
this.gizmoControl.dispose();
|
|
639
|
+
}
|
|
634
640
|
}
|
|
635
641
|
};
|
|
636
642
|
|
|
637
643
|
// src/lib/webxr/world/World.ts
|
|
638
644
|
var World = class {
|
|
639
|
-
constructor(scene, client) {
|
|
640
|
-
this.meshVisualizer = new MapMeshVisualizer(scene, client);
|
|
645
|
+
constructor(scene, client, renderer, camera) {
|
|
646
|
+
this.meshVisualizer = new MapMeshVisualizer(scene, client, renderer, camera);
|
|
647
|
+
}
|
|
648
|
+
async ensureGizmoLoaded() {
|
|
649
|
+
await this.meshVisualizer.ensureGizmoLoaded();
|
|
641
650
|
}
|
|
642
651
|
async ensureMeshLoaded(mapDetails) {
|
|
643
652
|
await this.meshVisualizer.ensureMeshLoaded(mapDetails);
|
|
@@ -674,23 +683,21 @@ var WebxrController = class {
|
|
|
674
683
|
this.trackerSpace = null;
|
|
675
684
|
}
|
|
676
685
|
async initialize(buttonContainer) {
|
|
677
|
-
var _a, _b, _c, _d;
|
|
678
686
|
if (this.experience) {
|
|
679
687
|
return this.arButton;
|
|
680
688
|
}
|
|
681
689
|
if (!window.isSecureContext) {
|
|
682
690
|
throw new Error("WebXR requires a secure context (HTTPS).");
|
|
683
691
|
}
|
|
684
|
-
const canvas =
|
|
692
|
+
const canvas = this.options.canvas ?? document.createElement("canvas");
|
|
685
693
|
this.experience = new Experience(canvas);
|
|
686
|
-
this.world = new World(this.experience.getScene(), this.options.client);
|
|
687
694
|
const renderer = this.experience.getRenderer();
|
|
688
695
|
const camera = this.experience.getCamera();
|
|
689
696
|
const scene = this.experience.getScene();
|
|
697
|
+
this.world = new World(scene, this.options.client, renderer, camera);
|
|
690
698
|
renderer.xr.addEventListener("sessionstart", () => {
|
|
691
|
-
var _a2, _b2;
|
|
692
699
|
this.isSessionActive = true;
|
|
693
|
-
|
|
700
|
+
this.options.onSessionStart?.();
|
|
694
701
|
const cfg = this.options.client.getConfig();
|
|
695
702
|
if (cfg.autoLocalize) {
|
|
696
703
|
const session = renderer.xr.getSession();
|
|
@@ -704,9 +711,8 @@ var WebxrController = class {
|
|
|
704
711
|
}
|
|
705
712
|
});
|
|
706
713
|
renderer.xr.addEventListener("sessionend", () => {
|
|
707
|
-
var _a2, _b2;
|
|
708
714
|
this.isSessionActive = false;
|
|
709
|
-
|
|
715
|
+
this.options.onSessionEnd?.();
|
|
710
716
|
});
|
|
711
717
|
let lastTime = 0;
|
|
712
718
|
const animationLoop = (time, frame) => {
|
|
@@ -751,11 +757,10 @@ var WebxrController = class {
|
|
|
751
757
|
};
|
|
752
758
|
renderer.setAnimationLoop(animationLoop);
|
|
753
759
|
const resizeHandler = () => {
|
|
754
|
-
|
|
755
|
-
(_a2 = this.experience) == null ? void 0 : _a2.resize();
|
|
760
|
+
this.experience?.resize();
|
|
756
761
|
};
|
|
757
762
|
window.addEventListener("resize", resizeHandler);
|
|
758
|
-
const overlayRoot =
|
|
763
|
+
const overlayRoot = this.options.overlayRoot ?? document.body;
|
|
759
764
|
const arButton = ARButton.createButton(renderer, {
|
|
760
765
|
requiredFeatures: ["camera-access", "dom-overlay"],
|
|
761
766
|
domOverlay: { root: overlayRoot }
|
|
@@ -766,7 +771,7 @@ var WebxrController = class {
|
|
|
766
771
|
}
|
|
767
772
|
this.arButton = arButton;
|
|
768
773
|
this.resizeHandler = resizeHandler;
|
|
769
|
-
|
|
774
|
+
this.options.onARButtonCreated?.(arButton);
|
|
770
775
|
return arButton;
|
|
771
776
|
}
|
|
772
777
|
getScene() {
|
|
@@ -788,8 +793,7 @@ var WebxrController = class {
|
|
|
788
793
|
return this.experience.getRenderer();
|
|
789
794
|
}
|
|
790
795
|
hasActiveSession() {
|
|
791
|
-
|
|
792
|
-
return this.isSessionActive && ((_a = this.experience) == null ? void 0 : _a.getRenderer().xr.isPresenting) === true;
|
|
796
|
+
return this.isSessionActive && this.experience?.getRenderer().xr.isPresenting === true;
|
|
793
797
|
}
|
|
794
798
|
/**
|
|
795
799
|
* Runs a single-frame localization: captures one frame, evaluates the result
|
|
@@ -798,24 +802,23 @@ var WebxrController = class {
|
|
|
798
802
|
* Aligns with Unity SingleFrameLocalizationManager.LocalizeFrame().
|
|
799
803
|
*/
|
|
800
804
|
async localizeFrame() {
|
|
801
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
802
805
|
if (!this.experience) {
|
|
803
806
|
throw new Error("WebXR: WebXR controller has not been initialized.");
|
|
804
807
|
}
|
|
805
808
|
const renderer = this.experience.getRenderer();
|
|
806
|
-
const session =
|
|
809
|
+
const session = renderer.xr.getSession?.();
|
|
807
810
|
if (!session) {
|
|
808
811
|
throw new Error(
|
|
809
812
|
"WebXR Session: No active WebXR session. Start AR before calling localizeFrame()."
|
|
810
813
|
);
|
|
811
814
|
}
|
|
812
815
|
const cfg = this.options.client.getConfig();
|
|
813
|
-
const confidenceCheck =
|
|
816
|
+
const confidenceCheck = cfg.confidenceCheck ?? false;
|
|
814
817
|
const confidenceThreshold = Math.max(
|
|
815
818
|
CONFIDENCE_THRESHOLD_MIN,
|
|
816
|
-
Math.min(
|
|
819
|
+
Math.min(cfg.confidenceThreshold ?? 0.5, CONFIDENCE_THRESHOLD_MAX)
|
|
817
820
|
);
|
|
818
|
-
|
|
821
|
+
cfg.onLocalizationInit?.();
|
|
819
822
|
this.isLocalizing = true;
|
|
820
823
|
let best = null;
|
|
821
824
|
let failureReason;
|
|
@@ -826,20 +829,27 @@ var WebxrController = class {
|
|
|
826
829
|
} finally {
|
|
827
830
|
this.isLocalizing = false;
|
|
828
831
|
}
|
|
829
|
-
const accepted = best && (!confidenceCheck || (
|
|
832
|
+
const accepted = best && (!confidenceCheck || (best.localizeData.confidence ?? 0) >= confidenceThreshold);
|
|
830
833
|
if (accepted && best) {
|
|
831
|
-
|
|
832
|
-
if (
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
834
|
+
cfg.onLocalizationSuccess?.(best);
|
|
835
|
+
if (this.world && this.trackerSpace) {
|
|
836
|
+
const willShowMesh = cfg.showMesh && !!best.mapDetails;
|
|
837
|
+
const willShowGizmo = cfg.showGizmo !== false;
|
|
838
|
+
if (willShowMesh || willShowGizmo) {
|
|
839
|
+
try {
|
|
840
|
+
await this.world.ensureGizmoLoaded();
|
|
841
|
+
if (willShowMesh) {
|
|
842
|
+
await this.world.ensureMeshLoaded(best.mapDetails);
|
|
843
|
+
}
|
|
844
|
+
this.world.applyMeshTransform(best, this.trackerSpace);
|
|
845
|
+
} catch {
|
|
846
|
+
}
|
|
837
847
|
}
|
|
838
848
|
}
|
|
839
849
|
return best;
|
|
840
850
|
}
|
|
841
|
-
const reason = failureReason
|
|
842
|
-
|
|
851
|
+
const reason = failureReason ?? (!best ? "All attempts failed to produce a pose." : confidenceCheck ? `Best confidence ${best.localizeData.confidence ?? 0} below threshold ${confidenceThreshold}.` : void 0);
|
|
852
|
+
cfg.onLocalizationFailure?.(reason);
|
|
843
853
|
return null;
|
|
844
854
|
}
|
|
845
855
|
/**
|
|
@@ -849,12 +859,11 @@ var WebxrController = class {
|
|
|
849
859
|
* result, apiCalled, and an optional failureReason for onLocalizationFailure.
|
|
850
860
|
*/
|
|
851
861
|
async captureFrame() {
|
|
852
|
-
var _a, _b, _c;
|
|
853
862
|
if (!this.experience) {
|
|
854
863
|
throw new Error("WebXR: WebXR controller has not been initialized.");
|
|
855
864
|
}
|
|
856
865
|
const renderer = this.experience.getRenderer();
|
|
857
|
-
const session =
|
|
866
|
+
const session = renderer.xr.getSession?.();
|
|
858
867
|
if (!session) {
|
|
859
868
|
throw new Error(
|
|
860
869
|
"WebXR Session: No active WebXR session. Start AR before capturing."
|
|
@@ -868,12 +877,11 @@ var WebxrController = class {
|
|
|
868
877
|
}
|
|
869
878
|
const gl = renderer.getContext();
|
|
870
879
|
const cfg = this.options.client.getConfig();
|
|
871
|
-
const timeoutMs =
|
|
880
|
+
const timeoutMs = cfg.localizationTrackingTimeoutMs ?? DEFAULT_TRACKING_TIMEOUT_MS;
|
|
872
881
|
return new Promise((resolve, reject) => {
|
|
873
882
|
const startTime = Date.now();
|
|
874
883
|
const tryFrame = (attempt, cameraAttemptsWithPose) => {
|
|
875
884
|
session.requestAnimationFrame(async (_time, xrFrame) => {
|
|
876
|
-
var _a2, _b2, _c2, _d;
|
|
877
885
|
try {
|
|
878
886
|
const elapsed = Date.now() - startTime;
|
|
879
887
|
const viewerPose = xrFrame.getViewerPose(referenceSpace);
|
|
@@ -898,7 +906,7 @@ var WebxrController = class {
|
|
|
898
906
|
const gl2 = gl;
|
|
899
907
|
const bindingCtor = XRWebGLBinding;
|
|
900
908
|
const binding = new bindingCtor(session, gl2);
|
|
901
|
-
const cameraTexture =
|
|
909
|
+
const cameraTexture = binding.getCameraImage?.(xrCamera) ?? null;
|
|
902
910
|
if (!cameraTexture) continue;
|
|
903
911
|
const width = xrCamera.width;
|
|
904
912
|
const height = xrCamera.height;
|
|
@@ -939,7 +947,7 @@ var WebxrController = class {
|
|
|
939
947
|
} finally {
|
|
940
948
|
gl.bindFramebuffer(
|
|
941
949
|
gl.FRAMEBUFFER,
|
|
942
|
-
|
|
950
|
+
session.renderState.baseLayer?.framebuffer ?? null
|
|
943
951
|
);
|
|
944
952
|
}
|
|
945
953
|
});
|
|
@@ -948,18 +956,17 @@ var WebxrController = class {
|
|
|
948
956
|
});
|
|
949
957
|
}
|
|
950
958
|
dispose() {
|
|
951
|
-
var _a, _b, _c, _d;
|
|
952
959
|
if (this.resizeHandler) {
|
|
953
960
|
window.removeEventListener("resize", this.resizeHandler);
|
|
954
961
|
}
|
|
955
|
-
|
|
956
|
-
|
|
962
|
+
this.experience?.getRenderer().setAnimationLoop(null);
|
|
963
|
+
this.experience?.dispose();
|
|
957
964
|
this.experience = null;
|
|
958
|
-
|
|
965
|
+
this.world?.dispose();
|
|
959
966
|
this.world = null;
|
|
960
967
|
this.trackingLossFrames = 0;
|
|
961
968
|
this.hadTrackingLoss = false;
|
|
962
|
-
if (
|
|
969
|
+
if (this.arButton?.parentElement) {
|
|
963
970
|
this.arButton.parentElement.removeChild(this.arButton);
|
|
964
971
|
}
|
|
965
972
|
this.arButton = null;
|