Generate Super Mario War worlds from real-world data.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 

58 řádky
1.7 KiB

  1. import {PNG} from 'pngjs';
  2. import {Projection} from '../../utils/types';
  3. import * as d3geo from 'd3-geo';
  4. export default interface ProjectionService {}
  5. export class ProjectionServiceImpl implements ProjectionService {
  6. private readonly projections: Record<Projection, Function> = {
  7. [Projection.EQUIRECTANGULAR]: d3geo.geoEquirectangular,
  8. [Projection.MERCATOR]: d3geo.geoMercator,
  9. } as const
  10. private readonly referenceWidth = 960 as const;
  11. project(equiImage: PNG, projection: Projection) {
  12. if (projection === Projection.EQUIRECTANGULAR) {
  13. return equiImage;
  14. }
  15. const projectionFunction = this.projections[projection]();
  16. if (!projectionFunction.invert) {
  17. return undefined;
  18. }
  19. const sx = equiImage.width;
  20. const sy = equiImage.height;
  21. const sourceData = equiImage.data;
  22. const tx = sx;
  23. // const py = projection === Projection.MERCATOR ? dy * 2 : dy;
  24. const ty = sy;
  25. const target = new PNG({
  26. width: tx,
  27. height: ty,
  28. });
  29. const targetData = target.data;
  30. let i = 0;
  31. for (let y = 0; y < sy; y += 1) {
  32. for (let x = 0; x < sx; x += 1) {
  33. const projected = projectionFunction.invert([x / sx * this.referenceWidth, y / sx * this.referenceWidth]) as [number, number];
  34. if (projected) {
  35. const [lambda, phi] = projected;
  36. if (!(lambda > 180 || lambda < -180 || phi > 90 || phi < -90)) {
  37. const q = ((90 - phi) / 180 * sy | 0) * sx + ((180 + lambda) / 360 * sx | 0) << 2;
  38. targetData[i] = sourceData[q];
  39. targetData[i + 1] = sourceData[q + 1];
  40. targetData[i + 2] = sourceData[q + 2];
  41. targetData[i + 3] = 255;
  42. }
  43. }
  44. i += 4;
  45. }
  46. }
  47. return target;
  48. }
  49. }