mirror of
https://github.com/mapillary/mapillary-js.git
synced 2025-12-08 17:35:55 +00:00
240 lines
8.3 KiB
TypeScript
240 lines
8.3 KiB
TypeScript
import { S2 } from "s2-geometry";
|
|
import { LngLat } from "../../src/api/interfaces/LngLat";
|
|
import { S2GeometryProvider } from "../../src/api/S2GeometryProvider";
|
|
import { MapillaryError } from "../../src/error/MapillaryError";
|
|
import * as GeoCoords from "../../src/geo/GeoCoords";
|
|
import { isClockwise } from "../helper/TestMath";
|
|
|
|
describe("S2GeometryProvider.ctor", () => {
|
|
it("should be defined", () => {
|
|
const geometry = new S2GeometryProvider();
|
|
|
|
expect(geometry).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe("GS2GeometryProvider.lngLatToCellId", () => {
|
|
it("should call geometry correctly", () => {
|
|
const keySpy = spyOn(S2, "latLngToKey");
|
|
const idSpy = spyOn(S2, "keyToId");
|
|
keySpy.and.returnValue("0/0");
|
|
idSpy.and.returnValue("0.0");
|
|
|
|
const level = 22;
|
|
const geometry = new S2GeometryProvider(level);
|
|
|
|
const lat = -1;
|
|
const lng = 1;
|
|
geometry.lngLatToCellId({ lat, lng });
|
|
|
|
expect(keySpy.calls.count()).toBe(1);
|
|
expect(keySpy.calls.first().args[0]).toBe(lat);
|
|
expect(keySpy.calls.first().args[1]).toBe(lng);
|
|
expect(keySpy.calls.first().args[2]).toBe(level);
|
|
|
|
expect(idSpy.calls.count()).toBe(1);
|
|
expect(idSpy.calls.first().args[0]).toBe("0/0");
|
|
});
|
|
});
|
|
|
|
describe("S2GeometryProvider.bboxToCellIds", () => {
|
|
const setupSpies: (tileSize: number) => void =
|
|
(tileSize: number): void => {
|
|
spyOn(S2, "latLngToKey").and.callFake(
|
|
(lat: number, lng: number): string => {
|
|
return `${Math.round(lat)}/${Math.round(lng)}`;
|
|
});
|
|
|
|
spyOn(S2, "keyToId").and.callFake(
|
|
(key: string): string => {
|
|
const [k0, k1] = key.split("/");
|
|
return `${k0}.${k1}`;
|
|
});
|
|
|
|
spyOn(S2, "idToKey").and.callFake(
|
|
(id: string): string => {
|
|
const [i0, i1] = id.split(".");
|
|
return `${i0}/${i1}`;
|
|
});
|
|
|
|
spyOn(S2, "keyToLatLng").and.callFake(
|
|
(key: string): S2.ILatLng => {
|
|
const [k0, k1] = key.split("/");
|
|
const lat = Number.parseInt(k0, 10);
|
|
const lng = Number.parseInt(k1, 10);
|
|
|
|
return { lat: lat, lng: lng };
|
|
});
|
|
|
|
spyOn(S2.S2Cell, "FromHilbertQuadKey").and.callFake(
|
|
(key: string): S2.S2Cell => {
|
|
const [k0, k1] = key.split("/");
|
|
const lat = Number.parseInt(k0, 10);
|
|
const lng = Number.parseInt(k1, 10);
|
|
|
|
const s2Cell: S2.S2Cell = new S2.S2Cell();
|
|
spyOn(s2Cell, "getCornerLatLngs").and.returnValue([
|
|
{ lat: lat - 0.5, lng: lng + 0.5 },
|
|
{ lat: lat - 0.5, lng: lng - 0.5 },
|
|
{ lat: lat + 0.5, lng: lng - 0.5 },
|
|
{ lat: lat + 0.5, lng: lng + 0.5 },
|
|
]);
|
|
|
|
return s2Cell;
|
|
});
|
|
|
|
spyOn(S2, "latLngToNeighborKeys").and.callFake(
|
|
(lat: number, lng: number): string[] => {
|
|
return [
|
|
`${lat}/${lng - 1}`,
|
|
`${lat + 1}/${lng}`,
|
|
`${lat}/${lng + 1}`,
|
|
`${lat - 1}/${lng}`,
|
|
];
|
|
});
|
|
|
|
spyOn(GeoCoords, "geodeticToEnu").and.callFake(
|
|
(
|
|
lat: number,
|
|
lng: number,
|
|
_: number,
|
|
refLat: number,
|
|
refLng: number)
|
|
: number[] => {
|
|
return [
|
|
tileSize * (lng - refLng),
|
|
tileSize * (lat - refLat),
|
|
0];
|
|
});
|
|
|
|
spyOn(GeoCoords, "enuToGeodetic").and.callFake(
|
|
(x: number, y: number, _: number, refLat: number, refLng: number): number[] => {
|
|
return [
|
|
refLng + x / tileSize,
|
|
refLat + y / tileSize,
|
|
0];
|
|
});
|
|
};
|
|
|
|
it("should return cell", () => {
|
|
const geometry = new S2GeometryProvider();
|
|
const tileSize = 1;
|
|
setupSpies(tileSize);
|
|
|
|
const sw: LngLat = { lat: -0.1, lng: -0.1 };
|
|
const ne: LngLat = { lat: 0.1, lng: 0.1 };
|
|
const cellIds = geometry.bboxToCellIds(sw, ne);
|
|
|
|
expect(cellIds.length).toBe(1);
|
|
expect(cellIds[0]).toBe("0.0");
|
|
});
|
|
|
|
it("should return cell and adjacent", () => {
|
|
const geometry = new S2GeometryProvider();
|
|
const tileSize = 1;
|
|
setupSpies(tileSize);
|
|
|
|
const sw: LngLat = { lat: -0.6, lng: -0.6 };
|
|
const ne: LngLat = { lat: 0.6, lng: 0.6 };
|
|
const cellIds = geometry.bboxToCellIds(sw, ne);
|
|
|
|
expect(cellIds.length).toBe(9);
|
|
expect(cellIds.indexOf("0.0")).not.toBe(-1);
|
|
expect(cellIds.indexOf("0.1")).not.toBe(-1);
|
|
expect(cellIds.indexOf("-1.1")).not.toBe(-1);
|
|
expect(cellIds.indexOf("-1.0")).not.toBe(-1);
|
|
expect(cellIds.indexOf("-1.-1")).not.toBe(-1);
|
|
expect(cellIds.indexOf("0.-1")).not.toBe(-1);
|
|
expect(cellIds.indexOf("1.-1")).not.toBe(-1);
|
|
expect(cellIds.indexOf("1.0")).not.toBe(-1);
|
|
expect(cellIds.indexOf("1.1")).not.toBe(-1);
|
|
});
|
|
|
|
describe("S2GeometryProvider.bboxToCellIds", () => {
|
|
it("should throw if north east is not larger than south west", () => {
|
|
const geometry = new S2GeometryProvider();
|
|
|
|
expect(() => {
|
|
geometry
|
|
.bboxToCellIds(
|
|
{ lat: 0, lng: 0 },
|
|
{ lat: -1, lng: 1 });
|
|
}).toThrowError(MapillaryError);
|
|
|
|
expect(() => {
|
|
geometry
|
|
.bboxToCellIds(
|
|
{ lat: 0, lng: 0 },
|
|
{ lat: 1, lng: -1 });
|
|
}).toThrowError(MapillaryError);
|
|
|
|
expect(() => {
|
|
geometry.bboxToCellIds(
|
|
{ lat: 0, lng: 0 },
|
|
{ lat: -1, lng: -1 });
|
|
}).toThrowError(MapillaryError);
|
|
});
|
|
});
|
|
|
|
describe("S2GeometryProvider.getVertices", () => {
|
|
it("should be correctly placed relative to each other", () => {
|
|
const geometry = new S2GeometryProvider();
|
|
|
|
const lngLats: LngLat[] = [
|
|
{ lat: 0, lng: 0 },
|
|
{ lat: 45, lng: 0 },
|
|
{ lat: 0, lng: 45 },
|
|
{ lat: -45, lng: 0 },
|
|
{ lat: 0, lng: -45 },
|
|
{ lat: 45, lng: 45 },
|
|
{ lat: -45, lng: -45 },
|
|
{ lat: 45, lng: -45 },
|
|
{ lat: -45, lng: 45 },
|
|
{ lat: -45, lng: 135 },
|
|
];
|
|
|
|
for (let lngLat of lngLats) {
|
|
const cellId = geometry.lngLatToCellId(lngLat);
|
|
const vertices = geometry.getVertices(cellId);
|
|
expect(vertices.length).toBe(4);
|
|
|
|
const polygon = vertices
|
|
.map(
|
|
(ll: LngLat): number[] => {
|
|
return [ll.lng, ll.lat];
|
|
});
|
|
|
|
expect(isClockwise(polygon)).toBe(true);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("S2GeometryProvider.getAdjacent", () => {
|
|
it("should always be 8", () => {
|
|
const geometry = new S2GeometryProvider();
|
|
|
|
const lngLats: LngLat[] = [
|
|
{ lat: 0, lng: 0 },
|
|
{ lat: 45, lng: 0 },
|
|
{ lat: 0, lng: 45 },
|
|
{ lat: -45, lng: 0 },
|
|
{ lat: 0, lng: -45 },
|
|
{ lat: 45, lng: 45 },
|
|
{ lat: -45, lng: -45 },
|
|
{ lat: 45, lng: -45 },
|
|
{ lat: -45, lng: 45 },
|
|
{ lat: -45, lng: 135 },
|
|
{ lat: -45, lng: 180 },
|
|
{ lat: 0, lng: 180 },
|
|
{ lat: 45, lng: 180 },
|
|
];
|
|
|
|
for (let lngLat of lngLats) {
|
|
const cellId = geometry.lngLatToCellId(lngLat);
|
|
const adjacent = geometry.getAdjacent(cellId);
|
|
expect(adjacent.length).toBe(8);
|
|
}
|
|
});
|
|
});
|
|
});
|