22
33import static org .mobilitydata .gtfsvalidator .notice .SeverityLevel .ERROR ;
44
5+ import java .util .ArrayList ;
56import java .util .Collection ;
7+ import java .util .List ;
68import java .util .Map ;
79import javax .inject .Inject ;
810import org .mobilitydata .gtfsvalidator .annotation .GtfsValidationNotice ;
@@ -33,14 +35,14 @@ public void validate(NoticeContainer noticeContainer) {
3335 // For all entities with the same trip id
3436 for (Map .Entry <String , Collection <GtfsStopTime >> entry :
3537 stopTimeTableContainer .byTripIdMap ().asMap ().entrySet ()) {
36- Collection <GtfsStopTime > stopTimesForTrip = entry .getValue ();
38+ List <GtfsStopTime > stopTimesForTrip = new ArrayList <>( entry .getValue () );
3739 // Checking entities two by two
38- for ( GtfsStopTime stopTime1 : stopTimesForTrip ) {
39- for (GtfsStopTime stopTime2 : stopTimesForTrip ) {
40- // If the two entities are the same, skip
41- if ( stopTime1 . equals ( stopTime2 ) ) {
42- continue ;
43- }
40+ // Checking entities two by two
41+ for (int i = 0 ; i < stopTimesForTrip . size (); i ++ ) {
42+ GtfsStopTime stopTime1 = stopTimesForTrip . get ( i );
43+ for ( int j = i + 1 ; j < stopTimesForTrip . size (); j ++ ) {
44+ GtfsStopTime stopTime2 = stopTimesForTrip . get ( j ) ;
45+
4446 // If the two entities have overlapping pickup/drop-off windows
4547 if (!(stopTime1 .hasEndPickupDropOffWindow ()
4648 && stopTime1 .hasStartPickupDropOffWindow ()
@@ -50,12 +52,18 @@ public void validate(NoticeContainer noticeContainer) {
5052 && stopTime2 .hasLocationId ())) {
5153 continue ;
5254 }
55+
56+ if (stopTime1 .locationId ().equals (stopTime2 .locationId ())) {
57+ continue ;
58+ }
59+
5360 if (stopTime1 .startPickupDropOffWindow ().isAfter (stopTime2 .endPickupDropOffWindow ())
5461 || stopTime1 .endPickupDropOffWindow ().isBefore (stopTime2 .startPickupDropOffWindow ())
5562 || stopTime1 .endPickupDropOffWindow ().equals (stopTime2 .startPickupDropOffWindow ())
5663 || stopTime1 .startPickupDropOffWindow ().equals (stopTime2 .endPickupDropOffWindow ())) {
5764 continue ;
5865 }
66+
5967 // If the two entities have overlapping pickup/drop-off zones
6068 GtfsGeoJsonFeature stop1GeoJsonFeature =
6169 geoJsonFeaturesContainer .byLocationId (stopTime1 .locationId ());
@@ -64,12 +72,16 @@ public void validate(NoticeContainer noticeContainer) {
6472 if (stop1GeoJsonFeature == null || stop2GeoJsonFeature == null ) {
6573 continue ;
6674 }
75+
6776 if (stop1GeoJsonFeature .geometryOverlaps (stop2GeoJsonFeature )) {
6877 noticeContainer .addValidationNotice (
6978 new OverlappingZoneAndPickupDropOffWindowNotice (
79+ stopTime1 .tripId (),
80+ stopTime1 .stopSequence (),
7081 stopTime1 .locationId (),
7182 stopTime1 .startPickupDropOffWindow (),
7283 stopTime1 .endPickupDropOffWindow (),
84+ stopTime2 .stopSequence (),
7385 stopTime2 .locationId (),
7486 stopTime2 .startPickupDropOffWindow (),
7587 stopTime2 .endPickupDropOffWindow ()));
@@ -89,38 +101,52 @@ public void validate(NoticeContainer noticeContainer) {
89101 severity = ERROR ,
90102 files = @ GtfsValidationNotice .FileRefs ({GtfsGeoJsonFeature .class , GtfsStopTime .class }))
91103 static class OverlappingZoneAndPickupDropOffWindowNotice extends ValidationNotice {
104+ /** The `trip_id` of the entities. */
105+ private final String tripId ;
106+
107+ /** The `stop_sequence` of the first entity in `stop_times.txt`. */
108+ private final Integer stopSequence1 ;
92109
93110 /** The `location_id` of the first entity. */
94- private final String locationIdA ;
111+ private final String locationId1 ;
95112
96113 /** The `start_pickup_drop_off_window` of the first entity in `stop_times.txt`. */
97- private final GtfsTime startPickupDropOffWindowA ;
114+ private final GtfsTime startPickupDropOffWindow1 ;
98115
99116 /** The `end_pickup_drop_off_window` of the first entity in `stop_times.txt`. */
100- private final GtfsTime endPickupDropOffWindowA ;
117+ private final GtfsTime endPickupDropOffWindow1 ;
118+
119+ /** The `stop_sequence` of the second entity in `stop_times.txt`. */
120+ private final Integer stopSequence2 ;
101121
102122 /** The `location_id` of the second entity. */
103- private final String locationIdB ;
123+ private final String locationId2 ;
104124
105125 /** The `start_pickup_drop_off_window` of the second entity in `stop_times.txt`. */
106- private final GtfsTime startPickupDropOffWindowB ;
126+ private final GtfsTime startPickupDropOffWindow2 ;
107127
108128 /** The `end_pickup_drop_off_window` of the second entity in `stop_times.txt`. */
109- private final GtfsTime endPickupDropOffWindowB ;
129+ private final GtfsTime endPickupDropOffWindow2 ;
110130
111131 OverlappingZoneAndPickupDropOffWindowNotice (
112- String locationIdA ,
113- GtfsTime startPickupDropOffWindowA ,
114- GtfsTime endPickupDropOffWindowA ,
115- String locationIdB ,
116- GtfsTime startPickupDropOffWindowB ,
117- GtfsTime endPickupDropOffWindowB ) {
118- this .locationIdA = locationIdA ;
119- this .startPickupDropOffWindowA = startPickupDropOffWindowA ;
120- this .endPickupDropOffWindowA = endPickupDropOffWindowA ;
121- this .locationIdB = locationIdB ;
122- this .startPickupDropOffWindowB = startPickupDropOffWindowB ;
123- this .endPickupDropOffWindowB = endPickupDropOffWindowB ;
132+ String tripId ,
133+ Integer stopSequence1 ,
134+ String locationId1 ,
135+ GtfsTime startPickupDropOffWindow1 ,
136+ GtfsTime endPickupDropOffWindow1 ,
137+ Integer stopSequence2 ,
138+ String locationId2 ,
139+ GtfsTime startPickupDropOffWindow2 ,
140+ GtfsTime endPickupDropOffWindow2 ) {
141+ this .tripId = tripId ;
142+ this .stopSequence1 = stopSequence1 ;
143+ this .locationId1 = locationId1 ;
144+ this .startPickupDropOffWindow1 = startPickupDropOffWindow1 ;
145+ this .endPickupDropOffWindow1 = endPickupDropOffWindow1 ;
146+ this .stopSequence2 = stopSequence2 ;
147+ this .locationId2 = locationId2 ;
148+ this .startPickupDropOffWindow2 = startPickupDropOffWindow2 ;
149+ this .endPickupDropOffWindow2 = endPickupDropOffWindow2 ;
124150 }
125151 }
126152}
0 commit comments