From 3e47ca005c0b2fea15de4e7de8560cf992bd5062 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 17 Mar 2018 01:18:05 -0400 Subject: [PATCH] Started adding Flow annotations to functions in the `geo` submodule (re: #3744) --- .flowconfig | 1 + modules/geo/extent.js | 30 +++++++++++++++++------------ modules/geo/geo.js | 29 ++++++++++++++-------------- modules/geo/raw_mercator.js | 38 +++++++++++++++++++++---------------- modules/geo/vector.js | 27 ++++++++++++++------------ 5 files changed, 71 insertions(+), 54 deletions(-) diff --git a/.flowconfig b/.flowconfig index 1fed44533..a4fc48427 100644 --- a/.flowconfig +++ b/.flowconfig @@ -7,5 +7,6 @@ [lints] [options] +include_warnings=true [strict] diff --git a/modules/geo/extent.js b/modules/geo/extent.js index f8eb9904b..419b2f8ab 100644 --- a/modules/geo/extent.js +++ b/modules/geo/extent.js @@ -1,3 +1,7 @@ +// @flow +type Vec2 = [number, number]; +type Mat2 = [Vec2, Vec2]; + import _extend from 'lodash-es/extend'; import { @@ -6,9 +10,10 @@ import { } from './index'; -export function geoExtent(min, max) { - if (!(this instanceof geoExtent)) return new geoExtent(min, max); - if (min instanceof geoExtent) { +export function geoExtent(min?: Vec2 | Mat2, max?: Vec2) { + if (!(this instanceof geoExtent)) { + return new geoExtent(min, max); + } else if (min instanceof geoExtent) { return min; } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) { this[0] = min[0]; @@ -19,6 +24,7 @@ export function geoExtent(min, max) { } } +// $FlowFixMe geoExtent.prototype = new Array(2); _extend(geoExtent.prototype, { @@ -34,8 +40,8 @@ _extend(geoExtent.prototype, { extend: function(obj) { if (!(obj instanceof geoExtent)) obj = new geoExtent(obj); return geoExtent( - [Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])], - [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])] + [(Math.min(obj[0][0], this[0][0]): number), (Math.min(obj[0][1], this[0][1]): number)], + [(Math.max(obj[1][0], this[1][0]): number), (Math.max(obj[1][1], this[1][1]): number)] ); }, @@ -101,16 +107,16 @@ _extend(geoExtent.prototype, { intersection: function(obj) { if (!this.intersects(obj)) return new geoExtent(); return new geoExtent( - [Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])], - [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])] + [(Math.max(obj[0][0], this[0][0]): number), (Math.max(obj[0][1], this[0][1]): number)], + [(Math.min(obj[1][0], this[1][0]): number), (Math.min(obj[1][1], this[1][1]): number)] ); }, percentContainedIn: function(obj) { if (!(obj instanceof geoExtent)) obj = new geoExtent(obj); - var a1 = this.intersection(obj).area(), - a2 = this.area(); + var a1 = this.intersection(obj).area(); + var a2 = this.area(); if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) { return 0; @@ -120,9 +126,9 @@ _extend(geoExtent.prototype, { }, - padByMeters: function(meters) { - var dLat = geoMetersToLat(meters), - dLon = geoMetersToLon(meters, this.center()[1]); + padByMeters: function(meters: number) { + var dLat: number = geoMetersToLat(meters); + var dLon: number = geoMetersToLon(meters, this.center()[1]); return geoExtent( [this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat] diff --git a/modules/geo/geo.js b/modules/geo/geo.js index 639887bac..9cc0d0a57 100644 --- a/modules/geo/geo.js +++ b/modules/geo/geo.js @@ -1,32 +1,35 @@ +// @flow +type Vec2 = [number, number]; + // constants var TAU = 2 * Math.PI; var EQUATORIAL_RADIUS = 6356752.314245179; var POLAR_RADIUS = 6378137.0; -export function geoLatToMeters(dLat) { +export function geoLatToMeters(dLat: number) { return dLat * (TAU * POLAR_RADIUS / 360); } -export function geoLonToMeters(dLon, atLat) { +export function geoLonToMeters(dLon: number, atLat: number) { return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180))); } -export function geoMetersToLat(m) { +export function geoMetersToLat(m: number) { return m / (TAU * POLAR_RADIUS / 360); } -export function geoMetersToLon(m, atLat) { +export function geoMetersToLon(m: number, atLat: number) { return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180))); } -export function geoMetersToOffset(meters, tileSize) { +export function geoMetersToOffset(meters: Vec2, tileSize?: number) { tileSize = tileSize || 256; return [ meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), @@ -35,7 +38,7 @@ export function geoMetersToOffset(meters, tileSize) { } -export function geoOffsetToMeters(offset, tileSize) { +export function geoOffsetToMeters(offset: Vec2, tileSize?: number) { tileSize = tileSize || 256; return [ offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, @@ -45,26 +48,24 @@ export function geoOffsetToMeters(offset, tileSize) { // Equirectangular approximation of spherical distances on Earth -export function geoSphericalDistance(a, b) { - var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2); - var y = geoLatToMeters(a[1] - b[1]); +export function geoSphericalDistance(a: Vec2, b: Vec2) { + 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)); } // scale to zoom -export function geoScaleToZoom(k, tileSize) { +export function geoScaleToZoom(k: number, tileSize?: number) { tileSize = tileSize || 256; - var log2ts = Math.log(tileSize) * Math.LOG2E; + var log2ts: number = Math.log(tileSize) * Math.LOG2E; return Math.log(k * TAU) / Math.LN2 - log2ts; } // zoom to scale -export function geoZoomToScale(z, tileSize) { +export function geoZoomToScale(z: number, tileSize?: number) { tileSize = tileSize || 256; return tileSize * Math.pow(2, z) / TAU; } - - diff --git a/modules/geo/raw_mercator.js b/modules/geo/raw_mercator.js index 1ec4b82bf..3129532ff 100644 --- a/modules/geo/raw_mercator.js +++ b/modules/geo/raw_mercator.js @@ -1,3 +1,8 @@ +// @flow +type Vec2 = [number, number]; +type Mat2 = [Vec2, Vec2]; +type Transform = { x: number, y: number, k: number }; + import { geoMercatorRaw as d3_geoMercatorRaw, geoTransform as d3_geoTransform @@ -15,32 +20,33 @@ import { * Resampling */ export function geoRawMercator() { - var project = d3_geoMercatorRaw, - k = 512 / Math.PI, // scale - x = 0, y = 0, // translate - clipExtent = [[0, 0], [0, 0]]; + var project = d3_geoMercatorRaw; + var k: number = 512 / Math.PI; // scale + var x: number = 0; + var y: number = 0; // translate + var clipExtent: Mat2 = [[0, 0], [0, 0]]; - function projection(point) { + function projection(point: Vec2) { point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180); return [point[0] * k + x, y - point[1] * k]; } - projection.invert = function(point) { + projection.invert = function(point: Vec2) { point = project.invert((point[0] - x) / k, (y - point[1]) / k); return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI]; }; - projection.scale = function(_) { + projection.scale = function(_: number) { if (!arguments.length) return k; k = +_; return projection; }; - projection.translate = function(_) { + projection.translate = function(_: Vec2) { if (!arguments.length) return [x, y]; x = +_[0]; y = +_[1]; @@ -48,26 +54,26 @@ export function geoRawMercator() { }; - projection.clipExtent = function(_) { + projection.clipExtent = function(_: Mat2) { if (!arguments.length) return clipExtent; clipExtent = _; return projection; }; - projection.transform = function(_) { + projection.transform = function(obj: Transform) { if (!arguments.length) return d3_zoomIdentity.translate(x, y).scale(k); - x = +_.x; - y = +_.y; - k = +_.k; + x = +obj.x; + y = +obj.y; + k = +obj.k; return projection; }; projection.stream = d3_geoTransform({ - point: function(x, y) { - x = projection([x, y]); - this.stream.point(x[0], x[1]); + point: function(x: number, y: number) { + var vec: Vec2 = projection([x, y]); + this.stream.point(vec[0], vec[1]); } }).stream; diff --git a/modules/geo/vector.js b/modules/geo/vector.js index e67a6d176..87e066805 100644 --- a/modules/geo/vector.js +++ b/modules/geo/vector.js @@ -1,5 +1,8 @@ +// @flow +type Vec2 = [number, number]; + // vector equals -export function geoVecEqual(a, b, epsilon) { +export function geoVecEqual(a: Vec2, b: Vec2, epsilon?: number) { if (epsilon) { return (Math.abs(a[0] - b[0]) <= epsilon) && (Math.abs(a[1] - b[1]) <= epsilon); } else { @@ -8,27 +11,27 @@ export function geoVecEqual(a, b, epsilon) { } // vector addition -export function geoVecAdd(a, b) { +export function geoVecAdd(a: Vec2, b: Vec2) { return [ a[0] + b[0], a[1] + b[1] ]; } // vector subtraction -export function geoVecSubtract(a, b) { +export function geoVecSubtract(a: Vec2, b: Vec2) { return [ a[0] - b[0], a[1] - b[1] ]; } // vector scaling -export function geoVecScale(a, mag) { +export function geoVecScale(a: Vec2, mag: number) { return [ a[0] * mag, a[1] * mag ]; } // vector rounding (was: geoRoundCoordinates) -export function geoVecFloor(a) { +export function geoVecFloor(a: Vec2) { return [ Math.floor(a[0]), Math.floor(a[1]) ]; } // linear interpolation -export function geoVecInterp(a, b, t) { +export function geoVecInterp(a: Vec2, b: Vec2, t: number) { return [ a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t @@ -36,20 +39,20 @@ export function geoVecInterp(a, b, t) { } // http://jsperf.com/id-dist-optimization -export function geoVecLength(a, b) { - var x = a[0] - b[0]; - var y = a[1] - b[1]; +export function geoVecLength(a: Vec2, b: Vec2) { + var x: number = a[0] - b[0]; + var y: number = a[1] - b[1]; return Math.sqrt((x * x) + (y * y)); } // 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, b) { +export function geoVecAngle(a: Vec2, b: Vec2) { return Math.atan2(b[1] - a[1], b[0] - a[0]); } // dot product -export function geoVecDot(a, b, origin) { +export function geoVecDot(a: Vec2, b: Vec2, origin?: Vec2) { origin = origin || [0, 0]; return (a[0] - origin[0]) * (b[0] - origin[0]) + (a[1] - origin[1]) * (b[1] - origin[1]); @@ -58,7 +61,7 @@ export function geoVecDot(a, b, origin) { // 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, b, origin) { +export function geoVecCross(a: Vec2, b: Vec2, origin?: Vec2) { origin = origin || [0, 0]; return (a[0] - origin[0]) * (b[1] - origin[1]) - (a[1] - origin[1]) * (b[0] - origin[0]);