mapillary-js
Version:
WebGL JavaScript library for displaying street level imagery from mapillary.com
580 lines (442 loc) • 22 kB
text/typescript
import * as THREE from "three";
import {TransformHelper} from "../helper/TransformHelper.spec";
import {
Transform,
ViewportCoords,
} from "../../src/Geo";
let precision: number = 8;
describe("ViewportCoords.canvasToViewport", () => {
let viewportCoords: ViewportCoords;
beforeEach(() => {
viewportCoords = new ViewportCoords();
});
it("should convert canvas origin to (-1, 1)", () => {
let canvasX: number = 0;
let canvasY: number = 0;
let viewport1: number[] = viewportCoords.canvasToViewport(
canvasX,
canvasY,
<HTMLElement>{ offsetHeight: 240, offsetWidth: 320 });
let viewport2: number[] = viewportCoords.canvasToViewport(
canvasX,
canvasY,
<HTMLElement>{ offsetHeight: 320, offsetWidth: 240 });
let viewport3: number[] = viewportCoords.canvasToViewport(
canvasX,
canvasY,
<HTMLElement>{ offsetHeight: 1080, offsetWidth: 1920 });
expect(viewport1[0]).toBeCloseTo(-1, precision);
expect(viewport1[1]).toBeCloseTo(1, precision);
expect(viewport2[0]).toBeCloseTo(-1, precision);
expect(viewport2[1]).toBeCloseTo(1, precision);
expect(viewport3[0]).toBeCloseTo(-1, precision);
expect(viewport3[1]).toBeCloseTo(1, precision);
});
it("should convert canvas max to (1, -1)", () => {
let viewport1: number[] = viewportCoords
.canvasToViewport(320, 240, <HTMLElement>{ offsetHeight: 240, offsetWidth: 320 });
let viewport2: number[] = viewportCoords
.canvasToViewport(240, 320, <HTMLElement>{ offsetHeight: 320, offsetWidth: 240 });
let viewport3: number[] = viewportCoords
.canvasToViewport(1920, 1080, <HTMLElement>{ offsetHeight: 1080, offsetWidth: 1920 });
expect(viewport1[0]).toBeCloseTo(1, precision);
expect(viewport1[1]).toBeCloseTo(-1, precision);
expect(viewport2[0]).toBeCloseTo(1, precision);
expect(viewport2[1]).toBeCloseTo(-1, precision);
expect(viewport3[0]).toBeCloseTo(1, precision);
expect(viewport3[1]).toBeCloseTo(-1, precision);
});
it("should convert canvas center to (0, 0)", () => {
let viewport1: number[] = viewportCoords
.canvasToViewport(160, 120, <HTMLElement>{ offsetHeight: 240, offsetWidth: 320 });
let viewport2: number[] = viewportCoords
.canvasToViewport(120, 160, <HTMLElement>{ offsetHeight: 320, offsetWidth: 240 });
let viewport3: number[] = viewportCoords
.canvasToViewport(960, 540, <HTMLElement>{ offsetHeight: 1080, offsetWidth: 1920 });
expect(viewport1[0]).toBeCloseTo(0, precision);
expect(viewport1[1]).toBeCloseTo(0, precision);
expect(viewport2[0]).toBeCloseTo(0, precision);
expect(viewport2[1]).toBeCloseTo(0, precision);
expect(viewport3[0]).toBeCloseTo(0, precision);
expect(viewport3[1]).toBeCloseTo(0, precision);
});
});
describe("ViewportCoords.viewportToCanvas", () => {
let viewportCoords: ViewportCoords;
beforeEach(() => {
viewportCoords = new ViewportCoords();
});
it("should convert viewport (-1, 1) to canvas origin", () => {
let canvas1: number[] = viewportCoords
.viewportToCanvas(-1, 1, <HTMLElement>{ offsetHeight: 240, offsetWidth: 320 });
let canvas2: number[] = viewportCoords
.viewportToCanvas(-1, 1, <HTMLElement>{ offsetHeight: 320, offsetWidth: 240 });
let canvas3: number[] = viewportCoords
.viewportToCanvas(-1, 1, <HTMLElement>{ offsetHeight: 1080, offsetWidth: 1920 });
expect(canvas1[0]).toBeCloseTo(0, precision);
expect(canvas1[1]).toBeCloseTo(0, precision);
expect(canvas2[0]).toBeCloseTo(0, precision);
expect(canvas2[1]).toBeCloseTo(0, precision);
expect(canvas3[0]).toBeCloseTo(0, precision);
expect(canvas3[1]).toBeCloseTo(0, precision);
});
it("should convert viewport (1, -1) to canvas max", () => {
let canvas1: number[] = viewportCoords
.viewportToCanvas(1, -1, <HTMLElement>{ offsetHeight: 240, offsetWidth: 320 });
let canvas2: number[] = viewportCoords
.viewportToCanvas(1, -1, <HTMLElement>{ offsetHeight: 320, offsetWidth: 240 });
let canvas3: number[] = viewportCoords
.viewportToCanvas(1, -1, <HTMLElement>{ offsetHeight: 1080, offsetWidth: 1920 });
expect(canvas1[0]).toBeCloseTo(320, precision);
expect(canvas1[1]).toBeCloseTo(240, precision);
expect(canvas2[0]).toBeCloseTo(240, precision);
expect(canvas2[1]).toBeCloseTo(320, precision);
expect(canvas3[0]).toBeCloseTo(1920, precision);
expect(canvas3[1]).toBeCloseTo(1080, precision);
});
it("should convert viewport (0, 0) to canvas center", () => {
let canvas1: number[] = viewportCoords
.viewportToCanvas(0, 0, <HTMLElement>{ offsetHeight: 240, offsetWidth: 320 });
let canvas2: number[] = viewportCoords
.viewportToCanvas(0, 0, <HTMLElement>{ offsetHeight: 320, offsetWidth: 240 });
let canvas3: number[] = viewportCoords
.viewportToCanvas(0, 0, <HTMLElement>{ offsetHeight: 1080, offsetWidth: 1920 });
expect(canvas1[0]).toBeCloseTo(160, precision);
expect(canvas1[1]).toBeCloseTo(120, precision);
expect(canvas2[0]).toBeCloseTo(120, precision);
expect(canvas2[1]).toBeCloseTo(160, precision);
expect(canvas3[0]).toBeCloseTo(960, precision);
expect(canvas3[1]).toBeCloseTo(540, precision);
});
});
describe("ViewportCoords.getBasicDistances", () => {
let transformHelper: TransformHelper;
beforeEach(() => {
transformHelper = new TransformHelper();
});
it("should be zero when basic image corners correspond to viewport corners", () => {
let transform: Transform = transformHelper.createTransform();
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
let viewportCoords: ViewportCoords = new ViewportCoords();
let vector3: THREE.Vector3 = new THREE.Vector3();
spyOn(THREE, "Vector3").and.callFake(
(x: number, y: number, z: number): THREE.Vector3 => {
vector3.setX(x);
vector3.setY(y);
vector3.setZ(z);
return vector3;
});
spyOn(vector3, "unproject").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
spyOn(transform, "projectBasic").and.callFake(
(point3d: number[]): number[] => {
let basic: number[] = viewportCoords
.viewportToCanvas(point3d[0], point3d[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
return basic;
});
let basicDistances: number[] = viewportCoords.getBasicDistances(transform, perspectiveCamera);
expect(basicDistances[0]).toBeCloseTo(0, precision);
expect(basicDistances[1]).toBeCloseTo(0, precision);
expect(basicDistances[2]).toBeCloseTo(0, precision);
expect(basicDistances[3]).toBeCloseTo(0, precision);
});
it("should be zero when three basic image corners correspond to viewport corners and forth has distance", () => {
let transform: Transform = transformHelper.createTransform();
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
let viewportCoords: ViewportCoords = new ViewportCoords();
let vector3: THREE.Vector3 = new THREE.Vector3();
spyOn(THREE, "Vector3").and.callFake(
(x: number, y: number, z: number): THREE.Vector3 => {
vector3.setX(x);
vector3.setY(y);
vector3.setZ(z);
return vector3;
});
spyOn(vector3, "unproject").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
spyOn(transform, "projectBasic").and.callFake(
(point3d: number[]): number[] => {
let basic: number[] = viewportCoords
.viewportToCanvas(point3d[0], point3d[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
if (basic[0] === 0 && basic[1] === 0) {
basic[0] = -0.1;
basic[1] = -0.1;
}
return basic;
});
let basicDistances: number[] = viewportCoords.getBasicDistances(transform, perspectiveCamera);
expect(basicDistances[0]).toBeCloseTo(0, precision);
expect(basicDistances[1]).toBeCloseTo(0, precision);
expect(basicDistances[2]).toBeCloseTo(0, precision);
expect(basicDistances[3]).toBeCloseTo(0, precision);
});
it("should be non zero for one side when both corners of that side are outside of image", () => {
let transform: Transform = transformHelper.createTransform();
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
let viewportCoords: ViewportCoords = new ViewportCoords();
let vector3: THREE.Vector3 = new THREE.Vector3();
spyOn(THREE, "Vector3").and.callFake(
(x: number, y: number, z: number): THREE.Vector3 => {
vector3.setX(x);
vector3.setY(y);
vector3.setZ(z);
return vector3;
});
spyOn(vector3, "unproject").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
spyOn(transform, "projectBasic").and.callFake(
(point3d: number[]): number[] => {
let basic: number[] = viewportCoords
.viewportToCanvas(point3d[0], point3d[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
if (basic[0] === 0 && basic[1] === 0) {
basic[1] = -0.1;
} else if (basic[0] === 1 && basic[1] === 0) {
basic[1] = -0.1;
}
return basic;
});
let basicDistances: number[] = viewportCoords.getBasicDistances(transform, perspectiveCamera);
expect(basicDistances[0]).toBeCloseTo(0.1, precision);
expect(basicDistances[1]).toBeCloseTo(0, precision);
expect(basicDistances[2]).toBeCloseTo(0, precision);
expect(basicDistances[3]).toBeCloseTo(0, precision);
});
});
describe("ViewportCoords.getPixelDistances", () => {
let transformHelper: TransformHelper;
beforeEach(() => {
transformHelper = new TransformHelper();
});
it("should be zero when basic image corners correspond to viewport corners", () => {
let transform: Transform = transformHelper.createTransform();
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
let viewportCoords: ViewportCoords = new ViewportCoords();
let vector3: THREE.Vector3 = new THREE.Vector3();
spyOn(THREE, "Vector3").and.callFake(
(x: number, y: number, z: number): THREE.Vector3 => {
vector3.setX(x);
vector3.setY(y);
vector3.setZ(z);
return vector3;
});
spyOn(vector3, "unproject").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
spyOn(transform, "projectBasic").and.callFake(
(point3d: number[]): number[] => {
let basic: number[] = viewportCoords
.viewportToCanvas(point3d[0], point3d[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
return basic;
});
spyOn(transform, "unprojectBasic").and.callFake(
(basic: number[]): number[] => {
return basic.concat([1]);
});
spyOn(vector3, "project").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
let pixelDistances: number[] = viewportCoords
.getPixelDistances(<HTMLElement>{ offsetHeight: 1, offsetWidth: 1 }, transform, perspectiveCamera);
expect(pixelDistances[0]).toBeCloseTo(0, precision);
expect(pixelDistances[1]).toBeCloseTo(0, precision);
expect(pixelDistances[2]).toBeCloseTo(0, precision);
expect(pixelDistances[3]).toBeCloseTo(0, precision);
});
it("should be zero when three basic image corners correspond to viewport corners and forth has distance", () => {
let transform: Transform = transformHelper.createTransform();
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
let viewportCoords: ViewportCoords = new ViewportCoords();
let vector3: THREE.Vector3 = new THREE.Vector3();
spyOn(THREE, "Vector3").and.callFake(
(x: number, y: number, z: number): THREE.Vector3 => {
vector3.setX(x);
vector3.setY(y);
vector3.setZ(z);
return vector3;
});
spyOn(vector3, "unproject").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
spyOn(transform, "projectBasic").and.callFake(
(point3d: number[]): number[] => {
let basic: number[] = viewportCoords
.viewportToCanvas(point3d[0], point3d[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
if (basic[0] === 0 && basic[1] === 0) {
basic[0] = -0.1;
basic[1] = -0.1;
}
return basic;
});
spyOn(transform, "unprojectBasic").and.callFake(
(basic: number[]): number[] => {
return basic.concat([1]);
});
spyOn(vector3, "project").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
let pixelDistances: number[] = viewportCoords
.getPixelDistances(<HTMLElement>{ offsetHeight: 1, offsetWidth: 1 }, transform, perspectiveCamera);
expect(pixelDistances[0]).toBeCloseTo(0, precision);
expect(pixelDistances[1]).toBeCloseTo(0, precision);
expect(pixelDistances[2]).toBeCloseTo(0, precision);
expect(pixelDistances[3]).toBeCloseTo(0, precision);
});
it("should be non zero for one side when both corners of that side are outside of image", () => {
let transform: Transform = transformHelper.createTransform();
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
let viewportCoords: ViewportCoords = new ViewportCoords();
let vector3: THREE.Vector3 = new THREE.Vector3();
spyOn(THREE, "Vector3").and.callFake(
(x: number, y: number, z: number): THREE.Vector3 => {
vector3.setX(x);
vector3.setY(y);
vector3.setZ(z);
return vector3;
});
spyOn(vector3, "unproject").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
spyOn(transform, "projectBasic").and.callFake(
(point3d: number[]): number[] => {
let basic: number[] = viewportCoords
.viewportToCanvas(point3d[0], point3d[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
if (basic[0] === 0 && basic[1] === 0) {
basic[1] = -0.1;
} else if (basic[0] === 1 && basic[1] === 0) {
basic[1] = -0.1;
}
return basic;
});
spyOn(transform, "unprojectBasic").and.callFake(
(basic: number[]): number[] => {
let viewport: number[] = viewportCoords
.canvasToViewport(basic[0], basic[1], <HTMLElement>{ offsetHeight: 1, offsetWidth: 1 });
let point3d: number[] = viewport.concat([1]);
if (point3d[0] === -1 && point3d[1] === 1) {
point3d[1] = 0.8;
} else if (point3d[0] === 1 && point3d[1] === 1) {
point3d[1] = 0.8;
}
return point3d;
});
spyOn(vector3, "project").and.callFake(
(pc: THREE.PerspectiveCamera): THREE.Vector3 => {
return vector3;
});
let pixelDistances: number[] = viewportCoords
.getPixelDistances(<HTMLElement>{ offsetHeight: 1, offsetWidth: 1 }, transform, perspectiveCamera);
expect(pixelDistances[0]).toBeCloseTo(0.1, precision);
expect(pixelDistances[1]).toBeCloseTo(0, precision);
expect(pixelDistances[2]).toBeCloseTo(0, precision);
expect(pixelDistances[3]).toBeCloseTo(0, precision);
});
});
describe("ViewportCoords.worldToCamera", () => {
let viewportCoords: ViewportCoords;
beforeEach(() => {
viewportCoords = new ViewportCoords();
});
it("should convert to same coordinates", () => {
const point3d: number[] = [10, 20, 30];
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
perspectiveCamera.matrixWorldInverse = new THREE.Matrix4().identity();
const pointCamera: number[] = viewportCoords.worldToCamera(point3d, perspectiveCamera);
expect(pointCamera[0]).toBeCloseTo(point3d[0], precision);
expect(pointCamera[1]).toBeCloseTo(point3d[1], precision);
expect(pointCamera[2]).toBeCloseTo(point3d[2], precision);
});
it("should negate coordinates", () => {
const point3d: number[] = [10, 20, 30];
let perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
perspectiveCamera.matrixWorldInverse = new THREE.Matrix4().makeScale(-1, -1, -1);
const pointCamera: number[] = viewportCoords.worldToCamera(point3d, perspectiveCamera);
expect(pointCamera[0]).toBeCloseTo(-point3d[0], precision);
expect(pointCamera[1]).toBeCloseTo(-point3d[1], precision);
expect(pointCamera[2]).toBeCloseTo(-point3d[2], precision);
});
});
describe("ViewportCoords.basicToCanvasSafe", () => {
let transformHelper: TransformHelper;
beforeEach(() => {
transformHelper = new TransformHelper();
});
it("should be null when behind camera", () => {
const perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
perspectiveCamera.matrixWorldInverse = new THREE.Matrix4().identity();
const transform: Transform = transformHelper.createTransform();
spyOn(transform, "unprojectBasic").and.returnValue([1, 1, 1]);
const viewportCoords: ViewportCoords = new ViewportCoords();
const [basicX, basicY]: number[] = [0, 0];
const canvas: number[] =
viewportCoords.basicToCanvasSafe(
basicX,
basicY,
{ offsetHeight: 100, offsetWidth: 100 },
transform,
perspectiveCamera);
expect(canvas).toBe(null);
});
it("should not be null when in front of camera", () => {
const perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
perspectiveCamera.matrixWorldInverse = new THREE.Matrix4().makeScale(-1, -1, -1);
const transform: Transform = transformHelper.createTransform();
spyOn(transform, "unprojectBasic").and.returnValue([1, 1, 1]);
const viewportCoords: ViewportCoords = new ViewportCoords();
const [basicX, basicY]: number[] = [0, 0];
const canvas: number[] =
viewportCoords.basicToCanvasSafe(
basicX,
basicY,
{ offsetHeight: 100, offsetWidth: 100 },
transform,
perspectiveCamera);
expect(canvas).not.toBe(null);
});
});
describe("ViewportCoords.basicToViewportSafe", () => {
let transformHelper: TransformHelper;
beforeEach(() => {
transformHelper = new TransformHelper();
});
it("should be null when behind camera", () => {
const perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
perspectiveCamera.matrixWorldInverse = new THREE.Matrix4().identity();
const transform: Transform = transformHelper.createTransform();
spyOn(transform, "unprojectBasic").and.returnValue([1, 1, 1]);
const viewportCoords: ViewportCoords = new ViewportCoords();
const [basicX, basicY]: number[] = [0, 0];
const canvas: number[] =
viewportCoords.basicToViewportSafe(
basicX,
basicY,
transform,
perspectiveCamera);
expect(canvas).toBe(null);
});
it("should not be null when in front of camera", () => {
const perspectiveCamera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera();
perspectiveCamera.matrixWorldInverse = new THREE.Matrix4().makeScale(-1, -1, -1);
const transform: Transform = transformHelper.createTransform();
spyOn(transform, "unprojectBasic").and.returnValue([1, 1, 1]);
const viewportCoords: ViewportCoords = new ViewportCoords();
const [basicX, basicY]: number[] = [0, 0];
const canvas: number[] =
viewportCoords.basicToViewportSafe(
basicX,
basicY,
transform,
perspectiveCamera);
expect(canvas).not.toBe(null);
});
});