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 theTravelNotesData from '../../data/TravelNotesData.js'; |
26 | import { DISTANCE, ZERO, ONE, TWO, DEGREES, LAT_LNG, LAT, LNG, EARTH_RADIUS } from '../../main/Constants.js'; |
27 | import LatLngDistance from '../../containers/LatLngDistance.js'; |
28 | import LatLngElevOnRoute from '../../containers/LatLngElevOnRoute.js'; |
29 | |
30 | import { |
31 | LeafletLatLng, |
32 | LeafletLatLngBounds, |
33 | LeafletPoint, |
34 | LeafletLineUtil, |
35 | LeafletProjection |
36 | } from '../../leaflet/LeafletImports.js'; |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | class Geometry { |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | static get #HUNDRED ( ) { return 100; } |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | constructor ( ) { |
61 | Object.freeze ( this ); |
62 | } |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | getLatLngElevAtDist ( route, distance ) { |
73 | if ( route.distance <= distance || ZERO >= distance ) { |
74 | return null; |
75 | } |
76 | let nearestDistance = 0; |
77 | const itineraryPointsIterator = route.itinerary.itineraryPoints.iterator; |
78 | while ( nearestDistance < distance && ! itineraryPointsIterator.done ) { |
79 | nearestDistance += itineraryPointsIterator.value.distance; |
80 | } |
81 | const previousItineraryPoint = itineraryPointsIterator.value; |
82 | itineraryPointsIterator.done; |
83 | const scale = ( previousItineraryPoint.distance - nearestDistance + distance ) / previousItineraryPoint.distance; |
84 | |
85 | return new LatLngElevOnRoute ( |
86 | previousItineraryPoint.lat + ( ( itineraryPointsIterator.value.lat - previousItineraryPoint.lat ) * scale ), |
87 | previousItineraryPoint.lng + ( ( itineraryPointsIterator.value.lng - previousItineraryPoint.lng ) * scale ), |
88 | distance, |
89 | previousItineraryPoint.elev + ( ( itineraryPointsIterator.value.elev - previousItineraryPoint.elev ) * scale ), |
90 | Geometry.#HUNDRED * |
91 | ( itineraryPointsIterator.value.elev - previousItineraryPoint.elev ) / previousItineraryPoint.distance |
92 | ); |
93 | } |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | getClosestLatLngDistance ( route, latLng ) { |
104 | if ( ZERO === route.itinerary.itineraryPoints.length ) { |
105 | return null; |
106 | } |
107 | const itineraryPointIterator = route.itinerary.itineraryPoints.iterator; |
108 | itineraryPointIterator.done; |
109 | let minDistance = Number.MAX_VALUE; |
110 | |
111 | |
112 | const point = LeafletProjection.SphericalMercator.project ( |
113 | new LeafletLatLng ( latLng [ ZERO ], latLng [ ONE ] ) ); |
114 | let point1 = LeafletProjection.SphericalMercator.project ( |
115 | new LeafletLatLng ( itineraryPointIterator.value.lat, itineraryPointIterator.value.lng ) |
116 | ); |
117 | let closestLatLng = null; |
118 | let closestDistance = DISTANCE.defaultValue; |
119 | let endSegmentDistance = itineraryPointIterator.value.distance; |
120 | while ( ! itineraryPointIterator.done ) { |
121 | const point2 = LeafletProjection.SphericalMercator.project ( |
122 | new LeafletLatLng ( itineraryPointIterator.value.lat, itineraryPointIterator.value.lng ) |
123 | ); |
124 | let distance = LeafletLineUtil.pointToSegmentDistance ( point, point1, point2 ); |
125 | if ( distance < minDistance ) { |
126 | minDistance = distance; |
127 | closestLatLng = LeafletProjection.SphericalMercator.unproject ( |
128 | LeafletLineUtil.closestPointOnSegment ( point, point1, point2 ) |
129 | ); |
130 | closestDistance = |
131 | endSegmentDistance - |
132 | closestLatLng.distanceTo ( |
133 | new LeafletLatLng ( itineraryPointIterator.value.lat, itineraryPointIterator.value.lng ) |
134 | ); |
135 | } |
136 | endSegmentDistance += itineraryPointIterator.value.distance; |
137 | point1 = point2; |
138 | } |
139 | return new LatLngDistance ( closestLatLng.lat, closestLatLng.lng, closestDistance ); |
140 | } |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | getLatLngBounds ( latLngs ) { |
149 | const sw = new LeafletLatLng ( LAT_LNG.maxLat, LAT_LNG.maxLng ); |
150 | const ne = new LeafletLatLng ( LAT_LNG.minLat, LAT_LNG.minLng ); |
151 | latLngs.forEach ( |
152 | latLng => { |
153 | sw.lat = Math.min ( sw.lat, latLng [ ZERO ] ); |
154 | sw.lng = Math.min ( sw.lng, latLng [ ONE ] ); |
155 | ne.lat = Math.max ( ne.lat, latLng [ ZERO ] ); |
156 | ne.lng = Math.max ( ne.lng, latLng [ ONE ] ); |
157 | } |
158 | ); |
159 | return new LeafletLatLngBounds ( sw, ne ); |
160 | } |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | getSquareBoundingBox ( latLngCenter, dimension ) { |
169 | const latCenterRad = latLngCenter [ ZERO ] * DEGREES.toRadians; |
170 | const deltaLat = ( dimension / EARTH_RADIUS ) * DEGREES.fromRadians; |
171 | const deltaLng = |
172 | Math.acos ( |
173 | ( Math.cos ( dimension / EARTH_RADIUS ) - ( Math.sin ( latCenterRad ) ** TWO ) ) / |
174 | ( Math.cos ( latCenterRad ) ** TWO ) |
175 | ) * DEGREES.fromRadians; |
176 | return new LeafletLatLngBounds ( |
177 | new LeafletLatLng ( latLngCenter [ ZERO ] - deltaLat, latLngCenter [ ONE ] - deltaLng ), |
178 | new LeafletLatLng ( latLngCenter [ ZERO ] + deltaLat, latLngCenter [ ONE ] + deltaLng ) |
179 | ); |
180 | } |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | |
190 | project ( latLng, zoom ) { |
191 | const projection = theTravelNotesData.map.project ( new LeafletLatLng ( latLng [ LAT ], latLng [ LNG ] ), zoom ); |
192 | return [ projection.x, projection.y ]; |
193 | } |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | screenCoordToLatLng ( xScreen, yScreen ) { |
203 | const latLng = theTravelNotesData.map.containerPointToLatLng ( new LeafletPoint ( xScreen, yScreen ) ); |
204 | return [ latLng.lat, latLng.lng ]; |
205 | } |
206 | |
207 | |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | |
214 | addPoints ( point1, point2 ) { |
215 | return [ |
216 | point1 [ ZERO ] + point2 [ ZERO ], |
217 | point1 [ ONE ] + point2 [ ONE ] |
218 | ]; |
219 | } |
220 | |
221 | |
222 | |
223 | |
224 | |
225 | |
226 | |
227 | |
228 | subtrackPoints ( point1, point2 ) { |
229 | return [ |
230 | point1 [ ZERO ] - point2 [ ZERO ], |
231 | point1 [ ONE ] - point2 [ ONE ] |
232 | ]; |
233 | } |
234 | } |
235 | |
236 | |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | |
243 | const theGeometry = new Geometry ( ); |
244 | |
245 | export default theGeometry; |
246 | |
247 | |
248 | |