From efddfd271c7cad80bfed4e87ea75be0ddc8dc41e Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 17 Mar 2018 09:24:39 -0400 Subject: [PATCH] More flow coverage of `geo` submodule (re: #3744) also: - Move types to index and export/import them - add return types --- modules/geo/extent.js | 3 +-- modules/geo/geo.js | 20 ++++++++++---------- modules/geo/geom.js | 35 ++++++++++++++++++++--------------- modules/geo/index.js | 5 +++++ modules/geo/raw_mercator.js | 4 +--- modules/geo/vector.js | 22 +++++++++++----------- 6 files changed, 48 insertions(+), 41 deletions(-) diff --git a/modules/geo/extent.js b/modules/geo/extent.js index 419b2f8ab..cc3aa1f26 100644 --- a/modules/geo/extent.js +++ b/modules/geo/extent.js @@ -1,6 +1,5 @@ // @flow -type Vec2 = [number, number]; -type Mat2 = [Vec2, Vec2]; +import type { Vec2, Mat2 } from '.'; import _extend from 'lodash-es/extend'; diff --git a/modules/geo/geo.js b/modules/geo/geo.js index 9cc0d0a57..372f757e8 100644 --- a/modules/geo/geo.js +++ b/modules/geo/geo.js @@ -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; } diff --git a/modules/geo/geom.js b/modules/geo/geom.js index d9eec87a0..5dab42a48 100644 --- a/modules/geo/geom.js +++ b/modules/geo/geom.js @@ -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, angle: number, around: Vec2): Array { + 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, 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, inactiveNodes: Array, 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, 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, b: Array): ?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, path2: Array): Array { 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, path2: Array): 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): 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, inner: Array): boolean { return _every(inner, function(point) { return geoPointInPolygon(point, outer); }); } -export function geoPolygonIntersectsPolygon(outer, inner, checkSegments) { +export function geoPolygonIntersectsPolygon(outer: Array, inner: Array, 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): 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; diff --git a/modules/geo/index.js b/modules/geo/index.js index 8252336ab..b872af5ec 100644 --- a/modules/geo/index.js +++ b/modules/geo/index.js @@ -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'; diff --git a/modules/geo/raw_mercator.js b/modules/geo/raw_mercator.js index 3129532ff..a4b98bef7 100644 --- a/modules/geo/raw_mercator.js +++ b/modules/geo/raw_mercator.js @@ -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, diff --git a/modules/geo/vector.js b/modules/geo/vector.js index 87e066805..870302d1f 100644 --- a/modules/geo/vector.js +++ b/modules/geo/vector.js @@ -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]);