import Projection from './projection' /* */ export default class Robinson extends Projection { constructor(lng = 0) { super() this.lng0 = lng this.lengthOfParallel = [ 1.0, 0.9986, 0.9954, 0.99, 0.9822, 0.973, 0.96, 0.9427, 0.9216, 0.8962, 0.8679, 0.835, 0.7986, 0.7597, 0.7186, 0.6732, 0.6213, 0.5722, 0.5322 ] this.distancesFromEquator = [ 0.0, 0.062, 0.124, 0.186, 0.248, 0.31, 0.372, 0.434, 0.4958, 0.5571, 0.6176, 0.6769, 0.7346, 0.7903, 0.8435, 0.8936, 0.9394, 0.9761, 1.0 ] } forward(coords) { let { x: lat, y: lng } = coords lng = this._adjustLng(lng) // Get the required indices, the remainder in between low and hight as ratio // and the sign of the found indices, as the tables are only in positive direction. let { low, high, ratio, sign } = this._getInterpolationValues(lat, 90) // Values that lie inbetween two indices are interpolated. let y = this._interpolate(this.distancesFromEquator[low], this.distancesFromEquator[high], ratio) // Reapply the sign to the vertical position. y *= sign // The center of the projection is in the center of the map. Therefore we shift the // center to the top left corner. y = 1 - (y + 1) / 2 // The lengthOfParallel table provides us with the corresponding scaling factor // for a specific latitude. Inbetween values are interpolated as before. let proportionalLength = this._interpolate(this.lengthOfParallel[low], this.lengthOfParallel[high], ratio) //To normalize the value to a range from -1 to 1. let x = (proportionalLength * lng) / 180 x = (x + 1) / 2 return { x, y } } backward(position) { let { x, y } = position y = 1 - 2 * y let sign = Math.sign(y) y = Math.abs(y) let low = 0 let high = 0 for (let i = 0; i < this.distancesFromEquator.length - 1 && y > this.distancesFromEquator[i]; i++) { low = i high = i + 1 } let lowDist = this.distancesFromEquator[low] let highDist = this.distancesFromEquator[high] let ratio = highDist - lowDist == 0 ? 0 : (y - lowDist) / (highDist - lowDist) let lat = low * 5 + ratio * 5 let parallelLengthMin = this.lengthOfParallel[low] let parallelLengthMax = this.lengthOfParallel[high] let completeLength = parallelLengthMin + (parallelLengthMax - parallelLengthMin) * ratio x = x * 2 - 1 let normalizedLength = x / completeLength let lng = normalizedLength * 180 return { x: lat * sign, y: this._adjustLng(lng, true) } } _adjustLng(lng, inv = false) { let moved = inv ? lng + this.lng0 : lng - this.lng0 // if (moved < -180) moved += 360 // if (moved > 180) moved -= 360 return moved } _interpolate(a, b, ratio) { return a * (1 - ratio) + b * ratio } _getInterpolationValues(value, max) { let sign = Math.sign(value) value = Math.min(Math.abs(value), max) // Note that min and max can be the same. Which is true // when lat is dividable by 5. This also covers the edge cases 0 and 90. let minIndex = Math.floor(value / 5) let maxIndex = Math.ceil(value / 5) let ratio = (value % 5) / 5 // console.log({ value, minIndex, maxIndex, ratio }) // console.log(this.lengthOfParallel.length) return { low: minIndex, high: maxIndex, ratio, sign } } get name() { return 'Robinson Projection' } get maxViewport() { let min = new PIXI.Point(-90, -180) let max = new PIXI.Point(90, 180) max.x += this.lng0 min.x += this.lng0 console.log({ min, max }) return { min, max } } }