File : core/WayPointEditor.js

1
/*
2
Copyright - 2017 2023 - wwwouaiebe - Contact: https://www.ouaie.be/
3
4
This  program is free software;
5
you can redistribute it and/or modify it under the terms of the
6
GNU General Public License as published by the Free Software Foundation;
7
either version 3 of the License, or any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
*/
18
/*
19
Changes:
20
    - v4.0.0:
21
        - created from v3.6.0
22
Doc reviewed 202208
23
 */
24
25
import theConfig from '../data/Config.js';
26
import theTravelNotesData from '../data/TravelNotesData.js';
27
import WayPointPropertiesDialog from '../dialogs/wayPointPropertiesDialog/WayPointPropertiesDialog.js';
28
import GeoCoder from './lib/GeoCoder.js';
29
import WayPoint from '../data/WayPoint.js';
30
import theEventDispatcher from './lib/EventDispatcher.js';
31
import theGeometry from './lib/Geometry.js';
32
import theRouter from './lib/Router.js';
33
34
import { ROUTE_EDITION_STATUS, TWO } from '../main/Constants.js';
35
36
/* ------------------------------------------------------------------------------------------------------------------------- */
37
/**
38
This class contains methods fot WayPoints creation or modifications
39
See theWayPointEditor for the one and only one instance of this class
40
*/
41
/* ------------------------------------------------------------------------------------------------------------------------- */
42
43
class WayPointEditor {
44
45
    /**
46
    This method rename a WayPoint with data from Nominatim
47
    @param {WayPoint} wayPoint The wayPoint to rename
48
    */
49
50
    async #renameWayPointWithGeocoder ( wayPoint ) {
51
        if ( ! theConfig.wayPoint.reverseGeocoding ) {
52
            theEventDispatcher.dispatch ( 'updatetravelproperties' );
53
            theEventDispatcher.dispatch ( 'updateroadbook' );
54
            theEventDispatcher.dispatch ( 'updateprofilename', { routeObjId : theTravelNotesData.editedRouteObjId } );
55
            return;
56
        }
57
        const address = await new GeoCoder ( ).getAddressAsync ( wayPoint.latLng );
58
59
        // Due to slow response of the geocoder, sometime the edited route is not anymore edited...
60
        // See issue ♯15
61
        if ( theTravelNotesData.editedRouteObjId === theTravelNotesData.travel.editedRoute.objId ) {
62
            theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
63
        }
64
        wayPoint.address = address.street;
65
        if ( '' !== address.city ) {
66
            wayPoint.address += ' ' + address.city;
67
        }
68
        wayPoint.name = '';
69
        if ( theConfig.wayPoint.geocodingIncludeName ) {
70
            wayPoint.name = address.name;
71
        }
72
        theEventDispatcher.dispatch ( 'updatetravelproperties' );
73
        theEventDispatcher.dispatch ( 'updateroadbook' );
74
        theEventDispatcher.dispatch ( 'updateprofilename', { routeObjId : theTravelNotesData.travel.editedRoute.objId } );
75
    }
76
77
    /**
78
    This method set the starting WayPoint
79
    @param {Array.<Number>} latLng The latitude and longitude where the WayPoint will be added
80
    */
81
82
    #setStartPoint ( latLng ) {
83
        const wayPoint = theTravelNotesData.travel.editedRoute.wayPoints.first;
84
        wayPoint.latLng = latLng;
85
        this.#renameWayPointWithGeocoder ( wayPoint );
86
        theEventDispatcher.dispatch (
87
            'addwaypoint',
88
            {
89
                wayPoint : wayPoint,
90
                letter : 'A'
91
            }
92
        );
93
    }
94
95
    /**
96
    This method set the ending WayPoint
97
    @param {Array.<Number>} latLng The latitude and longitude where the WayPoint will be added
98
    */
99
100
    #setEndPoint ( latLng ) {
101
        const wayPoint = theTravelNotesData.travel.editedRoute.wayPoints.last;
102
        wayPoint.latLng = latLng;
103
        this.#renameWayPointWithGeocoder ( wayPoint );
104
        theEventDispatcher.dispatch (
105
            'addwaypoint',
106
            {
107
                wayPoint : wayPoint,
108
                letter : 'B'
109
            }
110
        );
111
    }
112
113
    /**
114
    the constructor
115
    */
116
117
    constructor ( ) {
118
        Object.freeze ( this );
119
    }
120
121
    /**
122
    This method add a WayPoint
123
    @param {Array.<Number>} latLng The latitude and longitude where the WayPoint will be added
124
    */
125
126
    addWayPoint ( latLng ) {
127
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
128
        const wayPoint = new WayPoint ( );
129
        wayPoint.latLng = latLng;
130
        theTravelNotesData.travel.editedRoute.wayPoints.add ( wayPoint );
131
        this.#renameWayPointWithGeocoder ( wayPoint );
132
        theEventDispatcher.dispatch (
133
            'addwaypoint',
134
            {
135
                wayPoint : theTravelNotesData.travel.editedRoute.wayPoints.last,
136
                letter : theTravelNotesData.travel.editedRoute.wayPoints.length - TWO
137
            }
138
        );
139
        theTravelNotesData.travel.editedRoute.wayPoints.swap ( wayPoint.objId, true );
140
        theRouter.startRouting ( );
141
    }
142
143
    /**
144
    This method add a waypoint at a given position on the edited route. It's used to add a WayPoint by
145
    dragging
146
    @param {Array.<Number>} initialLatLng The latitude and longitude from witch the WayPoint is coming
147
    @param {Array.<Number>} finalLatLng The latitude and longitude where the WayPoint will be added
148
    */
149
150
    addWayPointOnRoute ( initialLatLng, finalLatLng ) {
151
        const newWayPointDistance = theGeometry.getClosestLatLngDistance (
152
            theTravelNotesData.travel.editedRoute,
153
            initialLatLng
154
        ).distance;
155
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
156
        const wayPoint = new WayPoint ( );
157
        wayPoint.latLng = finalLatLng;
158
        let letter = '';
159
        const wayPointsIterator = theTravelNotesData.travel.editedRoute.wayPoints.iterator;
160
        while ( ! wayPointsIterator.done ) {
161
            const latLngDistance = theGeometry.getClosestLatLngDistance (
162
                theTravelNotesData.travel.editedRoute,
163
                wayPointsIterator.value.latLng
164
            );
165
            if ( newWayPointDistance < latLngDistance.distance ) {
166
                letter = String ( wayPointsIterator.index );
167
                theTravelNotesData.travel.editedRoute.wayPoints.add ( wayPoint );
168
                theTravelNotesData.travel.editedRoute.wayPoints.moveTo (
169
                    wayPoint.objId, wayPointsIterator.value.objId, true
170
                );
171
                this.#renameWayPointWithGeocoder ( wayPoint );
172
                theEventDispatcher.dispatch ( 'addwaypoint', { wayPoint : wayPoint, letter : letter } );
173
                theRouter.startRouting ( );
174
                break;
175
            }
176
        }
177
    }
178
179
    /**
180
    This method reverse the waypoints order
181
    */
182
183
    reverseWayPoints ( ) {
184
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
185
        let wayPointsIterator = theTravelNotesData.travel.editedRoute.wayPoints.iterator;
186
        while ( ! wayPointsIterator.done ) {
187
            theEventDispatcher.dispatch ( 'removeobject', { objId : wayPointsIterator.value.objId } );
188
        }
189
        theTravelNotesData.travel.editedRoute.wayPoints.reverse ( );
190
        wayPointsIterator = theTravelNotesData.travel.editedRoute.wayPoints.iterator;
191
        while ( ! wayPointsIterator.done ) {
192
            theEventDispatcher.dispatch (
193
                'addwaypoint',
194
                {
195
                    wayPoint : wayPointsIterator.value,
196
                    letter :
197
                        wayPointsIterator .first ? 'A' : ( wayPointsIterator.last ? 'B' : String ( wayPointsIterator.index ) )
198
                }
199
            );
200
        }
201
        theEventDispatcher.dispatch ( 'updatetravelproperties' );
202
        theEventDispatcher.dispatch ( 'updateroadbook' );
203
        theRouter.startRouting ( );
204
    }
205
206
    /**
207
    This method remove a WayPoint
208
    @param {Number} wayPointObjId The objId of the WayPoint to remove
209
    */
210
211
    removeWayPoint ( wayPointObjId ) {
212
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
213
        theEventDispatcher.dispatch ( 'removeobject', { objId : wayPointObjId } );
214
        theTravelNotesData.travel.editedRoute.wayPoints.remove ( wayPointObjId );
215
        theRouter.startRouting ( );
216
    }
217
218
    /**
219
    This method set the starting WayPoint
220
    @param {Array.<Number>} latLng The latitude and longitude where the WayPoint will be added
221
    */
222
223
    setStartPoint ( latLng ) {
224
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
225
        this.#setStartPoint ( latLng );
226
        theRouter.startRouting ( );
227
    }
228
229
    /**
230
    This method set the ending WayPoint
231
    @param {Array.<Number>} latLng The latitude and longitude where the WayPoint will be added
232
    */
233
234
    setEndPoint ( latLng ) {
235
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
236
        this.#setEndPoint ( latLng );
237
        theRouter.startRouting ( );
238
    }
239
240
    /**
241
    This method set the starting and ending WayPoint
242
    @param {Array.<Number>} latLng The latitude and longitude where the WayPoints will be added
243
    */
244
245
    setStartAndEndPoint ( latLng ) {
246
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
247
        this.#setStartPoint ( latLng );
248
        this.#setEndPoint ( latLng );
249
        if ( TWO < theTravelNotesData.travel.editedRoute.wayPoints.length ) {
250
            theRouter.startRouting ( );
251
        }
252
    }
253
254
    /**
255
    This method is called when a drag of a WayPoint ends on the map
256
    @param {Number} dragEndEvent The drag event
257
    */
258
259
    wayPointDragEnd ( dragEndEvent ) {
260
        theTravelNotesData.travel.editedRoute.editionStatus = ROUTE_EDITION_STATUS.editedChanged;
261
        const draggedWayPoint = theTravelNotesData.travel.editedRoute.wayPoints.getAt ( dragEndEvent.target.objId );
262
        const latLng = dragEndEvent.target.getLatLng ( );
263
        draggedWayPoint.latLng = [ latLng.lat, latLng.lng ];
264
        this.#renameWayPointWithGeocoder ( draggedWayPoint );
265
        theRouter.startRouting ( );
266
    }
267
268
    /**
269
    This method shows the WayPointPropertiesDialog
270
    @param {Number} wayPointObjId The objId of the WayPoint that modify
271
    */
272
273
    wayPointProperties ( wayPointObjId ) {
274
        const wayPoint = theTravelNotesData.travel.editedRoute.wayPoints.getAt ( wayPointObjId );
275
        new WayPointPropertiesDialog ( wayPoint )
276
            .show ( )
277
            .then (
278
                ( ) => {
279
                    theEventDispatcher.dispatch ( 'updatetravelproperties' );
280
                    theEventDispatcher.dispatch ( 'updateroadbook' );
281
                }
282
            )
283
            .catch (
284
                err => {
285
                    if ( err instanceof Error ) {
286
                        console.error ( err );
287
                    }
288
                }
289
            );
290
    }
291
}
292
293
/* ------------------------------------------------------------------------------------------------------------------------- */
294
/**
295
The one and only one instance of WayPointEditor class
296
@type {WayPointEditor}
297
*/
298
/* ------------------------------------------------------------------------------------------------------------------------- */
299
300
const theWayPointEditor = new WayPointEditor ( );
301
302
export default theWayPointEditor;
303
304
/* --- End of file --------------------------------------------------------------------------------------------------------- */
305