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 | import theConfig from '../../data/Config.js'; |
26 | |
27 | import { ZERO, ONE, TWO, THREE } from '../../main/Constants.js'; |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | class ProfileSmoothingIron { |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | #route; |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | #smoothDistance; |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | #smoothPoints; |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | get #smoothPointsNumber ( ) { return theConfig.route.elev.smoothPoints; } |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | #createSmoothPoints ( ) { |
70 | this.#smoothPoints = []; |
71 | |
72 | |
73 | this.#smoothPoints.push ( |
74 | { |
75 | distance : ZERO, |
76 | elev : this.#route.itinerary.itineraryPoints.first.elev, |
77 | smoothElev : this.#route.itinerary.itineraryPoints.first.elev |
78 | } |
79 | ); |
80 | const itineraryPointsIterator = this.#route.itinerary.itineraryPoints.iterator; |
81 | itineraryPointsIterator.done; |
82 | let previousItineraryPointDistance = ZERO; |
83 | let itineraryPointdistance = itineraryPointsIterator.value.distance; |
84 | let previousItineraryPointElev = itineraryPointsIterator.value.elev; |
85 | itineraryPointsIterator.done; |
86 | |
87 | let smoothPointDistance = this.#smoothDistance; |
88 | |
89 | |
90 | while ( smoothPointDistance < this.#route.distance ) { |
91 | |
92 | if ( itineraryPointdistance < smoothPointDistance ) { |
93 | previousItineraryPointDistance = itineraryPointdistance; |
94 | previousItineraryPointElev = itineraryPointsIterator.value.elev; |
95 | while ( itineraryPointdistance < smoothPointDistance ) { |
96 | itineraryPointdistance += itineraryPointsIterator.value.distance; |
97 | itineraryPointsIterator.done; |
98 | } |
99 | } |
100 | |
101 | let ascentFactor = |
102 | ( itineraryPointsIterator.value.elev - previousItineraryPointElev ) |
103 | / |
104 | ( itineraryPointdistance - previousItineraryPointDistance ); |
105 | const smoothPointElev = |
106 | previousItineraryPointElev |
107 | + |
108 | ( ( smoothPointDistance - previousItineraryPointDistance ) * ascentFactor ); |
109 | this.#smoothPoints.push ( |
110 | { |
111 | distance : smoothPointDistance, |
112 | elev : smoothPointElev, |
113 | smoothElev : ZERO |
114 | } |
115 | ); |
116 | smoothPointDistance += this.#smoothDistance; |
117 | } |
118 | |
119 | |
120 | this.#smoothPoints.push ( |
121 | { |
122 | distance : this.#route.distance, |
123 | elev : this.#route.itinerary.itineraryPoints.last.elev, |
124 | smoothElev : this.#route.itinerary.itineraryPoints.last.elev |
125 | } |
126 | ); |
127 | } |
128 | |
129 | |
130 | |
131 | |
132 | |
133 | #computeSmoothElev ( ) { |
134 | let deltaElev = |
135 | ( this.#smoothPoints [ this.#smoothPointsNumber - ONE ].elev - this.#smoothPoints [ ZERO ].elev ) |
136 | / |
137 | ( this.#smoothPointsNumber - ONE ); |
138 | |
139 | let pointCounter = ZERO; |
140 | for ( pointCounter = ZERO; pointCounter < this.#smoothPointsNumber; pointCounter ++ ) { |
141 | this.#smoothPoints [ pointCounter ].smoothElev = |
142 | this.#smoothPoints [ ZERO ].elev + ( deltaElev * pointCounter ); |
143 | } |
144 | |
145 | for ( |
146 | pointCounter = this.#smoothPointsNumber; |
147 | pointCounter < this.#smoothPoints.length - this.#smoothPointsNumber; |
148 | pointCounter ++ |
149 | ) { |
150 | let elevSum = ZERO; |
151 | for ( |
152 | let pointNumber = pointCounter - this.#smoothPointsNumber; |
153 | pointNumber <= pointCounter + this.#smoothPointsNumber; |
154 | pointNumber ++ |
155 | ) { |
156 | elevSum += this.#smoothPoints [ pointNumber ].elev; |
157 | } |
158 | this.#smoothPoints [ pointCounter ].smoothElev = elevSum / ( ( this.#smoothPointsNumber * TWO ) + ONE ); |
159 | } |
160 | |
161 | pointCounter --; |
162 | |
163 | const deltaSmoothElev = |
164 | ( |
165 | this.#smoothPoints [ pointCounter + this.#smoothPointsNumber ].smoothElev |
166 | - |
167 | this.#smoothPoints [ pointCounter ].smoothElev |
168 | ) |
169 | / |
170 | this.#smoothPointsNumber; |
171 | |
172 | let tmpSmoothElev = this.#smoothPoints [ pointCounter ].smoothElev; |
173 | let tmpPointCounter = ONE; |
174 | |
175 | pointCounter ++; |
176 | |
177 | for ( ; pointCounter < this.#smoothPoints.length - ONE; tmpPointCounter ++, pointCounter ++ ) { |
178 | this.#smoothPoints [ pointCounter ].smoothElev = |
179 | tmpSmoothElev + ( deltaSmoothElev * tmpPointCounter ); |
180 | } |
181 | } |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | #computeSmoothDistance ( ) { |
190 | |
191 | |
192 | const itineraryPointsIterator = this.#route.itinerary.itineraryPoints.iterator; |
193 | let elev = ZERO; |
194 | while ( ! itineraryPointsIterator.done ) { |
195 | elev += |
196 | itineraryPointsIterator.next |
197 | ? |
198 | Math.abs ( itineraryPointsIterator.value.elev - itineraryPointsIterator.next.elev ) |
199 | : |
200 | ZERO; |
201 | |
202 | } |
203 | |
204 | |
205 | this.#smoothDistance = |
206 | Math.floor ( |
207 | Math.min ( |
208 | theConfig.route.elev.smoothCoefficient * this.#route.distance / elev, |
209 | this.#route.distance / ( THREE * this.#smoothPointsNumber ) |
210 | ) |
211 | ); |
212 | } |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | #setSmoothElev ( ) { |
219 | |
220 | const itineraryPointsIterator = this.#route.itinerary.itineraryPoints.iterator; |
221 | |
222 | |
223 | itineraryPointsIterator.done; |
224 | let itineraryPointsTotalDistance = itineraryPointsIterator.value.distance; |
225 | |
226 | |
227 | while ( ! itineraryPointsIterator.done ) { |
228 | const previousIronPoint = |
229 | this.#smoothPoints [ Math.floor ( itineraryPointsTotalDistance / this.#smoothDistance ) ]; |
230 | const nextIronPoint = |
231 | this.#smoothPoints [ Math.ceil ( itineraryPointsTotalDistance / this.#smoothDistance ) ]; |
232 | |
233 | |
234 | if ( previousIronPoint && nextIronPoint ) { |
235 | const deltaDist = itineraryPointsTotalDistance - previousIronPoint.distance; |
236 | const ascentFactor = ( nextIronPoint.elev - previousIronPoint.elev ) / |
237 | ( nextIronPoint.distance - previousIronPoint.distance ); |
238 | itineraryPointsIterator.value.elev = previousIronPoint.elev + ( deltaDist * ascentFactor ); |
239 | } |
240 | itineraryPointsTotalDistance += itineraryPointsIterator.value.distance; |
241 | } |
242 | } |
243 | |
244 | |
245 | |
246 | |
247 | |
248 | constructor ( ) { |
249 | Object.freeze ( this ); |
250 | } |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | smooth ( route ) { |
258 | this.#route = route; |
259 | this.#computeSmoothDistance ( ); |
260 | this.#createSmoothPoints ( ); |
261 | this.#computeSmoothElev ( ); |
262 | this.#setSmoothElev ( ); |
263 | } |
264 | } |
265 | |
266 | export default ProfileSmoothingIron; |
267 | |
268 | |
269 | |