feat(spatial): remove references to atomic reconstructions

This commit is contained in:
Oscar Lorentzon 2019-10-21 22:15:43 +02:00
parent 518c3d500a
commit 7ee9d1ff48
8 changed files with 8 additions and 322 deletions

View File

@ -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);
});
*/
});

View File

@ -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";

View File

@ -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];
}

View File

@ -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];
}

View File

@ -1,8 +0,0 @@
import {IReconstructionPoint} from "../../../Component";
export interface IReconstruction {
points: { [id: string]: IReconstructionPoint };
main_shot: string;
}
export default IReconstruction;

View File

@ -1,2 +1 @@
export {IReconstruction} from "./IReconstruction";
export {IReconstructionPoint} from "./IReconstructionPoint";

View File

@ -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;
}

View File

@ -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.
*