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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | #!/usr/bin/python2.5 # Copyright (C) 2007 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from gtfsobjectbase import GtfsObjectBase import problems as problems_module import util class Transfer(GtfsObjectBase): """Represents a transfer in a schedule""" _REQUIRED_FIELD_NAMES = ['from_stop_id', 'to_stop_id', 'transfer_type'] _FIELD_NAMES = _REQUIRED_FIELD_NAMES + ['min_transfer_time'] _TABLE_NAME = 'transfers' _ID_COLUMNS = ['from_stop_id', 'to_stop_id'] def __init__(self, schedule=None, from_stop_id=None, to_stop_id=None, transfer_type=None, min_transfer_time=None, field_dict=None): self._schedule = None if field_dict: self.__dict__.update(field_dict) else: self.from_stop_id = from_stop_id self.to_stop_id = to_stop_id self.transfer_type = transfer_type self.min_transfer_time = min_transfer_time if getattr(self, 'transfer_type', None) in ("", None): # Use the default, recommended transfer, if attribute is not set or blank self.transfer_type = 0 else: try: self.transfer_type = util.NonNegIntStringToInt(self.transfer_type) except (TypeError, ValueError): pass if hasattr(self, 'min_transfer_time'): try: self.min_transfer_time = util.NonNegIntStringToInt(self.min_transfer_time) except (TypeError, ValueError): pass else: self.min_transfer_time = None if schedule is not None: # Note from Tom, Nov 25, 2009: Maybe calling __init__ with a schedule # should output a DeprecationWarning. A schedule factory probably won't # use it and other GenericGTFSObject subclasses don't support it. schedule.AddTransferObject(self) def ValidateFromStopIdIsPresent(self, problems): if util.IsEmpty(self.from_stop_id): problems.MissingValue('from_stop_id') return False return True def ValidateToStopIdIsPresent(self, problems): if util.IsEmpty(self.to_stop_id): problems.MissingValue('to_stop_id') return False return True def ValidateTransferType(self, problems): if not util.IsEmpty(self.transfer_type): if (not isinstance(self.transfer_type, int)) or \ (self.transfer_type not in range(0, 4)): problems.InvalidValue('transfer_type', self.transfer_type) return False return True def ValidateMinimumTransferTime(self, problems): if not util.IsEmpty(self.min_transfer_time): if self.transfer_type != 2: problems.MinimumTransferTimeSetWithInvalidTransferType( self.transfer_type) # If min_transfer_time is negative, equal to or bigger than 24h, issue # an error. If smaller than 24h but bigger than 3h issue a warning. # These errors are not blocking, and should not prevent the transfer # from being added to the schedule. if (isinstance(self.min_transfer_time, int)): if self.min_transfer_time < 0: problems.InvalidValue('min_transfer_time', self.min_transfer_time, reason="This field cannot contain a negative " \ "value.") elif self.min_transfer_time >= 24*3600: problems.InvalidValue('min_transfer_time', self.min_transfer_time, reason="The value is very large for a " \ "transfer time and most likely " \ "indicates an error.") elif self.min_transfer_time >= 3*3600: problems.InvalidValue('min_transfer_time', self.min_transfer_time, type=problems_module.TYPE_WARNING, reason="The value is large for a transfer " \ "time and most likely indicates " \ "an error.") else: # It has a value, but it is not an integer problems.InvalidValue('min_transfer_time', self.min_transfer_time, reason="If present, this field should contain " \ "an integer value.") return False return True def GetTransferDistance(self): from_stop = self._schedule.stops[self.from_stop_id] to_stop = self._schedule.stops[self.to_stop_id] distance = util.ApproximateDistanceBetweenStops(from_stop, to_stop) return distance def ValidateFromStopIdIsValid(self, problems): if self.from_stop_id not in self._schedule.stops.keys(): problems.InvalidValue('from_stop_id', self.from_stop_id) return False return True def ValidateToStopIdIsValid(self, problems): if self.to_stop_id not in self._schedule.stops.keys(): problems.InvalidValue('to_stop_id', self.to_stop_id) return False return True def ValidateTransferDistance(self, problems): distance = self.GetTransferDistance() if distance > 10000: problems.TransferDistanceTooBig(self.from_stop_id, self.to_stop_id, distance) elif distance > 2000: problems.TransferDistanceTooBig(self.from_stop_id, self.to_stop_id, distance, type=problems_module.TYPE_WARNING) def ValidateTransferWalkingTime(self, problems): if util.IsEmpty(self.min_transfer_time): return if self.min_transfer_time < 0: # Error has already been reported, and it does not make sense # to calculate walking speed with negative times. return distance = self.GetTransferDistance() # If min_transfer_time + 120s isn't enough for someone walking very fast # (2m/s) then issue a warning. # # Stops that are close together (less than 240m appart) never trigger this # warning, regardless of min_transfer_time. FAST_WALKING_SPEED= 2 # 2m/s if self.min_transfer_time + 120 < distance / FAST_WALKING_SPEED: problems.TransferWalkingSpeedTooFast(from_stop_id=self.from_stop_id, to_stop_id=self.to_stop_id, transfer_time=self.min_transfer_time, distance=distance) def ValidateBeforeAdd(self, problems): result = True result = self.ValidateFromStopIdIsPresent(problems) and result result = self.ValidateToStopIdIsPresent(problems) and result result = self.ValidateTransferType(problems) and result result = self.ValidateMinimumTransferTime(problems) and result return result def ValidateAfterAdd(self, problems): valid_stop_ids = True valid_stop_ids = self.ValidateFromStopIdIsValid(problems) and valid_stop_ids valid_stop_ids = self.ValidateToStopIdIsValid(problems) and valid_stop_ids # We need both stop IDs to be valid to able to validate their distance and # the walking time between them if valid_stop_ids: self.ValidateTransferDistance(problems) self.ValidateTransferWalkingTime(problems) def Validate(self, problems=problems_module.default_problem_reporter): if self.ValidateBeforeAdd(problems) and self._schedule: self.ValidateAfterAdd(problems) def _ID(self): return tuple(self[i] for i in self._ID_COLUMNS) def AddToSchedule(self, schedule, problems): schedule.AddTransferObject(self, problems) |