Blame view

天文台pc/tianwentai-ui/node_modules/react-dnd-html5-backend/src/MonotonicInterpolant.ts 2.3 KB
bc518174   王天杨   提交两个项目文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  export class MonotonicInterpolant {
  	private xs: any
  	private ys: any
  	private c1s: any
  	private c2s: any
  	private c3s: any
  
  	public constructor(xs: number[], ys: number[]) {
  		const { length } = xs
  
  		// Rearrange xs and ys so that xs is sorted
  		const indexes = []
  		for (let i = 0; i < length; i++) {
  			indexes.push(i)
  		}
  		indexes.sort((a, b) => ((xs[a] as number) < (xs[b] as number) ? -1 : 1))
  
  		// Get consecutive differences and slopes
  		const dys = []
  		const dxs = []
  		const ms = []
  		let dx
  		let dy
  		for (let i = 0; i < length - 1; i++) {
  			dx = (xs[i + 1] as number) - (xs[i] as number)
  			dy = (ys[i + 1] as number) - (ys[i] as number)
  			dxs.push(dx)
  			dys.push(dy)
  			ms.push(dy / dx)
  		}
  
  		// Get degree-1 coefficients
  		const c1s = [ms[0]]
  		for (let i = 0; i < dxs.length - 1; i++) {
  			const m2 = ms[i] as number
  			const mNext = ms[i + 1] as number
  			if (m2 * mNext <= 0) {
  				c1s.push(0)
  			} else {
  				dx = dxs[i] as number
  				const dxNext = dxs[i + 1] as number
  				const common = dx + dxNext
  				c1s.push(
  					(3 * common) / ((common + dxNext) / m2 + (common + dx) / mNext),
  				)
  			}
  		}
  		c1s.push(ms[ms.length - 1])
  
  		// Get degree-2 and degree-3 coefficients
  		const c2s = []
  		const c3s = []
  		let m
  		for (let i = 0; i < c1s.length - 1; i++) {
  			m = ms[i] as number
  			const c1 = c1s[i] as number
  			const invDx = 1 / (dxs[i] as number)
  			const common = c1 + (c1s[i + 1] as number) - m - m
  			c2s.push((m - c1 - common) * invDx)
  			c3s.push(common * invDx * invDx)
  		}
  
  		this.xs = xs
  		this.ys = ys
  		this.c1s = c1s
  		this.c2s = c2s
  		this.c3s = c3s
  	}
  
  	public interpolate(x: number): number {
  		const { xs, ys, c1s, c2s, c3s } = this
  
  		// The rightmost point in the dataset should give an exact result
  		let i = xs.length - 1
  		if (x === xs[i]) {
  			return ys[i]
  		}
  
  		// Search for the interval x is in, returning the corresponding y if x is one of the original xs
  		let low = 0
  		let high = c3s.length - 1
  		let mid
  		while (low <= high) {
  			mid = Math.floor(0.5 * (low + high))
  			const xHere = xs[mid]
  			if (xHere < x) {
  				low = mid + 1
  			} else if (xHere > x) {
  				high = mid - 1
  			} else {
  				return ys[mid]
  			}
  		}
  		i = Math.max(0, high)
  
  		// Interpolate
  		const diff = x - xs[i]
  		const diffSq = diff * diff
  		return ys[i] + c1s[i] * diff + c2s[i] * diffSq + c3s[i] * diff * diffSq
  	}
  }