|
@@ -2,11 +2,31 @@ import {PNG} from 'pngjs'; |
|
|
import {Projection} from '../../utils/types'; |
|
|
import {Projection} from '../../utils/types'; |
|
|
import * as d3geo from 'd3-geo'; |
|
|
import * as d3geo from 'd3-geo'; |
|
|
|
|
|
|
|
|
|
|
|
type ProjectionData = { |
|
|
|
|
|
fn: Function, |
|
|
|
|
|
bounds: (a: [number, number]) => [number, number], |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
export default interface ProjectionService {} |
|
|
export default interface ProjectionService {} |
|
|
export class ProjectionServiceImpl implements ProjectionService { |
|
|
export class ProjectionServiceImpl implements ProjectionService { |
|
|
private readonly projections: Record<Projection, Function> = { |
|
|
|
|
|
[Projection.EQUIRECTANGULAR]: d3geo.geoEquirectangular, |
|
|
|
|
|
[Projection.MERCATOR]: d3geo.geoMercator, |
|
|
|
|
|
|
|
|
private readonly projections: Record<Projection, ProjectionData> = { |
|
|
|
|
|
[Projection.EQUIRECTANGULAR]: { |
|
|
|
|
|
fn: d3geo.geoEquirectangular, |
|
|
|
|
|
bounds: (a) => a, |
|
|
|
|
|
}, |
|
|
|
|
|
[Projection.MERCATOR]: { |
|
|
|
|
|
fn: d3geo.geoMercator, |
|
|
|
|
|
bounds: ([width, height]) => [width, height * 2], |
|
|
|
|
|
}, |
|
|
|
|
|
[Projection.AZIMUTHAL_EQUIDISTANT]: { |
|
|
|
|
|
fn: d3geo.geoAzimuthalEquidistant, |
|
|
|
|
|
bounds: (a) => a, |
|
|
|
|
|
}, |
|
|
|
|
|
[Projection.CONIC_CONFORMAL]: { |
|
|
|
|
|
fn: d3geo.geoConicConformal, |
|
|
|
|
|
bounds: (a) => a, |
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
} as const |
|
|
} as const |
|
|
|
|
|
|
|
|
private readonly referenceWidth = 960 as const; |
|
|
private readonly referenceWidth = 960 as const; |
|
@@ -16,17 +36,14 @@ export class ProjectionServiceImpl implements ProjectionService { |
|
|
return equiImage; |
|
|
return equiImage; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const projectionFunction = this.projections[projection](); |
|
|
|
|
|
if (!projectionFunction.invert) { |
|
|
|
|
|
|
|
|
const { [projection]: currentProjectionData } = this.projections |
|
|
|
|
|
const { invert } = currentProjectionData.fn(); |
|
|
|
|
|
if (!invert) { |
|
|
return undefined; |
|
|
return undefined; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const sx = equiImage.width; |
|
|
|
|
|
const sy = equiImage.height; |
|
|
|
|
|
const sourceData = equiImage.data; |
|
|
|
|
|
const tx = sx; |
|
|
|
|
|
// const py = projection === Projection.MERCATOR ? dy * 2 : dy; |
|
|
|
|
|
const ty = sy; |
|
|
|
|
|
|
|
|
const { width: sx, height: sy, data: sourceData } = equiImage; |
|
|
|
|
|
const [tx, ty] = currentProjectionData.bounds([sx, sy]); |
|
|
const target = new PNG({ |
|
|
const target = new PNG({ |
|
|
width: tx, |
|
|
width: tx, |
|
|
height: ty, |
|
|
height: ty, |
|
@@ -34,9 +51,9 @@ export class ProjectionServiceImpl implements ProjectionService { |
|
|
const targetData = target.data; |
|
|
const targetData = target.data; |
|
|
|
|
|
|
|
|
let i = 0; |
|
|
let i = 0; |
|
|
for (let y = 0; y < sy; y += 1) { |
|
|
|
|
|
|
|
|
for (let y = (sy - ty) / 2; y < (ty + ((sy - ty) / 2)); y += 1) { |
|
|
for (let x = 0; x < sx; x += 1) { |
|
|
for (let x = 0; x < sx; x += 1) { |
|
|
const projected = projectionFunction.invert([x / sx * this.referenceWidth, y / sx * this.referenceWidth]) as [number, number]; |
|
|
|
|
|
|
|
|
const projected = invert([x / sx * this.referenceWidth, y / sx * this.referenceWidth]) as [number, number]; |
|
|
if (projected) { |
|
|
if (projected) { |
|
|
const [lambda, phi] = projected; |
|
|
const [lambda, phi] = projected; |
|
|
if (!(lambda > 180 || lambda < -180 || phi > 90 || phi < -90)) { |
|
|
if (!(lambda > 180 || lambda < -180 || phi > 90 || phi < -90)) { |
|
|