More flow coverage of geo submodule

(re: #3744)

also:
- Move types to index and export/import them
- add return types
This commit is contained in:
Bryan Housel
2018-03-17 09:24:39 -04:00
parent 3e47ca005c
commit efddfd271c
6 changed files with 48 additions and 41 deletions

View File

@@ -1,6 +1,5 @@
// @flow
type Vec2 = [number, number];
type Mat2 = [Vec2, Vec2];
import type { Vec2, Mat2 } from '.';
import _extend from 'lodash-es/extend';

View File

@@ -1,5 +1,5 @@
// @flow
type Vec2 = [number, number];
import type { Vec2 } from '.';
// constants
var TAU = 2 * Math.PI;
@@ -7,29 +7,29 @@ var EQUATORIAL_RADIUS = 6356752.314245179;
var POLAR_RADIUS = 6378137.0;
export function geoLatToMeters(dLat: number) {
export function geoLatToMeters(dLat: number): number {
return dLat * (TAU * POLAR_RADIUS / 360);
}
export function geoLonToMeters(dLon: number, atLat: number) {
export function geoLonToMeters(dLon: number, atLat: number): number {
return Math.abs(atLat) >= 90 ? 0 :
dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
}
export function geoMetersToLat(m: number) {
export function geoMetersToLat(m: number): number {
return m / (TAU * POLAR_RADIUS / 360);
}
export function geoMetersToLon(m: number, atLat: number) {
export function geoMetersToLon(m: number, atLat: number): number {
return Math.abs(atLat) >= 90 ? 0 :
m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
}
export function geoMetersToOffset(meters: Vec2, tileSize?: number) {
export function geoMetersToOffset(meters: Vec2, tileSize?: number): Vec2 {
tileSize = tileSize || 256;
return [
meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS),
@@ -38,7 +38,7 @@ export function geoMetersToOffset(meters: Vec2, tileSize?: number) {
}
export function geoOffsetToMeters(offset: Vec2, tileSize?: number) {
export function geoOffsetToMeters(offset: Vec2, tileSize?: number): Vec2 {
tileSize = tileSize || 256;
return [
offset[0] * TAU * EQUATORIAL_RADIUS / tileSize,
@@ -48,7 +48,7 @@ export function geoOffsetToMeters(offset: Vec2, tileSize?: number) {
// Equirectangular approximation of spherical distances on Earth
export function geoSphericalDistance(a: Vec2, b: Vec2) {
export function geoSphericalDistance(a: Vec2, b: Vec2): number {
var x: number = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
var y: number = geoLatToMeters(a[1] - b[1]);
return Math.sqrt((x * x) + (y * y));
@@ -56,7 +56,7 @@ export function geoSphericalDistance(a: Vec2, b: Vec2) {
// scale to zoom
export function geoScaleToZoom(k: number, tileSize?: number) {
export function geoScaleToZoom(k: number, tileSize?: number): number {
tileSize = tileSize || 256;
var log2ts: number = Math.log(tileSize) * Math.LOG2E;
return Math.log(k * TAU) / Math.LN2 - log2ts;
@@ -64,7 +64,7 @@ export function geoScaleToZoom(k: number, tileSize?: number) {
// zoom to scale
export function geoZoomToScale(z: number, tileSize?: number) {
export function geoZoomToScale(z: number, tileSize?: number): number {
tileSize = tileSize || 256;
return tileSize * Math.pow(2, z) / TAU;
}

View File

@@ -1,3 +1,8 @@
// @flow
import type { Vec2 } from '.';
type Node = { id: string, loc: Vec2 };
type Edge = { index: number, distance: number, loc: ?Vec2 };
import _every from 'lodash-es/every';
import _some from 'lodash-es/some';
@@ -14,18 +19,18 @@ import {
// Return the counterclockwise angle in the range (-pi, pi)
// between the positive X axis and the line intersecting a and b.
export function geoAngle(a, b, projection) {
export function geoAngle(a: Node, b: Node, projection: (Vec2) => Vec2): number {
return geoVecAngle(projection(a.loc), projection(b.loc));
}
export function geoEdgeEqual(a, b) {
export function geoEdgeEqual(a: Vec2, b: Vec2): boolean {
return (a[0] === b[0] && a[1] === b[1]) ||
(a[0] === b[1] && a[1] === b[0]);
}
// Rotate all points counterclockwise around a pivot point by given angle
export function geoRotate(points, angle, around) {
return points.map(function(point) {
export function geoRotate(points: Array<Vec2>, angle: number, around: Vec2): Array<Vec2> {
return points.map(function(point: Vec2) {
var radial = geoVecSubtract(point, around);
return [
radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
@@ -39,7 +44,7 @@ export function geoRotate(points, angle, around) {
// projection onto that edge, if such a projection exists, or the distance to
// the closest vertex on that edge. Returns an object with the `index` of the
// chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
export function geoChooseEdge(nodes, point, projection, activeID) {
export function geoChooseEdge(nodes: Array<Node>, point: Vec2, projection: (loc: Vec2) => Vec2, activeID?: string): ?Edge {
var dist = geoVecLength;
var points = nodes.map(function(n) { return projection(n.loc); });
var ids = nodes.map(function(n) { return n.id; });
@@ -84,7 +89,7 @@ export function geoChooseEdge(nodes, point, projection, activeID) {
// This is used to test e.g. multipolygon rings that cross
// `activeNodes` is the ring containing the activeID being dragged.
// `inactiveNodes` is the other ring to test against
export function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
export function geoHasLineIntersections(activeNodes: Array<Node>, inactiveNodes: Array<Node>, activeID?: string): boolean {
var actives = [];
var inactives = [];
var j, k, n1, n2, segment;
@@ -125,7 +130,7 @@ export function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
// Test active (dragged or drawing) segments against inactive segments
// This is used to test whether a way intersects with itself.
export function geoHasSelfIntersections(nodes, activeID) {
export function geoHasSelfIntersections(nodes: Array<Node>, activeID?: string): boolean {
var actives = [];
var inactives = [];
var j, k;
@@ -175,7 +180,7 @@ export function geoHasSelfIntersections(nodes, activeID) {
// From https://github.com/pgkelley4/line-segments-intersect
// This uses the vector cross product approach described below:
// http://stackoverflow.com/a/565282/786339
export function geoLineIntersection(a, b) {
export function geoLineIntersection(a: Array<Vec2>, b: Array<Vec2>): ?Vec2 {
var p = [a[0][0], a[0][1]];
var p2 = [a[1][0], a[1][1]];
var q = [b[0][0], b[0][1]];
@@ -198,7 +203,7 @@ export function geoLineIntersection(a, b) {
}
export function geoPathIntersections(path1, path2) {
export function geoPathIntersections(path1: Array<Vec2>, path2: Array<Vec2>): Array<Vec2> {
var intersections = [];
for (var i = 0; i < path1.length - 1; i++) {
for (var j = 0; j < path2.length - 1; j++) {
@@ -213,7 +218,7 @@ export function geoPathIntersections(path1, path2) {
return intersections;
}
export function geoPathHasIntersections(path1, path2) {
export function geoPathHasIntersections(path1: Array<Vec2>, path2: Array<Vec2>): boolean {
for (var i = 0; i < path1.length - 1; i++) {
for (var j = 0; j < path2.length - 1; j++) {
var a = [ path1[i], path1[i+1] ];
@@ -237,7 +242,7 @@ export function geoPathHasIntersections(path1, path2) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
//
export function geoPointInPolygon(point, polygon) {
export function geoPointInPolygon(point: Vec2, polygon: Array<Vec2>): boolean {
var x = point[0];
var y = point[1];
var inside = false;
@@ -257,14 +262,14 @@ export function geoPointInPolygon(point, polygon) {
}
export function geoPolygonContainsPolygon(outer, inner) {
export function geoPolygonContainsPolygon(outer: Array<Vec2>, inner: Array<Vec2>): boolean {
return _every(inner, function(point) {
return geoPointInPolygon(point, outer);
});
}
export function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
export function geoPolygonIntersectsPolygon(outer: Array<Vec2>, inner: Array<Vec2>, checkSegments: boolean): boolean {
function testPoints(outer, inner) {
return _some(inner, function(point) {
return geoPointInPolygon(point, outer);
@@ -275,7 +280,7 @@ export function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
}
export function geoPathLength(path) {
export function geoPathLength(path: Array<Vec2>): number {
var length = 0;
for (var i = 0; i < path.length - 1; i++) {
length += geoVecLength(path[i], path[i + 1]);
@@ -286,7 +291,7 @@ export function geoPathLength(path) {
// If the given point is at the edge of the padded viewport,
// return a vector that will nudge the viewport in that direction
export function geoViewportEdge(point, dimensions) {
export function geoViewportEdge(point: Vec2, dimensions: Vec2): ?Vec2 {
var pad = [80, 20, 50, 20]; // top, right, bottom, left
var x = 0;
var y = 0;

View File

@@ -1,3 +1,8 @@
// @flow
export type Vec2 = [number, number];
export type Mat2 = [Vec2, Vec2];
export type Transform = { x: number, y: number, k: number };
export { geoExtent } from './extent.js';
export { geoLatToMeters } from './geo.js';

View File

@@ -1,7 +1,5 @@
// @flow
type Vec2 = [number, number];
type Mat2 = [Vec2, Vec2];
type Transform = { x: number, y: number, k: number };
import type { Mat2, Vec2, Transform } from '.';
import {
geoMercatorRaw as d3_geoMercatorRaw,

View File

@@ -1,8 +1,8 @@
// @flow
type Vec2 = [number, number];
import type { Vec2 } from '.';
// vector equals
export function geoVecEqual(a: Vec2, b: Vec2, epsilon?: number) {
export function geoVecEqual(a: Vec2, b: Vec2, epsilon?: number): boolean {
if (epsilon) {
return (Math.abs(a[0] - b[0]) <= epsilon) && (Math.abs(a[1] - b[1]) <= epsilon);
} else {
@@ -11,27 +11,27 @@ export function geoVecEqual(a: Vec2, b: Vec2, epsilon?: number) {
}
// vector addition
export function geoVecAdd(a: Vec2, b: Vec2) {
export function geoVecAdd(a: Vec2, b: Vec2): Vec2 {
return [ a[0] + b[0], a[1] + b[1] ];
}
// vector subtraction
export function geoVecSubtract(a: Vec2, b: Vec2) {
export function geoVecSubtract(a: Vec2, b: Vec2): Vec2 {
return [ a[0] - b[0], a[1] - b[1] ];
}
// vector scaling
export function geoVecScale(a: Vec2, mag: number) {
export function geoVecScale(a: Vec2, mag: number): Vec2 {
return [ a[0] * mag, a[1] * mag ];
}
// vector rounding (was: geoRoundCoordinates)
export function geoVecFloor(a: Vec2) {
export function geoVecFloor(a: Vec2): Vec2 {
return [ Math.floor(a[0]), Math.floor(a[1]) ];
}
// linear interpolation
export function geoVecInterp(a: Vec2, b: Vec2, t: number) {
export function geoVecInterp(a: Vec2, b: Vec2, t: number): Vec2 {
return [
a[0] + (b[0] - a[0]) * t,
a[1] + (b[1] - a[1]) * t
@@ -39,7 +39,7 @@ export function geoVecInterp(a: Vec2, b: Vec2, t: number) {
}
// http://jsperf.com/id-dist-optimization
export function geoVecLength(a: Vec2, b: Vec2) {
export function geoVecLength(a: Vec2, b: Vec2): number {
var x: number = a[0] - b[0];
var y: number = a[1] - b[1];
return Math.sqrt((x * x) + (y * y));
@@ -47,12 +47,12 @@ export function geoVecLength(a: Vec2, b: Vec2) {
// Return the counterclockwise angle in the range (-pi, pi)
// between the positive X axis and the line intersecting a and b.
export function geoVecAngle(a: Vec2, b: Vec2) {
export function geoVecAngle(a: Vec2, b: Vec2): number {
return Math.atan2(b[1] - a[1], b[0] - a[0]);
}
// dot product
export function geoVecDot(a: Vec2, b: Vec2, origin?: Vec2) {
export function geoVecDot(a: Vec2, b: Vec2, origin?: Vec2): number {
origin = origin || [0, 0];
return (a[0] - origin[0]) * (b[0] - origin[0]) +
(a[1] - origin[1]) * (b[1] - origin[1]);
@@ -61,7 +61,7 @@ export function geoVecDot(a: Vec2, b: Vec2, origin?: Vec2) {
// 2D cross product of OA and OB vectors, returns magnitude of Z vector
// Returns a positive value, if OAB makes a counter-clockwise turn,
// negative for clockwise turn, and zero if the points are collinear.
export function geoVecCross(a: Vec2, b: Vec2, origin?: Vec2) {
export function geoVecCross(a: Vec2, b: Vec2, origin?: Vec2): number {
origin = origin || [0, 0];
return (a[0] - origin[0]) * (b[1] - origin[1]) -
(a[1] - origin[1]) * (b[0] - origin[0]);