点数组的插值

3

我有以下数据点,代表一个星座的边界。

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之间进行插值。

我编写了以下函数来执行此操作(值得注意的是,它是在赤道坐标系中完成的 - 而不是笛卡尔坐标系 - 因此数学上略微复杂,但并不是非常复杂)。

插值两个点的函数如下(用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
}

我已经通过测试套件运行了它,位于上述“边界”的前两个点之间,以在数学上获得其有效性:
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
  ...
]

如果我理解正确的话,您的边界数组有多个赤经/赤纬对,但是您的插值函数期望起始和结束坐标,每个坐标都代表一个ra/dec对。在调用插值函数时,您如何决定起始和结束对应的坐标呢?它只是边界列表中相邻的一对吗?所以是[0,1],然后是[1,2],然后是[2,3],一直到[N-1,0]? - jarmod
@jarmod 没错 - 不幸的是,国际天文学联合会只提供边界点作为“连续”的点线。我理解你为什么会问这个问题,因为它可能是一个随机排序的点列表。 - Micheal J. Roberts
每次调用插值函数都会返回一个包含P个点的数组(其中P为精度,在此示例中为10)。如果边界数组中有K个点,则您期望的最终输出是什么?它是一个K*P个点的一维数组吗? - jarmod
是的,一个由K(1+P)个点组成的一维数组(原始点保持不变且按顺序排列 - 在它们之间进行插值)。我还会在以上问题中添加所需的输出。 - Micheal J. Roberts
@Jarmod 我已经添加了所需的输出。如果这有帮助,请告诉我。 - Micheal J. Roberts
显示剩余2条评论
2个回答

2

我认为Array.reduce()是在这里使用最好的工具。

您可以编写一个函数,该函数接受边界数组和精度,并输出所需的EquatorialCoordinate数组:

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,您需要将其切片掉。


嗯,看起来这似乎返回了一个空数组和很多 TypeScript 的问题。我会将此问题标记为 TypeScript。非常感谢您的回答。 - Micheal J. Roberts
getInterpolatedEquatorialCoordinates() 返回一个数组,所以我们不能使用 push ...。 - Micheal J. Roberts
你可以将一个数组推入另一个数组中,而这个累加器是[] - Charlie Bamford
当然可以 - 从技术上讲,但这样我们只会得到一个数组内的另一个数组 - 这不是期望的输出。 - Micheal J. Roberts
所以只需使用 a.push(...getInterpolatedEquatorialCoordinates(arr[i-1], p, precision)) 将其展平即可。 - Charlie Bamford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接