mapillary-js
Version:
A WebGL interactive street imagery library
155 lines (117 loc) • 4.85 kB
text/typescript
import * as THREE from "three";
import * as Lines from "../../geo/Lines";
import { Transform } from "../../geo/Transform";
import { ViewportCoords } from "../../geo/ViewportCoords";
function basicBoundaryPoints(pointsPerSide: number): number[][] {
let points: number[][] = [];
let os: number[][] = [[0, 0], [1, 0], [1, 1], [0, 1]];
let ds: number[][] = [[1, 0], [0, 1], [-1, 0], [0, -1]];
for (let side: number = 0; side < 4; ++side) {
let o: number[] = os[side];
let d: number[] = ds[side];
for (let i: number = 0; i < pointsPerSide; ++i) {
points.push([o[0] + d[0] * i / pointsPerSide,
o[1] + d[1] * i / pointsPerSide]);
}
}
return points;
}
function insideViewport(x: number, y: number): boolean {
return x >= -1 && x <= 1 && y >= -1 && y <= 1;
}
function insideBasic(x: number, y: number): boolean {
return x >= 0 && x <= 1 && y >= 0 && y <= 1;
}
export function viewportDistances(transform: Transform, perspective: THREE.PerspectiveCamera, viewportCoords: ViewportCoords): number[] {
const boundaryPointsBasic: number[][] = basicBoundaryPoints(100);
const boundaryPointsViewport: number[][] = boundaryPointsBasic
.map(
(basic: number[]) => {
return viewportCoords.basicToViewportSafe(basic[0], basic[1], transform, perspective);
});
const visibleBoundaryPoints: number[][] = [];
const viewportSides: Lines.Point[] = [
{ x: -1, y: 1 },
{ x: 1, y: 1 },
{ x: 1, y: -1 },
{ x: -1, y: -1 }];
const intersections: boolean[] = [false, false, false, false];
for (let i: number = 0; i < boundaryPointsViewport.length; i++) {
const p1: number[] = boundaryPointsViewport[i];
const p2: number[] = boundaryPointsViewport[(i + 1) % boundaryPointsViewport.length];
if (p1 === null) {
continue;
}
if (p2 === null) {
if (insideViewport(p1[0], p1[1])) {
visibleBoundaryPoints.push(p1);
}
continue;
}
const [x1, y1]: number[] = p1;
const [x2, y2]: number[] = p2;
if (insideViewport(x1, y1)) {
if (insideViewport(x2, y2)) {
visibleBoundaryPoints.push(p1);
} else {
for (let side: number = 0; side < 4; side++) {
const s1: Lines.Segment = { p1: { x: x1, y: y1 }, p2: { x: x2, y: y2 } };
const s2: Lines.Segment = { p1: viewportSides[side], p2: viewportSides[(side + 1) % 4] };
const intersecting: boolean = Lines.segmentsIntersect(s1, s2);
if (intersecting) {
const intersection: Lines.Point = Lines.segmentIntersection(s1, s2);
visibleBoundaryPoints.push(p1, [intersection.x, intersection.y]);
intersections[side] = true;
}
}
}
}
}
const [topLeftBasicX, topLeftBasicY]: number[] =
viewportCoords.viewportToBasic(-1, 1, transform, perspective);
const [topRightBasicX, topRightBasicY]: number[] =
viewportCoords.viewportToBasic(1, 1, transform, perspective);
const [bottomRightBasicX, bottomRightBasicY]: number[] =
viewportCoords.viewportToBasic(1, -1, transform, perspective);
const [bottomLeftBasicX, bottomLeftBasicY]: number[] =
viewportCoords.viewportToBasic(-1, -1, transform, perspective);
if (insideBasic(topLeftBasicX, topLeftBasicY)) {
intersections[3] = intersections[0] = true;
}
if (insideBasic(topRightBasicX, topRightBasicY)) {
intersections[0] = intersections[1] = true;
}
if (insideBasic(bottomRightBasicX, bottomRightBasicY)) {
intersections[1] = intersections[2] = true;
}
if (insideBasic(bottomLeftBasicX, bottomLeftBasicY)) {
intersections[2] = intersections[3] = true;
}
const maximums: number[] = [-1, -1, 1, 1];
for (let visibleBoundaryPoint of visibleBoundaryPoints) {
const x: number = visibleBoundaryPoint[0];
const y: number = visibleBoundaryPoint[1];
if (x > maximums[1]) {
maximums[1] = x;
}
if (x < maximums[3]) {
maximums[3] = x;
}
if (y > maximums[0]) {
maximums[0] = y;
}
if (y < maximums[2]) {
maximums[2] = y;
}
}
const boundary: number[] = [1, 1, -1, -1];
const distances: number[] = [];
for (let side: number = 0; side < 4; side++) {
if (intersections[side]) {
distances.push(0);
continue;
}
distances.push(Math.abs(boundary[side] - maximums[side]));
}
return distances;
}