mirror of
https://github.com/mapillary/mapillary-js.git
synced 2026-01-18 13:56:53 +00:00
feat(spatial): remove references to atomic reconstructions
This commit is contained in:
parent
518c3d500a
commit
7ee9d1ff48
@ -2,7 +2,7 @@ import * as geohash from "latlon-geohash";
|
||||
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
import {SpatialDataCache, ReconstructionData} from "../../../src/Component";
|
||||
import {SpatialDataCache} from "../../../src/Component";
|
||||
import {
|
||||
GraphService,
|
||||
Node,
|
||||
@ -180,6 +180,7 @@ describe("SpatialDataCache.cacheReconstructions$", () => {
|
||||
expect(cache.hasTile(hash)).toBe(true);
|
||||
};
|
||||
|
||||
/*
|
||||
it("should cache a reconstruction", (done: Function) => {
|
||||
const graphService: GraphService = new GraphServiceMockCreator().create();
|
||||
const cache: SpatialDataCache = new SpatialDataCache(graphService);
|
||||
@ -339,4 +340,5 @@ describe("SpatialDataCache.cacheReconstructions$", () => {
|
||||
expect(cache.isCachingReconstructions(hash)).toBe(false);
|
||||
expect(cache.hasReconstructions(hash)).toBe(true);
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
@ -45,7 +45,7 @@ export {RouteComponent} from "./component/RouteComponent";
|
||||
export {SequenceComponent} from "./component/sequence/SequenceComponent";
|
||||
export {SequenceDOMRenderer} from "./component/sequence/SequenceDOMRenderer";
|
||||
export {SequenceMode} from "./component/sequence/SequenceMode";
|
||||
export {NodeData, ReconstructionData, SpatialDataCache} from "./component/spatialdata/SpatialDataCache";
|
||||
export {NodeData, SpatialDataCache} from "./component/spatialdata/SpatialDataCache";
|
||||
export {SpatialDataComponent} from "./component/spatialdata/SpatialDataComponent";
|
||||
export {SpatialDataScene} from "./component/spatialdata/SpatialDataScene";
|
||||
export {ImagePlaneComponent} from "./component/imageplane/ImagePlaneComponent";
|
||||
|
||||
@ -25,9 +25,6 @@ import {
|
||||
IGPano,
|
||||
ILatLon,
|
||||
} from "../../API";
|
||||
import {
|
||||
IReconstruction,
|
||||
} from "../../Component";
|
||||
import {
|
||||
AbortMapillaryError,
|
||||
} from "../../Error";
|
||||
@ -62,24 +59,17 @@ export type NodeData = {
|
||||
width: number;
|
||||
};
|
||||
|
||||
export type ReconstructionData = {
|
||||
data: NodeData,
|
||||
reconstruction: IReconstruction,
|
||||
};
|
||||
|
||||
export class SpatialDataCache {
|
||||
private _graphService: GraphService;
|
||||
|
||||
private _cacheRequests: { [hash: string]: XMLHttpRequest[] };
|
||||
private _reconstructions: { [hash: string]: ReconstructionData[] };
|
||||
private _tiles: { [hash: string]: NodeData[] };
|
||||
|
||||
private _clusterReconstructions: { [key: string]: IClusterReconstruction };
|
||||
private _tileClusters: { [hash: string]: string[] };
|
||||
private _clusterReconstructionTiles: { [key: string]: string[] };
|
||||
private _tileClusters: { [hash: string]: string[] };
|
||||
|
||||
private _cachingClusterReconstructions$: { [hash: string]: Observable<IClusterReconstruction> };
|
||||
private _cachingReconstructions$: { [hash: string]: Observable<ReconstructionData> };
|
||||
private _cachingTiles$: { [hash: string]: Observable<NodeData[]> };
|
||||
|
||||
constructor(graphService: GraphService) {
|
||||
@ -87,15 +77,12 @@ export class SpatialDataCache {
|
||||
|
||||
this._tiles = {};
|
||||
this._cacheRequests = {};
|
||||
this._reconstructions = {};
|
||||
|
||||
this._clusterReconstructions = {};
|
||||
this._tileClusters = {};
|
||||
this._clusterReconstructionTiles = {};
|
||||
this._tileClusters = {};
|
||||
|
||||
this._cachingReconstructions$ = {};
|
||||
this._cachingTiles$ = {};
|
||||
|
||||
this._cachingClusterReconstructions$ = {};
|
||||
}
|
||||
|
||||
@ -104,11 +91,11 @@ export class SpatialDataCache {
|
||||
throw new Error("Cannot cache reconstructions of a non-existing tile.");
|
||||
}
|
||||
|
||||
if (this.hasReconstructions(hash)) {
|
||||
if (this.hasClusterReconstructions(hash)) {
|
||||
throw new Error("Cannot cache reconstructions that already exists.");
|
||||
}
|
||||
|
||||
if (this.isCachingReconstructions(hash)) {
|
||||
if (this.isCachingClusterReconstructions(hash)) {
|
||||
return this._cachingClusterReconstructions$[hash];
|
||||
}
|
||||
|
||||
@ -183,94 +170,6 @@ export class SpatialDataCache {
|
||||
return this._cachingClusterReconstructions$[hash];
|
||||
}
|
||||
|
||||
public cacheReconstructions$(hash: string): Observable<ReconstructionData> {
|
||||
if (!this.hasTile(hash)) {
|
||||
throw new Error("Cannot cache reconstructions of a non-existing tile.");
|
||||
}
|
||||
|
||||
if (this.hasReconstructions(hash)) {
|
||||
throw new Error("Cannot cache reconstructions that already exists.");
|
||||
}
|
||||
|
||||
if (this.isCachingReconstructions(hash)) {
|
||||
return this._cachingReconstructions$[hash];
|
||||
}
|
||||
|
||||
const tile: NodeData[] = [];
|
||||
|
||||
if (hash in this._reconstructions) {
|
||||
const reconstructionKeys: string[] =
|
||||
this.getReconstructions(hash)
|
||||
.map(
|
||||
(reconstruction: ReconstructionData): string => {
|
||||
return reconstruction.data.key;
|
||||
});
|
||||
|
||||
for (const node of this.getTile(hash)) {
|
||||
if (reconstructionKeys.indexOf(node.key) === -1) {
|
||||
tile.push(node);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tile.push(...this.getTile(hash));
|
||||
|
||||
this._reconstructions[hash] = [];
|
||||
}
|
||||
|
||||
this._cacheRequests[hash] = [];
|
||||
this._cachingReconstructions$[hash] = observableFrom(tile).pipe(
|
||||
mergeMap(
|
||||
(nodeData: NodeData): Observable<[NodeData, IReconstruction]> => {
|
||||
return !this._cacheRequests[hash] ?
|
||||
observableEmpty() :
|
||||
observableZip(
|
||||
observableOf(nodeData),
|
||||
this._getAtomicReconstruction(nodeData.key, this._cacheRequests[hash]))
|
||||
.pipe(
|
||||
catchError(
|
||||
(error: Error): Observable<[NodeData, IReconstruction]> => {
|
||||
if (error instanceof AbortMapillaryError) {
|
||||
return observableEmpty();
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
|
||||
return observableOf(<[NodeData, IReconstruction]>[nodeData, null]);
|
||||
}));
|
||||
},
|
||||
6),
|
||||
map(
|
||||
([nodeData, reconstruction]: [NodeData, IReconstruction]): ReconstructionData => {
|
||||
return { data: nodeData, reconstruction: reconstruction };
|
||||
}),
|
||||
filter(
|
||||
(): boolean => {
|
||||
return hash in this._reconstructions;
|
||||
}),
|
||||
tap(
|
||||
(data: ReconstructionData): void => {
|
||||
this._reconstructions[hash].push(data);
|
||||
}),
|
||||
filter(
|
||||
(data: ReconstructionData): boolean => {
|
||||
return !!data.reconstruction;
|
||||
}),
|
||||
finalize(
|
||||
(): void => {
|
||||
if (hash in this._cachingReconstructions$) {
|
||||
delete this._cachingReconstructions$[hash];
|
||||
}
|
||||
|
||||
if (hash in this._cacheRequests) {
|
||||
delete this._cacheRequests[hash];
|
||||
}
|
||||
}),
|
||||
publish(),
|
||||
refCount());
|
||||
|
||||
return this._cachingReconstructions$[hash];
|
||||
}
|
||||
|
||||
public cacheTile$(hash: string): Observable<NodeData[]> {
|
||||
if (hash.length !== 8) {
|
||||
throw new Error("Hash needs to be level 8.");
|
||||
@ -333,10 +232,6 @@ export class SpatialDataCache {
|
||||
return hash in this._cachingClusterReconstructions$;
|
||||
}
|
||||
|
||||
public isCachingReconstructions(hash: string): boolean {
|
||||
return hash in this._cachingReconstructions$;
|
||||
}
|
||||
|
||||
public isCachingTile(hash: string): boolean {
|
||||
return hash in this._cachingTiles$;
|
||||
}
|
||||
@ -356,12 +251,6 @@ export class SpatialDataCache {
|
||||
return true;
|
||||
}
|
||||
|
||||
public hasReconstructions(hash: string): boolean {
|
||||
return !(hash in this._cachingReconstructions$) &&
|
||||
hash in this._reconstructions &&
|
||||
this._reconstructions[hash].length === this._tiles[hash].length;
|
||||
}
|
||||
|
||||
public hasTile(hash: string): boolean {
|
||||
return !(hash in this._cachingTiles$) && hash in this._tiles;
|
||||
}
|
||||
@ -375,16 +264,6 @@ export class SpatialDataCache {
|
||||
[];
|
||||
}
|
||||
|
||||
public getReconstructions(hash: string): ReconstructionData[] {
|
||||
return hash in this._reconstructions ?
|
||||
this._reconstructions[hash]
|
||||
.filter(
|
||||
(data: ReconstructionData): boolean => {
|
||||
return !!data.reconstruction;
|
||||
}) :
|
||||
[];
|
||||
}
|
||||
|
||||
public getTile(hash: string): NodeData[] {
|
||||
return hash in this._tiles ? this._tiles[hash] : [];
|
||||
}
|
||||
@ -402,14 +281,6 @@ export class SpatialDataCache {
|
||||
delete this._cacheRequests[hash];
|
||||
}
|
||||
|
||||
for (let hash of Object.keys(this._reconstructions)) {
|
||||
if (!!keepHashes && keepHashes.indexOf(hash) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
delete this._reconstructions[hash];
|
||||
}
|
||||
|
||||
for (let hash of Object.keys(this._tileClusters)) {
|
||||
if (!!keepHashes && keepHashes.indexOf(hash) !== -1) {
|
||||
continue;
|
||||
@ -470,42 +341,6 @@ export class SpatialDataCache {
|
||||
};
|
||||
}
|
||||
|
||||
private _getAtomicReconstruction(key: string, requests: XMLHttpRequest[]): Observable<IReconstruction> {
|
||||
return Observable.create(
|
||||
(subscriber: Subscriber<IReconstruction>): void => {
|
||||
const xmlHTTP: XMLHttpRequest = new XMLHttpRequest();
|
||||
|
||||
xmlHTTP.open("GET", Urls.atomicReconstruction(key), true);
|
||||
xmlHTTP.responseType = "json";
|
||||
xmlHTTP.timeout = 15000;
|
||||
|
||||
xmlHTTP.onload = () => {
|
||||
if (!xmlHTTP.response) {
|
||||
subscriber.error(new Error(`Atomic reconstruction does not exist (${key})`));
|
||||
} else {
|
||||
subscriber.next(xmlHTTP.response);
|
||||
subscriber.complete();
|
||||
}
|
||||
};
|
||||
|
||||
xmlHTTP.onerror = () => {
|
||||
subscriber.error(new Error(`Failed to get atomic reconstruction (${key})`));
|
||||
};
|
||||
|
||||
xmlHTTP.ontimeout = () => {
|
||||
subscriber.error(new Error(`Atomic reconstruction request timed out (${key})`));
|
||||
};
|
||||
|
||||
xmlHTTP.onabort = () => {
|
||||
subscriber.error(new AbortMapillaryError(`Atomic reconstruction request was aborted (${key})`));
|
||||
};
|
||||
|
||||
requests.push(xmlHTTP);
|
||||
|
||||
xmlHTTP.send(null);
|
||||
});
|
||||
}
|
||||
|
||||
private _getClusterReconstruction(key: string): IClusterReconstruction {
|
||||
return this._clusterReconstructions[key];
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import * as THREE from "three";
|
||||
|
||||
import {
|
||||
IReconstruction,
|
||||
IReconstructionPoint,
|
||||
ISpatialDataConfiguration,
|
||||
} from "../../Component";
|
||||
@ -17,16 +16,6 @@ export class SpatialDataScene {
|
||||
private _connectedComponentColors: { [id: string]: string };
|
||||
private _needsRender: boolean;
|
||||
private _interactiveObjects: THREE.Object3D[];
|
||||
private _reconstructions: {
|
||||
[hash: string]: {
|
||||
cameraKeys: { [id: string]: string };
|
||||
cameras: THREE.Object3D;
|
||||
connectedComponents: { [id: string]: THREE.Object3D[] };
|
||||
keys: string[];
|
||||
points: THREE.Object3D;
|
||||
positions: THREE.Object3D;
|
||||
};
|
||||
};
|
||||
|
||||
private _tileClusterReconstructions: {
|
||||
[hash: string]: {
|
||||
@ -66,7 +55,6 @@ export class SpatialDataScene {
|
||||
this._connectedComponentColors = {};
|
||||
this._needsRender = false;
|
||||
this._interactiveObjects = [];
|
||||
this._reconstructions = {};
|
||||
this._nodes = {};
|
||||
this._tiles = {};
|
||||
this._tileClusterReconstructions = {};
|
||||
@ -170,60 +158,6 @@ export class SpatialDataScene {
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public addReconstruction(
|
||||
reconstruction: IReconstruction,
|
||||
transform: Transform,
|
||||
originalPosition: number[],
|
||||
connectedComponent: string,
|
||||
hash: string): void {
|
||||
|
||||
if (!(hash in this._reconstructions)) {
|
||||
this._reconstructions[hash] = {
|
||||
cameraKeys: {},
|
||||
cameras: new THREE.Object3D(),
|
||||
connectedComponents: {},
|
||||
keys: [],
|
||||
points: new THREE.Object3D(),
|
||||
positions: new THREE.Object3D(),
|
||||
};
|
||||
|
||||
this._reconstructions[hash].cameras.visible = this._camerasVisible;
|
||||
this._reconstructions[hash].points.visible = this._pointsVisible;
|
||||
this._reconstructions[hash].positions.visible = this._positionsVisible;
|
||||
|
||||
this._scene.add(
|
||||
this._reconstructions[hash].cameras,
|
||||
this._reconstructions[hash].points,
|
||||
this._reconstructions[hash].positions);
|
||||
}
|
||||
|
||||
if (!(connectedComponent in this._reconstructions[hash].connectedComponents)) {
|
||||
this._reconstructions[hash].connectedComponents[connectedComponent] = [];
|
||||
}
|
||||
|
||||
if (transform.hasValidScale) {
|
||||
this._reconstructions[hash].points.add(this._createPoints(reconstruction, transform));
|
||||
}
|
||||
|
||||
const camera: THREE.Object3D = this._createCamera(transform);
|
||||
this._reconstructions[hash].cameras.add(camera);
|
||||
for (const child of camera.children) {
|
||||
this._reconstructions[hash].cameraKeys[child.uuid] = reconstruction.main_shot;
|
||||
this._interactiveObjects.push(child);
|
||||
}
|
||||
|
||||
this._reconstructions[hash].connectedComponents[connectedComponent].push(camera);
|
||||
|
||||
const color: string = this._getColor(connectedComponent, this._visualizeConnectedComponents);
|
||||
this._setCameraColor(color, camera);
|
||||
|
||||
this._reconstructions[hash].positions.add(this._createPosition(transform, originalPosition));
|
||||
|
||||
this._reconstructions[hash].keys.push(reconstruction.main_shot);
|
||||
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public addTile(tileBBox: number[][], hash: string): void {
|
||||
if (this.hasTile(hash)) {
|
||||
return;
|
||||
@ -283,11 +217,6 @@ export class SpatialDataScene {
|
||||
this._clusterReconstructions[key].tiles.indexOf(hash) !== -1;
|
||||
}
|
||||
|
||||
public hasReconstruction(key: string, hash: string): boolean {
|
||||
return hash in this._reconstructions &&
|
||||
this._reconstructions[hash].keys.indexOf(key) !== -1;
|
||||
}
|
||||
|
||||
public hasTile(hash: string): boolean {
|
||||
return hash in this._tiles;
|
||||
}
|
||||
@ -337,14 +266,6 @@ export class SpatialDataScene {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const hash in this._reconstructions) {
|
||||
if (!this._reconstructions.hasOwnProperty(hash)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._reconstructions[hash].points.visible = visible;
|
||||
}
|
||||
|
||||
for (const key in this._clusterReconstructions) {
|
||||
if (!this._clusterReconstructions.hasOwnProperty(key)) {
|
||||
continue;
|
||||
@ -591,48 +512,6 @@ export class SpatialDataScene {
|
||||
return new THREE.Points(geometry, material);
|
||||
}
|
||||
|
||||
private _createPoints(reconstruction: IReconstruction, transform: Transform): THREE.Object3D {
|
||||
const srtInverse: THREE.Matrix4 = new THREE.Matrix4().getInverse(transform.srt);
|
||||
const points: IReconstructionPoint[] = Object
|
||||
.keys(reconstruction.points)
|
||||
.map(
|
||||
(key: string): IReconstructionPoint => {
|
||||
return reconstruction.points[key];
|
||||
});
|
||||
|
||||
const numPoints: number = points.length;
|
||||
const positions: Float32Array = new Float32Array(numPoints * 3);
|
||||
const colors: Float32Array = new Float32Array(numPoints * 3);
|
||||
|
||||
for (let i: number = 0; i < numPoints; i++) {
|
||||
const index: number = 3 * i;
|
||||
|
||||
const coords: number[] = points[i].coordinates;
|
||||
const point: THREE.Vector3 = new THREE.Vector3(coords[0], coords[1], coords[2])
|
||||
.applyMatrix4(srtInverse);
|
||||
|
||||
positions[index + 0] = point.x;
|
||||
positions[index + 1] = point.y;
|
||||
positions[index + 2] = point.z;
|
||||
|
||||
const color: number[] = points[i].color;
|
||||
colors[index + 0] = color[0] / 255.0;
|
||||
colors[index + 1] = color[1] / 255.0;
|
||||
colors[index + 2] = color[2] / 255.0;
|
||||
}
|
||||
|
||||
const geometry: THREE.BufferGeometry = new THREE.BufferGeometry();
|
||||
geometry.addAttribute("position", new THREE.BufferAttribute(positions, 3));
|
||||
geometry.addAttribute("color", new THREE.BufferAttribute(colors, 3));
|
||||
|
||||
const material: THREE.PointsMaterial = new THREE.PointsMaterial({
|
||||
size: 0.1,
|
||||
vertexColors: THREE.VertexColors,
|
||||
});
|
||||
|
||||
return new THREE.Points(geometry, material);
|
||||
}
|
||||
|
||||
private _createPosition(transform: Transform, originalPosition: number[]): THREE.Object3D {
|
||||
const computedPosition: number[] = transform.unprojectBasic([0, 0], 0);
|
||||
const vertices: number[][] = [originalPosition, computedPosition];
|
||||
@ -727,8 +606,6 @@ export class SpatialDataScene {
|
||||
private _disposeReconstruction(hash: string): void {
|
||||
this._disposePoints(hash);
|
||||
|
||||
delete this._reconstructions[hash];
|
||||
|
||||
delete this._tileClusterReconstructions[hash];
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import {IReconstructionPoint} from "../../../Component";
|
||||
|
||||
export interface IReconstruction {
|
||||
points: { [id: string]: IReconstructionPoint };
|
||||
main_shot: string;
|
||||
}
|
||||
|
||||
export default IReconstruction;
|
||||
@ -1,2 +1 @@
|
||||
export {IReconstruction} from "./IReconstruction";
|
||||
export {IReconstructionPoint} from "./IReconstructionPoint";
|
||||
|
||||
@ -2,7 +2,6 @@ import {IUrlOptions} from "../Viewer";
|
||||
|
||||
export class Urls {
|
||||
private static _apiHost: string = "a.mapillary.com";
|
||||
private static _atomicReconstructionHost: string = "atomic-reconstructions.mapillary.com";
|
||||
private static _clusterReconstructionHost: string = "cluster-reconstructions.mapillary.com";
|
||||
private static _exploreHost: string = "www.mapillary.com";
|
||||
private static _imageHost: string = "images.mapillary.com";
|
||||
@ -27,10 +26,6 @@ export class Urls {
|
||||
return Urls._imageTileHost;
|
||||
}
|
||||
|
||||
public static atomicReconstruction(key: string): string {
|
||||
return `${Urls._scheme}://${Urls._atomicReconstructionHost}/${key}/sfm/v1.0/atomic_reconstruction.json`;
|
||||
}
|
||||
|
||||
public static clusterReconstruction(key: string): string {
|
||||
return `${Urls._scheme}://${Urls._clusterReconstructionHost}/${key}/v1.0/aligned.jsonz`;
|
||||
}
|
||||
@ -66,10 +61,6 @@ export class Urls {
|
||||
Urls._apiHost = options.apiHost;
|
||||
}
|
||||
|
||||
if (!!options.atomicReconstructionHost) {
|
||||
Urls._atomicReconstructionHost = options.atomicReconstructionHost;
|
||||
}
|
||||
|
||||
if (!!options.clusterReconstructionHost) {
|
||||
Urls._clusterReconstructionHost = options.clusterReconstructionHost;
|
||||
}
|
||||
|
||||
@ -13,16 +13,6 @@ export interface IUrlOptions {
|
||||
*/
|
||||
apiHost?: string;
|
||||
|
||||
/**
|
||||
* Atomic reconstruction host.
|
||||
*
|
||||
* @description Used for retrieving the atomic reconstructions
|
||||
* for showing point clouds.
|
||||
*
|
||||
* @default {"atomic-reconstructions.mapillary.com"}
|
||||
*/
|
||||
atomicReconstructionHost?: string;
|
||||
|
||||
/**
|
||||
* Cluster reconstruction host.
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user