mirror of
https://github.com/mapillary/mapillary-js.git
synced 2026-02-01 14:33:45 +00:00
refactor: provider get vertices returns polygon
This commit is contained in:
parent
2eed0b3c9f
commit
4891291c7c
@ -48,6 +48,4 @@ const bundles = [
|
||||
},
|
||||
];
|
||||
|
||||
bundles.unshift(esm);
|
||||
|
||||
export default bundles;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { S2 } from "s2-geometry";
|
||||
import { CellCorners } from "../../src/api/interfaces/CellCorners";
|
||||
import { LatLon } from "../../src/api/interfaces/LatLon";
|
||||
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", () => {
|
||||
@ -231,20 +231,17 @@ describe("S2GeometryProvider.getCorners", () => {
|
||||
];
|
||||
|
||||
for (let latLon of latLons) {
|
||||
const cellId: string = geometry.latLonToCellId(latLon);
|
||||
const corners: CellCorners = geometry.getCorners(cellId);
|
||||
const cellId = geometry.latLonToCellId(latLon);
|
||||
const vertices = geometry.getVertices(cellId);
|
||||
expect(vertices.length).toBe(4);
|
||||
|
||||
expect(corners.se.lat).toBeLessThan(corners.ne.lat);
|
||||
expect(corners.se.lat).toBeLessThan(corners.nw.lat);
|
||||
const polygon = vertices
|
||||
.map(
|
||||
(ll: LatLon): number[] => {
|
||||
return [ll.lon, ll.lat];
|
||||
});
|
||||
|
||||
expect(corners.sw.lat).toBeLessThan(corners.ne.lat);
|
||||
expect(corners.sw.lat).toBeLessThan(corners.nw.lat);
|
||||
|
||||
expect(corners.sw.lon).toBeLessThan(corners.se.lon);
|
||||
expect(corners.sw.lon).toBeLessThan(corners.ne.lon);
|
||||
|
||||
expect(corners.nw.lon).toBeLessThan(corners.se.lon);
|
||||
expect(corners.nw.lon).toBeLessThan(corners.ne.lon);
|
||||
expect(isClockwise(polygon)).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
10
spec/helper/TestMath.ts
Normal file
10
spec/helper/TestMath.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export function isClockwise(polygon: number[][]): boolean {
|
||||
if (polygon.length < 3) { return false; };
|
||||
let edgeSum = 0;
|
||||
for (let i = 0; i < polygon.length; ++i) {
|
||||
const [x1, y1] = polygon[i];
|
||||
const [x2, y2] = polygon[(i + 1) % polygon.length];
|
||||
edgeSum += (x2 - x1) * (y2 + y1);
|
||||
}
|
||||
return edgeSum > 0;
|
||||
}
|
||||
@ -2,7 +2,7 @@ import * as geohash from "latlon-geohash";
|
||||
import { geodeticToEnu } from "../geo/GeoCoords";
|
||||
|
||||
import { GeometryProviderBase } from "./GeometryProviderBase";
|
||||
import { CellCorners, CellNeighbors } from "./interfaces/CellCorners";
|
||||
import { CellNeighbors } from "./interfaces/CellCorners";
|
||||
import { LatLon } from "./interfaces/LatLon";
|
||||
|
||||
|
||||
@ -51,17 +51,17 @@ export class GeohashGeometryProvider extends GeometryProviderBase {
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public getCorners(cellId: string): CellCorners {
|
||||
const bounds: geohash.Bounds = geohash.bounds(cellId);
|
||||
const nw: LatLon = { lat: bounds.ne.lat, lon: bounds.sw.lon };
|
||||
const ne: LatLon = { lat: bounds.ne.lat, lon: bounds.ne.lon };
|
||||
const se: LatLon = { lat: bounds.ne.lat, lon: bounds.sw.lon };
|
||||
const sw: LatLon = { lat: bounds.sw.lat, lon: bounds.sw.lon };
|
||||
return { nw, ne, se, sw };
|
||||
public getVertices(cellId: string): LatLon[] {
|
||||
const bounds = geohash.bounds(cellId);
|
||||
const nw = { lat: bounds.ne.lat, lon: bounds.sw.lon };
|
||||
const ne = { lat: bounds.ne.lat, lon: bounds.ne.lon };
|
||||
const se = { lat: bounds.sw.lat, lon: bounds.ne.lon };
|
||||
const sw = { lat: bounds.sw.lat, lon: bounds.sw.lon };
|
||||
return [nw, ne, se, sw];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public getNeighbors(cellId: string): CellNeighbors {
|
||||
public getAdjacent(cellId: string): CellNeighbors {
|
||||
return geohash.neighbours(cellId);
|
||||
}
|
||||
|
||||
@ -73,13 +73,11 @@ export class GeohashGeometryProvider extends GeometryProviderBase {
|
||||
*
|
||||
* @returns {string} The geohash tile for the lat, lon and precision.
|
||||
*/
|
||||
public latLonToCellId(
|
||||
latLon: LatLon,
|
||||
relativeLevel: number = 0): string {
|
||||
public latLonToCellId(latLon: LatLon): string {
|
||||
return geohash.encode(
|
||||
latLon.lat,
|
||||
latLon.lon,
|
||||
this._level + relativeLevel);
|
||||
this._level);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,27 +93,20 @@ export class GeohashGeometryProvider extends GeometryProviderBase {
|
||||
*/
|
||||
public latLonToCellIds(
|
||||
latLon: LatLon,
|
||||
threshold: number,
|
||||
relativeLevel: number = 0): string[] {
|
||||
threshold: number)
|
||||
: string[] {
|
||||
|
||||
const h: string = geohash.encode(
|
||||
latLon.lat, latLon.lon, this._level + relativeLevel);
|
||||
const h = geohash.encode(
|
||||
latLon.lat, latLon.lon, this._level);
|
||||
|
||||
const bounds: geohash.Bounds = geohash.bounds(h);
|
||||
const corners: CellCorners = {
|
||||
ne: { lat: bounds.ne.lat, lon: bounds.ne.lon },
|
||||
nw: { lat: bounds.ne.lat, lon: bounds.sw.lon },
|
||||
se: { lat: bounds.sw.lat, lon: bounds.ne.lon },
|
||||
sw: { lat: bounds.sw.lat, lon: bounds.sw.lon },
|
||||
};
|
||||
|
||||
const neighbours: CellNeighbors = this.getNeighbors(h);
|
||||
const bounds = geohash.bounds(h);
|
||||
const neighbours = this.getAdjacent(h);
|
||||
|
||||
return this._filterNeighbors(
|
||||
latLon,
|
||||
threshold,
|
||||
h,
|
||||
corners,
|
||||
bounds,
|
||||
neighbours);
|
||||
}
|
||||
|
||||
@ -123,17 +114,17 @@ export class GeohashGeometryProvider extends GeometryProviderBase {
|
||||
latLon: LatLon,
|
||||
threshold: number,
|
||||
cellId: string,
|
||||
corners: CellCorners,
|
||||
bounds: geohash.Bounds,
|
||||
neighbors: CellNeighbors): string[] {
|
||||
|
||||
const bl = [0, 0, 0];
|
||||
const tr =
|
||||
geodeticToEnu(
|
||||
corners.ne.lat,
|
||||
corners.ne.lon,
|
||||
bounds.ne.lat,
|
||||
bounds.ne.lon,
|
||||
0,
|
||||
corners.sw.lat,
|
||||
corners.sw.lon,
|
||||
bounds.sw.lat,
|
||||
bounds.sw.lon,
|
||||
0);
|
||||
|
||||
const position =
|
||||
@ -141,8 +132,8 @@ export class GeohashGeometryProvider extends GeometryProviderBase {
|
||||
latLon.lat,
|
||||
latLon.lon,
|
||||
0,
|
||||
corners.sw.lat,
|
||||
corners.sw.lon,
|
||||
bounds.sw.lat,
|
||||
bounds.sw.lon,
|
||||
0);
|
||||
|
||||
const left = position[0] - bl[0];
|
||||
@ -150,12 +141,12 @@ export class GeohashGeometryProvider extends GeometryProviderBase {
|
||||
const bottom = position[1] - bl[1];
|
||||
const top = tr[1] - position[1];
|
||||
|
||||
const l: boolean = left < threshold;
|
||||
const r: boolean = right < threshold;
|
||||
const b: boolean = bottom < threshold;
|
||||
const t: boolean = top < threshold;
|
||||
const l = left < threshold;
|
||||
const r = right < threshold;
|
||||
const b = bottom < threshold;
|
||||
const t = top < threshold;
|
||||
|
||||
const cellIds: string[] = [cellId];
|
||||
const cellIds = [cellId];
|
||||
|
||||
if (t) {
|
||||
cellIds.push(neighbors.n);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { CellCorners, CellNeighbors } from "./interfaces/CellCorners";
|
||||
import { CellNeighbors } from "./interfaces/CellCorners";
|
||||
import { LatLon } from "./interfaces/LatLon";
|
||||
|
||||
import { MapillaryError } from "../error/MapillaryError";
|
||||
@ -41,12 +41,17 @@ export abstract class GeometryProviderBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the corners of a cell.
|
||||
* Get the vertices of a cell.
|
||||
*
|
||||
* @description The vertices form a clockwise polygon
|
||||
* in the 2D latitude, longitude space. No assumption
|
||||
* on the position of the first vertex relative to the
|
||||
* others can be made.
|
||||
*
|
||||
* @param {string} cellId - Id of cell.
|
||||
* @returns {CellCorners} Cell corners struct.
|
||||
* @returns {Array<LatLon>} Clockwise polygon.
|
||||
*/
|
||||
public getCorners(cellId: string): CellCorners {
|
||||
public getVertices(cellId: string): LatLon[] {
|
||||
throw new MapillaryError("Not implemented");
|
||||
}
|
||||
|
||||
@ -57,7 +62,7 @@ export abstract class GeometryProviderBase {
|
||||
* @param {LatLon} ne - North east corner of the bounding box.
|
||||
* @returns {CellCorners} Cell corners struct.
|
||||
*/
|
||||
public getNeighbors(cellId: string): CellNeighbors {
|
||||
public getAdjacent(cellId: string): CellNeighbors {
|
||||
throw new MapillaryError("Not implemented");
|
||||
}
|
||||
|
||||
@ -68,8 +73,7 @@ export abstract class GeometryProviderBase {
|
||||
* @returns {string} Cell id for the latitude, longitude.
|
||||
*/
|
||||
public latLonToCellId(
|
||||
latLon: LatLon,
|
||||
relativeLevel?: number)
|
||||
latLon: LatLon)
|
||||
: string {
|
||||
throw new MapillaryError("Not implemented");
|
||||
}
|
||||
@ -88,8 +92,7 @@ export abstract class GeometryProviderBase {
|
||||
*/
|
||||
public latLonToCellIds(
|
||||
latLon: LatLon,
|
||||
threshold: number,
|
||||
relativeLevel?: number)
|
||||
threshold: number)
|
||||
: string[] {
|
||||
throw new MapillaryError("Not implemented");
|
||||
}
|
||||
|
||||
@ -2,10 +2,9 @@ import { S2 } from "s2-geometry";
|
||||
import { enuToGeodetic } from "../geo/GeoCoords";
|
||||
|
||||
import { GeometryProviderBase } from "./GeometryProviderBase";
|
||||
import { CellCorners, CellNeighbors } from "./interfaces/CellCorners";
|
||||
import { CellNeighbors } from "./interfaces/CellCorners";
|
||||
import { LatLon } from "./interfaces/LatLon";
|
||||
|
||||
|
||||
/**
|
||||
* @class S2GeometryProvider
|
||||
*
|
||||
@ -38,7 +37,7 @@ export class S2GeometryProvider extends GeometryProviderBase {
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public getNeighbors(cellId: string): CellNeighbors {
|
||||
public getAdjacent(cellId: string): CellNeighbors {
|
||||
const s2key = S2.idToKey(cellId);
|
||||
const position = s2key.split('/')[1];
|
||||
const level = position.length;
|
||||
@ -60,29 +59,15 @@ export class S2GeometryProvider extends GeometryProviderBase {
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public getCorners(cellId: string): CellCorners {
|
||||
public getVertices(cellId: string): LatLon[] {
|
||||
const key = S2.idToKey(cellId);
|
||||
const cell = S2.S2Cell.FromHilbertQuadKey(key);
|
||||
const corners = cell.getCornerLatLngs();
|
||||
|
||||
let south = Number.POSITIVE_INFINITY;
|
||||
let north = Number.NEGATIVE_INFINITY;
|
||||
let west = Number.POSITIVE_INFINITY;
|
||||
let east = Number.NEGATIVE_INFINITY;
|
||||
|
||||
for (let c of corners) {
|
||||
if (c.lat < south) { south = c.lat; }
|
||||
if (c.lat > north) { north = c.lat; }
|
||||
if (c.lng < west) { west = c.lng; }
|
||||
if (c.lng > east) { east = c.lng; }
|
||||
}
|
||||
|
||||
return {
|
||||
ne: { lat: north, lon: east },
|
||||
nw: { lat: north, lon: west },
|
||||
se: { lat: south, lon: east },
|
||||
sw: { lat: south, lon: west },
|
||||
};
|
||||
return cell
|
||||
.getCornerLatLngs()
|
||||
.map(
|
||||
(c: S2.ILatLng): LatLon => {
|
||||
return { lat: c.lat, lon: c.lng };
|
||||
});
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
@ -93,7 +78,7 @@ export class S2GeometryProvider extends GeometryProviderBase {
|
||||
/** @inheritdoc */
|
||||
public latLonToCellIds(latLon: LatLon, threshold: number): string[] {
|
||||
const cellId = this._latLonToId(latLon, this._level);
|
||||
const neighbors = this.getNeighbors(cellId);
|
||||
const neighbors = this.getAdjacent(cellId);
|
||||
const corners =
|
||||
this._getLatLonBoundingBoxCorners(latLon, threshold);
|
||||
|
||||
@ -129,7 +114,10 @@ export class S2GeometryProvider extends GeometryProviderBase {
|
||||
}
|
||||
|
||||
private _getLatLonBoundingBoxCorners(
|
||||
latLon: LatLon, threshold: number): LatLon[] {
|
||||
latLon: LatLon,
|
||||
threshold: number)
|
||||
: LatLon[] {
|
||||
|
||||
return [
|
||||
[-threshold, threshold, 0],
|
||||
[threshold, threshold, 0],
|
||||
|
||||
@ -31,7 +31,6 @@ import { Container } from "../../viewer/Container";
|
||||
import { Navigator } from "../../viewer/Navigator";
|
||||
import {
|
||||
CellNeighbors,
|
||||
CellCorners,
|
||||
} from "../../api/interfaces/CellCorners";
|
||||
import { ClusterReconstructionContract }
|
||||
from "../../api/contracts/ClusterReconstructionContract";
|
||||
@ -56,6 +55,7 @@ import { SpatialDataScene } from "./SpatialDataScene";
|
||||
import { SpatialDataCache } from "./SpatialDataCache";
|
||||
import { CameraType } from "../../geo/interfaces/CameraType";
|
||||
import { geodeticToEnu } from "../../geo/GeoCoords";
|
||||
import { LatLon } from "../../api/interfaces/LatLon";
|
||||
|
||||
type IntersectEvent = MouseEvent | FocusEvent;
|
||||
|
||||
@ -205,7 +205,7 @@ export class SpatialDataComponent extends Component<SpatialDataConfiguration> {
|
||||
observableOf([
|
||||
hash,
|
||||
this._navigator.api.data.geometry
|
||||
.getNeighbors(hash)[<keyof CellNeighbors>direction]]) :
|
||||
.getAdjacent(hash)[<keyof CellNeighbors>direction]]) :
|
||||
observableOf(this._computeTiles(hash, direction));
|
||||
}),
|
||||
publish<string[]>(),
|
||||
@ -580,7 +580,7 @@ export class SpatialDataComponent extends Component<SpatialDataConfiguration> {
|
||||
|
||||
for (const hash of currentHashes) {
|
||||
const hashNeighbours: CellNeighbors =
|
||||
this._navigator.api.data.geometry.getNeighbors(hash);
|
||||
this._navigator.api.data.geometry.getAdjacent(hash);
|
||||
|
||||
for (const direction in hashNeighbours) {
|
||||
if (!hashNeighbours.hasOwnProperty(direction)) {
|
||||
@ -613,26 +613,21 @@ export class SpatialDataComponent extends Component<SpatialDataConfiguration> {
|
||||
}
|
||||
|
||||
private _computeTileBBox(hash: string, reference: LatLonAlt): number[][] {
|
||||
const corners: CellCorners =
|
||||
this._navigator.api.data.geometry.getCorners(hash);
|
||||
const vertices =
|
||||
this._navigator.api.data.geometry
|
||||
.getVertices(hash)
|
||||
.map(
|
||||
(vertex: LatLon): number[] => {
|
||||
return geodeticToEnu(
|
||||
vertex.lat,
|
||||
vertex.lon,
|
||||
0,
|
||||
reference.lat,
|
||||
reference.lon,
|
||||
reference.alt);
|
||||
});
|
||||
|
||||
const sw = geodeticToEnu(
|
||||
corners.sw.lat,
|
||||
corners.sw.lon,
|
||||
0,
|
||||
reference.lat,
|
||||
reference.lon,
|
||||
reference.alt);
|
||||
|
||||
const ne = geodeticToEnu(
|
||||
corners.ne.lat,
|
||||
corners.ne.lon,
|
||||
0,
|
||||
reference.lat,
|
||||
reference.lon,
|
||||
reference.alt);
|
||||
|
||||
return [sw, ne];
|
||||
return vertices;
|
||||
}
|
||||
|
||||
private _createTransform(node: Node, reference: LatLonAlt): Transform {
|
||||
@ -680,7 +675,7 @@ export class SpatialDataComponent extends Component<SpatialDataConfiguration> {
|
||||
}
|
||||
|
||||
const neighbours: CellNeighbors =
|
||||
this._navigator.api.data.geometry.getNeighbors(currentHash);
|
||||
this._navigator.api.data.geometry.getAdjacent(currentHash);
|
||||
const directionIndex: number = directions.indexOf(direction);
|
||||
const length: number = directions.length;
|
||||
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import * as THREE from "three";
|
||||
import { PointContract } from "../../api/contracts/PointContract";
|
||||
import { ClusterReconstructionContract } from "../../api/contracts/ClusterReconstructionContract";
|
||||
import { ClusterReconstructionContract }
|
||||
from "../../api/contracts/ClusterReconstructionContract";
|
||||
import { MapillaryError } from "../../error/MapillaryError";
|
||||
import { isSpherical } from "../../geo/Geo";
|
||||
import { Transform } from "../../geo/Transform";
|
||||
import { FilterFunction } from "../../graph/FilterCreator";
|
||||
import { Node } from "../../graph/Node";
|
||||
import { SpatialDataConfiguration } from "../interfaces/SpatialDataConfiguration";
|
||||
import { SpatialDataConfiguration }
|
||||
from "../interfaces/SpatialDataConfiguration";
|
||||
import { CameraVisualizationMode } from "./CameraVisualizationMode";
|
||||
import { OriginalPositionMode } from "./OriginalPositionMode";
|
||||
|
||||
@ -65,11 +67,14 @@ abstract class CameraFrameBase extends THREE.Object3D {
|
||||
}
|
||||
|
||||
protected _createBufferGeometry(
|
||||
positions: number[][]): THREE.BufferGeometry {
|
||||
const positionAttribute = new THREE.BufferAttribute(
|
||||
new Float32Array(3 * positions.length), 3)
|
||||
const colorAttribute = new THREE.BufferAttribute(
|
||||
new Float32Array(3 * positions.length), 3)
|
||||
positions: number[][])
|
||||
: THREE.BufferGeometry {
|
||||
const positionAttribute =
|
||||
new THREE.BufferAttribute(
|
||||
new Float32Array(3 * positions.length), 3);
|
||||
const colorAttribute =
|
||||
new THREE.BufferAttribute(
|
||||
new Float32Array(3 * positions.length), 3);
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute("position", positionAttribute);
|
||||
geometry.setAttribute("color", colorAttribute);
|
||||
@ -80,8 +85,8 @@ abstract class CameraFrameBase extends THREE.Object3D {
|
||||
origin: number[],
|
||||
relativePositions: number[][],
|
||||
scale: number,
|
||||
color: string):
|
||||
CameraFrameLine {
|
||||
color: string)
|
||||
: CameraFrameLine {
|
||||
const geometry = this._createBufferGeometry(relativePositions);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
vertexColors: true,
|
||||
@ -97,7 +102,8 @@ abstract class CameraFrameBase extends THREE.Object3D {
|
||||
|
||||
protected _updateColorAttribute(
|
||||
frame: CameraFrameLine | CameraFrameLineSegments,
|
||||
color: string): void {
|
||||
color: string)
|
||||
: void {
|
||||
const [r, g, b] = new THREE.Color(color).toArray();
|
||||
const colorAttribute =
|
||||
<THREE.BufferAttribute>frame.geometry.attributes.color;
|
||||
@ -122,7 +128,8 @@ abstract class CameraFrameBase extends THREE.Object3D {
|
||||
|
||||
protected _updatePositionAttribute(
|
||||
frame: CameraFrameLine | CameraFrameLineSegments,
|
||||
scale: number): void {
|
||||
scale: number)
|
||||
: void {
|
||||
const positionAttribute =
|
||||
<THREE.BufferAttribute>frame.geometry.attributes.position;
|
||||
const positions = <Float32Array>positionAttribute.array;
|
||||
@ -188,7 +195,8 @@ class PerspectiveCameraFrame extends CameraFrameBase {
|
||||
|
||||
private _calculateRelativeDiagonals(
|
||||
transform: Transform,
|
||||
origin: number[]): number[][] {
|
||||
origin: number[])
|
||||
: number[][] {
|
||||
const depth = this._originalSize;
|
||||
const [topLeft, topRight, bottomRight, bottomLeft] =
|
||||
this._makeRelative(
|
||||
@ -211,8 +219,10 @@ class PerspectiveCameraFrame extends CameraFrameBase {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
private _calculateRelativeFrame(transform: Transform, origin: number[]):
|
||||
number[][] {
|
||||
private _calculateRelativeFrame(
|
||||
transform: Transform,
|
||||
origin: number[])
|
||||
: number[][] {
|
||||
const vertices2d: number[][] = [];
|
||||
const vertical = this._verticalFrameSamples;
|
||||
const horizontal = this._horizontalFrameSamples;
|
||||
@ -235,7 +245,8 @@ class PerspectiveCameraFrame extends CameraFrameBase {
|
||||
transform: Transform,
|
||||
scale: number,
|
||||
origin: number[],
|
||||
color: string): CameraFrameLineSegments {
|
||||
color: string)
|
||||
: CameraFrameLineSegments {
|
||||
const positions = this._calculateRelativeDiagonals(transform, origin);
|
||||
const geometry = this._createBufferGeometry(positions);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
@ -256,12 +267,12 @@ class PerspectiveCameraFrame extends CameraFrameBase {
|
||||
transform: Transform,
|
||||
scale: number,
|
||||
origin: number[],
|
||||
color: string): CameraFrameLine {
|
||||
color: string)
|
||||
: CameraFrameLine {
|
||||
const positions = this._calculateRelativeFrame(transform, origin);
|
||||
return this._createCameraFrame(origin, positions, scale, color);
|
||||
}
|
||||
|
||||
|
||||
private _interpolate(a: number, b: number, alpha: number): number {
|
||||
return a + alpha * (b - a);
|
||||
}
|
||||
@ -269,7 +280,8 @@ class PerspectiveCameraFrame extends CameraFrameBase {
|
||||
private _subsample(
|
||||
p1: number[],
|
||||
p2: number[],
|
||||
subsamples: number): number[][] {
|
||||
subsamples: number)
|
||||
: number[][] {
|
||||
if (subsamples < 1) {
|
||||
return [p1, p2];
|
||||
}
|
||||
@ -330,8 +342,10 @@ class SphericalCameraFrame extends CameraFrameBase {
|
||||
this.add(axis, lat, lon1, lon2, lon3, lon4);
|
||||
}
|
||||
|
||||
private _calculateRelativeAxis(transform: Transform, origin: number[]):
|
||||
number[][] {
|
||||
private _calculateRelativeAxis(
|
||||
transform: Transform,
|
||||
origin: number[])
|
||||
: number[][] {
|
||||
const depth = this._originalSize;
|
||||
const north: number[] = transform.unprojectBasic([0.5, 0], depth * 1.1);
|
||||
const south: number[] = transform.unprojectBasic([0.5, 1], depth * 0.8);
|
||||
@ -343,7 +357,8 @@ class SphericalCameraFrame extends CameraFrameBase {
|
||||
basicY: number,
|
||||
numVertices: number,
|
||||
transform: Transform,
|
||||
origin: number[]): number[][] {
|
||||
origin: number[])
|
||||
: number[][] {
|
||||
|
||||
const depth = 0.8 * this._originalSize;
|
||||
const positions: number[][] = [];
|
||||
@ -362,7 +377,8 @@ class SphericalCameraFrame extends CameraFrameBase {
|
||||
basicX: number,
|
||||
numVertices: number,
|
||||
transform: Transform,
|
||||
origin: number[]): number[][] {
|
||||
origin: number[])
|
||||
: number[][] {
|
||||
const scaledDepth = 0.8 * this._originalSize;
|
||||
const positions: number[][] = [];
|
||||
|
||||
@ -381,7 +397,8 @@ class SphericalCameraFrame extends CameraFrameBase {
|
||||
transform: Transform,
|
||||
scale: number,
|
||||
origin: number[],
|
||||
color: string): CameraFrameLine {
|
||||
color: string)
|
||||
: CameraFrameLine {
|
||||
const positions = this._calculateRelativeAxis(transform, origin);
|
||||
return this._createCameraFrame(origin, positions, scale, color);
|
||||
}
|
||||
@ -392,7 +409,8 @@ class SphericalCameraFrame extends CameraFrameBase {
|
||||
transform: Transform,
|
||||
scale: number,
|
||||
origin: number[],
|
||||
color: string): CameraFrameLine {
|
||||
color: string)
|
||||
: CameraFrameLine {
|
||||
const positions = this._calculateRelativeLatitude(
|
||||
basicY, numVertices, transform, origin);
|
||||
return this._createCameraFrame(origin, positions, scale, color);
|
||||
@ -404,7 +422,8 @@ class SphericalCameraFrame extends CameraFrameBase {
|
||||
transform: Transform,
|
||||
scale: number,
|
||||
origin: number[],
|
||||
color: string): CameraFrameLine {
|
||||
color: string)
|
||||
: CameraFrameLine {
|
||||
const positions = this._calculateRelativeLongitude(
|
||||
basicX, numVertices, transform, origin);
|
||||
return this._createCameraFrame(origin, positions, scale, color);
|
||||
@ -450,7 +469,8 @@ class ClusterPoints extends THREE.Points {
|
||||
|
||||
private _getArrays(
|
||||
reconstruction: ClusterReconstructionContract,
|
||||
translation: number[]): [Float32Array, Float32Array] {
|
||||
translation: number[])
|
||||
: [Float32Array, Float32Array] {
|
||||
const points = Object
|
||||
.keys(reconstruction.points)
|
||||
.map(
|
||||
@ -482,9 +502,9 @@ class ClusterPoints extends THREE.Points {
|
||||
}
|
||||
|
||||
class TileLine extends THREE.Line {
|
||||
constructor(bbox: number[][]) {
|
||||
constructor(vertices: number[][]) {
|
||||
super();
|
||||
this.geometry = this._createGeometry(bbox);
|
||||
this.geometry = this._createGeometry(vertices);
|
||||
this.material = new THREE.LineBasicMaterial();
|
||||
}
|
||||
|
||||
@ -493,27 +513,18 @@ class TileLine extends THREE.Line {
|
||||
(<THREE.Material>this.material).dispose();
|
||||
}
|
||||
|
||||
private _createGeometry(bbox: number[][]): THREE.BufferGeometry {
|
||||
const sw: number[] = bbox[0];
|
||||
const ne: number[] = bbox[1];
|
||||
|
||||
const vertices = [
|
||||
sw.slice(),
|
||||
[sw[0], ne[1], (sw[2] + ne[2]) / 2],
|
||||
ne.slice(),
|
||||
[ne[0], sw[1], (sw[2] + ne[2]) / 2],
|
||||
sw.slice(),
|
||||
];
|
||||
|
||||
const positions = new Float32Array(3 * vertices.length);
|
||||
private _createGeometry(vertices: number[][]): THREE.BufferGeometry {
|
||||
const polygon = vertices.slice()
|
||||
polygon.push(vertices[0]);
|
||||
const positions = new Float32Array(3 * (vertices.length + 1));
|
||||
let index = 0;
|
||||
for (const vertex of vertices) {
|
||||
for (const vertex of polygon) {
|
||||
positions[index++] = vertex[0];
|
||||
positions[index++] = vertex[1];
|
||||
positions[index++] = vertex[2];
|
||||
}
|
||||
|
||||
const geometry: THREE.BufferGeometry = new THREE.BufferGeometry();
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute(
|
||||
"position",
|
||||
new THREE.BufferAttribute(positions, 3));
|
||||
@ -565,8 +576,8 @@ class PositionLine extends THREE.Line {
|
||||
private _createGeometry(
|
||||
transform: Transform,
|
||||
originalPosition: number[],
|
||||
altitude: number):
|
||||
THREE.BufferGeometry {
|
||||
altitude: number)
|
||||
: THREE.BufferGeometry {
|
||||
const vertices = [
|
||||
[
|
||||
originalPosition[0],
|
||||
@ -583,7 +594,7 @@ class PositionLine extends THREE.Line {
|
||||
positions[index++] = vertex[2];
|
||||
}
|
||||
|
||||
const geometry: THREE.BufferGeometry = new THREE.BufferGeometry();
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute(
|
||||
"position",
|
||||
new THREE.BufferAttribute(positions, 3));
|
||||
@ -1112,12 +1123,12 @@ export class SpatialDataScene {
|
||||
this._needsRender = true;
|
||||
}
|
||||
|
||||
public addTile(bbox: number[][], cellId: string): void {
|
||||
public addTile(vertices: number[][], cellId: string): void {
|
||||
if (this.hasTile(cellId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tile = new TileLine(bbox);
|
||||
const tile = new TileLine(vertices);
|
||||
this._tiles[cellId] = new THREE.Object3D();
|
||||
this._tiles[cellId].visible = this._tilesVisible;
|
||||
this._tiles[cellId].add(tile);
|
||||
|
||||
@ -41,6 +41,5 @@ export { SpatialImageEnt } from "../api/ents/SpatialImageEnt";
|
||||
export { URLEnt } from "../api/ents/URLEnt";
|
||||
|
||||
// Type
|
||||
export { CellCorners } from "../api/interfaces/CellCorners";
|
||||
export { LatLon } from "../api/interfaces/LatLon";
|
||||
export { LatLonAlt } from "../api/interfaces/LatLonAlt";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user