ウェブサイト検索

javascript - 点の配列の補間


私は星座の境界を表す次のデータポイントを持っています。

let boundaries = [
    {
      ra: 344.46530375,
      dec: 35.1682358
    },
    {
      ra: 344.34285125,
      dec: 53.1680298
    },
    {
      ra: 351.45289375,
      dec: 53.1870041
    },
    ...
]

無関係ですが、これらはIAUの引用値から抽出されたものです。

しかし、これらの各点の間には、いわゆる「大円距離」または点iと点i+1の間の正距線距離が必要です。そのためには、指定された精度xで点iと点i+1の間を補間することができます。

私は次の関数を書きました。この関数はこの操作を実行できます(赤道座標系で行われることに注意する価値があります - デカルト座標系ではありません - そのため数学的には少し複雑ですが、大幅に複雑ではありません)。

2つの点の間を補間する関数は次の通りです(繁栄と安全のためにTypeScript ES6で記述されています):

/**
 * getInterpolatedEquatorialCoordinates()
 *
 * @description This function takes in a start and end
 * @param start EquatorialCoordinate
 * @param end EquatorialCoordinate
 * @param precision number
 * @output returns the interpolated array of []EquatorialCoordinate points:
 */
export const getInterpolatedEquatorialCoordinates = (
  start: EquatorialCoordinate,
  end: EquatorialCoordinate,
  precision: number
): Array<EquatorialCoordinate> => {
  // The interpolated points array to return:
  const points: Array<EquatorialCoordinate> = []

  // Obtain the difference between the end coordinate's Right Ascension, RA, and the start coordinate's RA:
  let nra = ((end.ra - start.ra)) % 360

  if (nra > 180) nra = nra - 360
  if (nra < -180) nra = nra + 360

  // Obtain the "gradient" rate of change of RA:
  const dra: number = nra / precision

  // Obtain the difference between the end coordinate's Declination, dec, and the start coordinate's dec:
  const ndec = ((end.dec - start.dec))

  // Obtain the "gradient" rate of change of dec:
  const ddec: number = ndec / precision

  let i = 0

  // Obtain the interpolated EquatorialCoordinate points for each step:
  while (i < precision) {
    i++
    points.push({
      ra: start.ra + (dra * i),
      dec: start.dec + (ddec * i)
    })
  }

  return points
}

私はこれを上記のboundariesの最初の二つの点の間でテストスイートにかけて、その数学的な妥当性を得ました:

test('getInterpolatedEquatorialCoordinates', function () {
  const start = {
    ra: 344.46530375,
    dec: 35.1682358
  }

  const end = {
    ra: 344.34285125,
    dec: 53.1680298
  }

  const minRA = Math.min(start.ra, end.ra)
  const minDec = Math.min(start.dec, end.dec)

  const maxRA = Math.max(start.ra, end.ra)
  const maxDec = Math.max(start.ra, end.ra)

  const precision = 10

  const points = getInterpolatedEquatorialCoordinates(start, end, precision)

  const isRAAboveLowerThreshold = (
    p: EquatorialCoordinate
  ) => p.ra >= minRA

  const isRABelowUpperThreshold = (
    p: EquatorialCoordinate
  ) => p.ra <= maxRA

  const isDecAboveLowerThreshold = (
    p: EquatorialCoordinate
  ) => p.dec >= minDec

  const isDecBelowUpperThreshold = (
    p: EquatorialCoordinate
  ) => p.dec <= maxDec

  expect(points.length).toBeGreaterThan(0)
  expect(points.length).toBe(precision)
  expect(points.every(isRAAboveLowerThreshold)).toBe(true)
  expect(points.every(isRABelowUpperThreshold)).toBe(true)
  expect(points.every(isDecAboveLowerThreshold)).toBe(true)
  expect(points.every(isDecBelowUpperThreshold)).toBe(true)
})

補間された出力点は次の通りです:

[
      { ra: 344.4530585, dec: 36.968215199999996 },
      { ra: 344.44081324999996, dec: 38.7681946 },
      { ra: 344.428568, dec: 40.568174 },
      { ra: 344.41632275, dec: 42.3681534 },
      { ra: 344.40407749999997, dec: 44.168132799999995 },
      { ra: 344.39183225, dec: 45.9681122 },
      { ra: 344.379587, dec: 47.7680916 },
      { ra: 344.36734175000004, dec: 49.568071 },
      { ra: 344.3550965, dec: 51.3680504 },
      { ra: 344.34285125, dec: 53.1680298 }
]

これは、私が満足する程度の精度であれば、どの精度でもうまく機能するようです。また、どの「方向」に進んでいるかに関係なく動作します。


質問:

今私がやりたいのは、上記の boundaries 配列のすべての点にこれを適用し、すべての点を一つにまとめた新しい配列を返すことです…

これを達成する最良の方法は何でしょうか?私はArray.prototype.mapメソッドを使おうとしましたが、まったく成功しませんでした…

次の「boundaries」について、期待される出力は以下の通りです。

let boundaries = [
    {
      ra: 344.46530375,
      dec: 35.1682358
    },
    {
      ra: 344.34285125,
      dec: 53.1680298
    },
    ...
]

let desiredOutput = [
  {
    ra: 344.46530375,
    dec: 35.1682358
  }, // Original Index 0
  // Start Interpolated Intermediary Values
  { 
    ra: 344.4530585, 
    dec: 36.968215199999996 
  },
  { 
    ra: 344.44081324999996,    
    dec: 38.7681946 
  },
  { 
    ra: 344.428568, 
    dec: 40.568174 
  },
  { 
    ra: 344.41632275, 
    dec: 42.3681534 
  },
  { 
    ra: 344.40407749999997, 
    dec: 44.168132799999995 
  },
  { 
    ra: 344.39183225, 
    dec: 45.9681122 
  },
  { 
    ra: 344.379587, 
    dec: 47.7680916 
  },
  { 
    ra: 344.36734175000004, 
    dec: 49.568071 
  },
  { 
    ra: 344.3550965, 
    dec: 51.3680504 
  },
  { 
    ra: 344.34285125, 
    dec: 53.1680298 
  },
  // End Interpolated Intermediary Values
  {
    ra: 344.34285125,
    dec: 53.1680298
  }, // Original Index 1
  ...
]

回答 #1

私はここで使用するのにArray.reduce()が最適なツールだと思います。

境界の配列と精度を受け取り、希望する赤道座標の配列を出力する関数を書くことができます。

const fillInBoundryPoints = (boundaries: EquatorialCoordinate[], precision: number) => {
  return boundaries.reduce((acc, cur, i, arr) => {
    if (i < arr.length - 1) {
      acc.push(cur)
      acc.push(...getInterpolatedEquatorialCoordinates(cur, arr[i + 1], precision))
    }
    return acc
  }, [] as EquatorialCoordinate[])
}

あなたが次のように使用するもの:

const precision = 10

const boundaries: EquatorialCoordinate[] = [
  {
    ra: 344.46530375,
    dec: 35.1682358
  },
  {
    ra: 344.34285125,
    dec: 53.1680298
  }
]

const desiredOutput = fillInBoundryPoints(boundaries, precision)

出力 :

[
  { ra: 344.46530375, dec: 35.1682358 },
  { ra: 344.4530585, dec: 36.968215199999996 },
  { ra: 344.44081324999996, dec: 38.7681946 },
  { ra: 344.428568, dec: 40.568174 },
  { ra: 344.41632275, dec: 42.3681534 },
  { ra: 344.40407749999997, dec: 44.168132799999995 },
  { ra: 344.39183225, dec: 45.9681122 },
  { ra: 344.379587, dec: 47.7680916 },
  { ra: 344.36734175000004, dec: 49.568071 },
  { ra: 344.3550965, dec: 51.3680504 },
  { ra: 344.34285125, dec: 53.1680298 }
]

回答 #2

あなたはmapを使うこともできますが、このシナリオにはreduceの方が自然に適しています

boundaries.reduce((a,p,i,arr) => {
  if ( i > 0 ) {
    a.push(getInterpolatedEquatorialCoordinates(arr[i-1], p, precision))
  }
  return a;
}, [])

注意: 前の値を参照する代わりに map ケースを使用する場合は、先読みする必要がありますが、最後に undefined が生成されるため、それを切り取る必要があります

関連記事