8
8
import { computeDestinationPoint , getGreatCircleBearing , getRhumbLineBearing } from 'geolib' ;
9
9
import cheapRuler from 'cheap-ruler' ;
10
10
import { ArrowDirection } from './layers/arrow-layer' ;
11
+ import { Line , LonLat } from '../utils/equipment-types' ;
12
+ import { MapEquipments } from './map-equipments' ;
11
13
12
- const substationPositionByIdIndexer = ( map , substation ) => {
14
+ export type Coordinate = {
15
+ lon : number ;
16
+ lat : number ;
17
+ } ;
18
+
19
+ export type SubstationPosition = {
20
+ id : string ;
21
+ coordinate : Coordinate ;
22
+ } ;
23
+
24
+ export type LinePosition = {
25
+ id : string ;
26
+ coordinates : Coordinate [ ] ;
27
+ } ;
28
+
29
+ const substationPositionByIdIndexer = ( map : Map < string , Coordinate > , substation : SubstationPosition ) => {
13
30
map . set ( substation . id , substation . coordinate ) ;
14
31
return map ;
15
32
} ;
16
33
17
- const linePositionByIdIndexer = ( map , line ) => {
34
+ const linePositionByIdIndexer = ( map : Map < string , Coordinate [ ] > , line : LinePosition ) => {
18
35
map . set ( line . id , line . coordinates ) ;
19
36
return map ;
20
37
} ;
21
38
22
39
export class GeoData {
23
- substationPositionsById = new Map ( ) ;
24
-
25
- linePositionsById = new Map ( ) ;
40
+ substationPositionsById = new Map < string , Coordinate > ( ) ;
41
+ linePositionsById = new Map < string , Coordinate [ ] > ( ) ;
26
42
27
- constructor ( substationPositionsById , linePositionsById ) {
43
+ constructor ( substationPositionsById : Map < string , Coordinate > , linePositionsById : Map < string , Coordinate [ ] > ) {
28
44
this . substationPositionsById = substationPositionsById ;
29
45
this . linePositionsById = linePositionsById ;
30
46
}
31
47
32
- setSubstationPositions ( positions ) {
48
+ setSubstationPositions ( positions : SubstationPosition [ ] ) {
33
49
// index positions by substation id
34
50
this . substationPositionsById = positions . reduce ( substationPositionByIdIndexer , new Map ( ) ) ;
35
51
}
36
52
37
- updateSubstationPositions ( substationIdsToUpdate , fetchedPositions ) {
53
+ updateSubstationPositions ( substationIdsToUpdate : string [ ] , fetchedPositions : SubstationPosition [ ] ) {
38
54
fetchedPositions . forEach ( ( pos ) => this . substationPositionsById . set ( pos . id , pos . coordinate ) ) ;
39
55
// If a substation position is requested but not present in the fetched results, we delete its position.
40
56
// It allows to cancel the position of a substation when the server can't situate it anymore after a network modification (for example a line deletion).
@@ -43,7 +59,7 @@ export class GeoData {
43
59
. forEach ( ( id ) => this . substationPositionsById . delete ( id ) ) ;
44
60
}
45
61
46
- getSubstationPosition ( substationId ) {
62
+ getSubstationPosition ( substationId : string ) : LonLat {
47
63
const position = this . substationPositionsById . get ( substationId ) ;
48
64
if ( ! position ) {
49
65
console . warn ( `Position not found for ${ substationId } ` ) ;
@@ -52,12 +68,12 @@ export class GeoData {
52
68
return [ position . lon , position . lat ] ;
53
69
}
54
70
55
- setLinePositions ( positions ) {
71
+ setLinePositions ( positions : LinePosition [ ] ) {
56
72
// index positions by line id
57
73
this . linePositionsById = positions . reduce ( linePositionByIdIndexer , new Map ( ) ) ;
58
74
}
59
75
60
- updateLinePositions ( lineIdsToUpdate , fetchedPositions ) {
76
+ updateLinePositions ( lineIdsToUpdate : string [ ] , fetchedPositions : LinePosition [ ] ) {
61
77
fetchedPositions . forEach ( ( pos ) => {
62
78
this . linePositionsById . set ( pos . id , pos . coordinates ) ;
63
79
} ) ;
@@ -72,7 +88,7 @@ export class GeoData {
72
88
/**
73
89
* Get line positions always ordered from side 1 to side 2.
74
90
*/
75
- getLinePositions ( network , line , detailed = true ) {
91
+ getLinePositions ( network : MapEquipments , line : Line , detailed = true ) : LonLat [ ] {
76
92
const voltageLevel1 = network . getVoltageLevel ( line . voltageLevelId1 ) ;
77
93
if ( ! voltageLevel1 ) {
78
94
throw new Error ( `Voltage level side 1 '${ line . voltageLevelId1 } ' not found` ) ;
@@ -101,7 +117,7 @@ export class GeoData {
101
117
const linePositions = this . linePositionsById . get ( line . id ) ;
102
118
// Is there any position for this line ?
103
119
if ( linePositions ) {
104
- const positions = new Array ( linePositions . length ) ;
120
+ const positions = new Array < LonLat > ( linePositions . length ) ;
105
121
106
122
for ( const [ index , position ] of linePositions . entries ( ) ) {
107
123
positions [ index ] = [ position . lon , position . lat ] ;
@@ -114,9 +130,9 @@ export class GeoData {
114
130
return [ substationPosition1 , substationPosition2 ] ;
115
131
}
116
132
117
- getLineDistances ( positions ) {
133
+ getLineDistances ( positions : LonLat [ ] ) {
118
134
if ( positions !== null && positions . length > 1 ) {
119
- let cumulativeDistanceArray = [ 0 ] ;
135
+ const cumulativeDistanceArray = [ 0 ] ;
120
136
let cumulativeDistance = 0 ;
121
137
let segmentDistance ;
122
138
let ruler ;
@@ -136,13 +152,13 @@ export class GeoData {
136
152
* along with the remaining distance to travel on this segment to be at the exact wanted distance
137
153
* (implemented using a binary search)
138
154
*/
139
- findSegment ( positions , cumulativeDistances , wantedDistance ) {
155
+ findSegment ( positions : LonLat [ ] , cumulativeDistances : number [ ] , wantedDistance : number ) {
140
156
let lowerBound = 0 ;
141
157
let upperBound = cumulativeDistances . length - 1 ;
142
158
let middlePoint ;
143
159
while ( lowerBound + 1 !== upperBound ) {
144
160
middlePoint = Math . floor ( ( lowerBound + upperBound ) / 2 ) ;
145
- let middlePointDistance = cumulativeDistances [ middlePoint ] ;
161
+ const middlePointDistance = cumulativeDistances [ middlePoint ] ;
146
162
if ( middlePointDistance <= wantedDistance ) {
147
163
lowerBound = middlePoint ;
148
164
} else {
@@ -151,21 +167,21 @@ export class GeoData {
151
167
}
152
168
return {
153
169
idx : lowerBound ,
154
- segment : positions . slice ( lowerBound , lowerBound + 2 ) ,
170
+ segment : positions . slice ( lowerBound , lowerBound + 2 ) as [ LonLat , LonLat ] ,
155
171
remainingDistance : wantedDistance - cumulativeDistances [ lowerBound ] ,
156
172
} ;
157
173
}
158
174
159
175
labelDisplayPosition (
160
- positions ,
161
- cumulativeDistances ,
162
- arrowPosition ,
163
- arrowDirection ,
164
- lineParallelIndex ,
165
- lineAngle ,
166
- proximityAngle ,
167
- distanceBetweenLines ,
168
- proximityFactor
176
+ positions : LonLat [ ] ,
177
+ cumulativeDistances : number [ ] ,
178
+ arrowPosition : number ,
179
+ arrowDirection : ArrowDirection ,
180
+ lineParallelIndex : number ,
181
+ lineAngle : number ,
182
+ proximityAngle : number ,
183
+ distanceBetweenLines : number ,
184
+ proximityFactor : number
169
185
) {
170
186
if ( arrowPosition > 1 || arrowPosition < 0 ) {
171
187
throw new Error ( 'Proportional position value incorrect: ' + arrowPosition ) ;
@@ -177,7 +193,7 @@ export class GeoData {
177
193
) {
178
194
return null ;
179
195
}
180
- let lineDistance = cumulativeDistances [ cumulativeDistances . length - 1 ] ;
196
+ const lineDistance = cumulativeDistances [ cumulativeDistances . length - 1 ] ;
181
197
let wantedDistance = lineDistance * arrowPosition ;
182
198
183
199
if ( cumulativeDistances . length === 2 ) {
@@ -187,7 +203,7 @@ export class GeoData {
187
203
wantedDistance = wantedDistance - 2 * distanceBetweenLines * arrowPosition * proximityFactor ;
188
204
}
189
205
190
- let goodSegment = this . findSegment ( positions , cumulativeDistances , wantedDistance ) ;
206
+ const goodSegment = this . findSegment ( positions , cumulativeDistances , wantedDistance ) ;
191
207
192
208
// We don't have the exact same distance calculation as in the arrow shader, so take some margin:
193
209
// we move the label a little bit on the flat side of the arrow so that at least it stays
@@ -206,9 +222,9 @@ export class GeoData {
206
222
default :
207
223
throw new Error ( 'impossible' ) ;
208
224
}
209
- let remainingDistance = goodSegment . remainingDistance * multiplier ;
225
+ const remainingDistance = goodSegment . remainingDistance * multiplier ;
210
226
211
- let angle = this . getMapAngle ( goodSegment . segment [ 0 ] , goodSegment . segment [ 1 ] ) ;
227
+ const angle = this . getMapAngle ( goodSegment . segment [ 0 ] , goodSegment . segment [ 1 ] ) ;
212
228
const neededOffset = this . getLabelOffset ( angle , 20 , arrowDirection ) ;
213
229
214
230
const position = {
@@ -252,8 +268,8 @@ export class GeoData {
252
268
return position ;
253
269
}
254
270
255
- getLabelOffset ( angle , offsetDistance , arrowDirection ) {
256
- let radiantAngle = ( - angle + 90 ) / ( 180 / Math . PI ) ;
271
+ getLabelOffset ( angle : number , offsetDistance : number , arrowDirection : ArrowDirection ) : [ number , number ] {
272
+ const radiantAngle = ( - angle + 90 ) / ( 180 / Math . PI ) ;
257
273
let direction = 0 ;
258
274
switch ( arrowDirection ) {
259
275
case ArrowDirection . FROM_SIDE_2_TO_SIDE_1 :
@@ -276,11 +292,11 @@ export class GeoData {
276
292
}
277
293
278
294
//returns the angle between point1 and point2 in degrees [0-360)
279
- getMapAngle ( point1 , point2 ) {
295
+ getMapAngle ( point1 : LonLat , point2 : LonLat ) {
280
296
// We don't have the exact same angle calculation as in the arrow shader, and this
281
297
// seems to give more approaching results
282
298
let angle = getRhumbLineBearing ( point1 , point2 ) ;
283
- let angle2 = getGreatCircleBearing ( point1 , point2 ) ;
299
+ const angle2 = getGreatCircleBearing ( point1 , point2 ) ;
284
300
const coeff = 0.1 ;
285
301
angle = coeff * angle + ( 1 - coeff ) * angle2 ;
286
302
return angle ;
0 commit comments