149 lines
4.1 KiB
JavaScript
149 lines
4.1 KiB
JavaScript
|
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 }
|
||
|
}
|
||
|
|
||
|
toString() {
|
||
|
return
|
||
|
}
|
||
|
get name() {
|
||
|
return 'Robinson Projection'
|
||
|
}
|
||
|
}
|