1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    SUMOVehicleClass.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Michael Behrisch
14 /// @author  Walter Bamberger
15 /// @author  Laura Bieker-Walz
16 /// @date    2006-01-24
17 /// @version $Id$
18 ///
19 // Definitions of SUMO vehicle classes and helper functions
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <string>
29 #include <map>
30 #include "SUMOVehicleClass.h"
31 #include <utils/common/StringUtils.h>
32 #include <utils/common/ToString.h>
33 #include <utils/common/MsgHandler.h>
34 #include <utils/common/StringTokenizer.h>
35 #include <utils/iodevices/OutputDevice.h>
36 #include <utils/xml/SUMOSAXAttributes.h>
37 
38 
39 // ===========================================================================
40 // static members
41 // ===========================================================================
42 
43 StringBijection<SUMOVehicleClass>::Entry sumoVehicleClassStringInitializer[] = {
44     {"ignoring",          SVC_IGNORING},
45     {"private",           SVC_PRIVATE},
46     {"public_emergency",  SVC_EMERGENCY}, // !!! deprecated
47     {"emergency",         SVC_EMERGENCY},
48     {"public_authority",  SVC_AUTHORITY}, // !!! deprecated
49     {"authority",         SVC_AUTHORITY},
50     {"public_army",       SVC_ARMY}, // !!! deprecated
51     {"army",              SVC_ARMY},
52     {"vip",               SVC_VIP},
53     {"passenger",         SVC_PASSENGER},
54     {"hov",               SVC_HOV},
55     {"taxi",              SVC_TAXI},
56     {"public_transport",  SVC_BUS}, // !!! deprecated
57     {"bus",               SVC_BUS},
58     {"coach",             SVC_COACH},
59     {"delivery",          SVC_DELIVERY},
60     {"transport",         SVC_TRUCK},
61     {"truck",             SVC_TRUCK},
62     {"trailer",           SVC_TRAILER},
63     {"lightrail",         SVC_TRAM}, // !!! deprecated
64     {"tram",              SVC_TRAM},
65     {"cityrail",          SVC_RAIL_URBAN}, // !!! deprecated
66     {"rail_urban",        SVC_RAIL_URBAN},
67     {"rail_slow",         SVC_RAIL}, // !!! deprecated
68     {"rail",              SVC_RAIL},
69     {"rail_fast",         SVC_RAIL_ELECTRIC}, // !!! deprecated
70     {"rail_electric",     SVC_RAIL_ELECTRIC},
71     {"motorcycle",        SVC_MOTORCYCLE},
72     {"moped",             SVC_MOPED},
73     {"bicycle",           SVC_BICYCLE},
74     {"pedestrian",        SVC_PEDESTRIAN},
75     {"evehicle",          SVC_E_VEHICLE},
76     //{"automated",         SVC_AUTOMATED},
77     {"ship",              SVC_SHIP},
78     {"custom1",           SVC_CUSTOM1},
79     {"custom2",           SVC_CUSTOM2}
80 };
81 
82 StringBijection<SUMOVehicleClass> SumoVehicleClassStrings(
83     sumoVehicleClassStringInitializer, SVC_CUSTOM2, false);
84 
85 
86 std::set<std::string> deprecatedVehicleClassesSeen;
87 
88 
89 StringBijection<SUMOVehicleShape>::Entry sumoVehicleShapeStringInitializer[] = {
90     {"pedestrian",            SVS_PEDESTRIAN},
91     {"bicycle",               SVS_BICYCLE},
92     {"moped",                 SVS_MOPED},
93     {"motorcycle",            SVS_MOTORCYCLE},
94     {"passenger",             SVS_PASSENGER},
95     {"passenger/sedan",       SVS_PASSENGER_SEDAN},
96     {"passenger/hatchback",   SVS_PASSENGER_HATCHBACK},
97     {"passenger/wagon",       SVS_PASSENGER_WAGON},
98     {"passenger/van",         SVS_PASSENGER_VAN},
99     {"delivery",              SVS_DELIVERY},
100     {"transport",             SVS_TRUCK}, // !!! deprecated
101     {"truck",                 SVS_TRUCK},
102     {"transport/semitrailer", SVS_TRUCK_SEMITRAILER}, // !!! deprecated
103     {"truck/semitrailer",     SVS_TRUCK_SEMITRAILER},
104     {"transport/trailer",     SVS_TRUCK_1TRAILER}, // !!! deprecated
105     {"truck/trailer",         SVS_TRUCK_1TRAILER},
106     {"bus/city",              SVS_BUS}, // !!! deprecated
107     {"bus",                   SVS_BUS},
108     {"bus/overland",          SVS_BUS_COACH}, // !!! deprecated
109     {"bus/coach",             SVS_BUS_COACH},
110     {"bus/flexible",          SVS_BUS_FLEXIBLE},
111     {"bus/trolley",           SVS_BUS_TROLLEY},
112     {"rail/slow",             SVS_RAIL}, // !!! deprecated
113     {"rail/fast",             SVS_RAIL}, // !!! deprecated
114     {"rail",                  SVS_RAIL},
115     {"rail/light",            SVS_RAIL_CAR}, // !!! deprecated
116     {"rail/city",             SVS_RAIL_CAR}, // !!! deprecated
117     {"rail/railcar",          SVS_RAIL_CAR},
118     {"rail/cargo",            SVS_RAIL_CARGO},
119     {"evehicle",              SVS_E_VEHICLE},
120     {"ant",                   SVS_ANT},
121     {"ship",                  SVS_SHIP},
122     {"emergency",             SVS_EMERGENCY},
123     {"firebrigade",           SVS_FIREBRIGADE},
124     {"police",                SVS_POLICE},
125     {"rickshaw",              SVS_RICKSHAW },
126     {"",                      SVS_UNKNOWN}
127 };
128 
129 
130 StringBijection<SUMOVehicleShape> SumoVehicleShapeStrings(
131     sumoVehicleShapeStringInitializer, SVS_UNKNOWN, false);
132 
133 // ===========================================================================
134 // static values used for cached
135 // ===========================================================================
136 
137 static std::map<int, std::vector<std::string> > vehicleClassNamesListCached;
138 static std::map<std::string, SVCPermissions> parseVehicleClassesCached;
139 static std::map<SVCPermissions, std::string> getVehicleClassNamesCached;
140 static std::string vehicleClassNameAll = "all";
141 
142 // ===========================================================================
143 // additional constants
144 // ===========================================================================
145 
146 const int SUMOVehicleClass_MAX = SVC_CUSTOM2;
147 
148 const SVCPermissions SVCAll = 2 * SUMOVehicleClass_MAX - 1; // all relevant bits set to 1
149 
150 const SVCPermissions SVC_UNSPECIFIED = -1;
151 
152 const std::string DEFAULT_VTYPE_ID("DEFAULT_VEHTYPE");
153 
154 const std::string DEFAULT_PEDTYPE_ID("DEFAULT_PEDTYPE");
155 
156 const std::string DEFAULT_BIKETYPE_ID("DEFAULT_BIKETYPE");
157 
158 const double DEFAULT_VEH_PROB(1.);
159 
160 const double DEFAULT_PEDESTRIAN_SPEED(5. / 3.6);
161 
162 const double DEFAULT_CONTAINER_TRANSHIP_SPEED(5. / 3.6);
163 
164 // ===========================================================================
165 // method definitions
166 // ===========================================================================
167 // ------------ Conversion of SUMOVehicleClass
168 
169 const std::string&
getVehicleClassNames(SVCPermissions permissions,bool expand)170 getVehicleClassNames(SVCPermissions permissions, bool expand) {
171     if (permissions == SVCAll && !expand) {
172         return vehicleClassNameAll;
173     }
174     // check if previously was cached
175     if (getVehicleClassNamesCached.count(permissions) == 0) {
176         getVehicleClassNamesCached[permissions] = joinToString(getVehicleClassNamesList(permissions), ' ');
177     }
178     return getVehicleClassNamesCached.at(permissions);
179 }
180 
181 
182 const std::vector<std::string>&
getVehicleClassNamesList(SVCPermissions permissions)183 getVehicleClassNamesList(SVCPermissions permissions) {
184     // first check if it's cached
185     if (vehicleClassNamesListCached.count(permissions) == 0) {
186         const std::vector<std::string> classNames = SumoVehicleClassStrings.getStrings();
187         std::vector<std::string> result;
188         for (std::vector<std::string>::const_iterator it = classNames.begin(); it != classNames.end(); it++) {
189             const int svc = (int)SumoVehicleClassStrings.get(*it);
190             if ((svc & permissions) == svc && svc != SVC_IGNORING) {
191                 result.push_back(*it);
192             }
193         }
194         // add it into vehicleClassNamesListCached
195         vehicleClassNamesListCached[permissions] = result;
196     }
197     return vehicleClassNamesListCached.at(permissions);
198 }
199 
200 
201 SUMOVehicleClass
getVehicleClassID(const std::string & name)202 getVehicleClassID(const std::string& name) {
203     if (SumoVehicleClassStrings.hasString(name)) {
204         return SumoVehicleClassStrings.get(name);
205     }
206     throw InvalidArgument("Unknown vehicle class '" + name + "'.");
207 }
208 
209 
210 int
getVehicleClassCompoundID(const std::string & name)211 getVehicleClassCompoundID(const std::string& name) {
212     int ret = SVC_IGNORING;
213     const std::vector<std::string> names = SumoVehicleClassStrings.getStrings();
214     for (std::vector<std::string>::const_iterator it = names.begin(); it != names.end(); it++) {
215         if (name.find(*it) != std::string::npos) {
216             ret = ret | (int) SumoVehicleClassStrings.get(*it);
217         }
218     }
219     return ret;
220 }
221 
222 
223 SVCPermissions
parseVehicleClasses(const std::string & allowedS)224 parseVehicleClasses(const std::string& allowedS) {
225     if (allowedS == "all") {
226         return SVCAll;
227     }
228     // check  if allowedS was previously cached
229     if (parseVehicleClassesCached.count(allowedS) == 0) {
230         SVCPermissions result = 0;
231         StringTokenizer sta(allowedS, " ");
232         while (sta.hasNext()) {
233             const std::string s = sta.next();
234             if (!SumoVehicleClassStrings.hasString(s)) {
235                 WRITE_ERROR("Unknown vehicle class '" + s + "' encountered.");
236             } else {
237                 const SUMOVehicleClass vc = getVehicleClassID(s);
238                 const std::string& realName = SumoVehicleClassStrings.getString(vc);
239                 if (realName != s) {
240                     deprecatedVehicleClassesSeen.insert(s);
241                 }
242                 result |= vc;
243             }
244         }
245         // save parsed vehicle class cached
246         parseVehicleClassesCached[allowedS] = result;
247     }
248     return parseVehicleClassesCached.at(allowedS);
249 }
250 
251 
252 bool
canParseVehicleClasses(const std::string & classes)253 canParseVehicleClasses(const std::string& classes) {
254     if (classes == "all") {
255         return true;
256     }
257     // check if was previously cached
258     if (parseVehicleClassesCached.count(classes) != 0) {
259         return true;
260     }
261     StringTokenizer sta(classes, " ");
262     while (sta.hasNext()) {
263         if (!SumoVehicleClassStrings.hasString(sta.next())) {
264             return false;
265         }
266     }
267     return true;
268 }
269 
270 
271 SVCPermissions
parseVehicleClasses(const std::string & allowedS,const std::string & disallowedS)272 parseVehicleClasses(const std::string& allowedS, const std::string& disallowedS) {
273     if (allowedS.size() == 0 && disallowedS.size() == 0) {
274         return SVCAll;
275     } else if (allowedS.size() > 0 && disallowedS.size() > 0) {
276         WRITE_WARNING("SVCPermissions must be specified either via 'allow' or 'disallow'. Ignoring 'disallow'");
277         return parseVehicleClasses(allowedS);
278     } else if (allowedS.size() > 0) {
279         return parseVehicleClasses(allowedS);
280     } else {
281         return invertPermissions(parseVehicleClasses(disallowedS));
282     }
283 }
284 
285 
286 SVCPermissions
invertPermissions(SVCPermissions permissions)287 invertPermissions(SVCPermissions permissions) {
288     return SVCAll & ~permissions;
289 }
290 
291 
292 SVCPermissions
parseVehicleClasses(const std::vector<std::string> & allowedS)293 parseVehicleClasses(const std::vector<std::string>& allowedS) {
294     SVCPermissions result = 0;
295     if (std::find(allowedS.begin(), allowedS.end(), "all") != allowedS.end()) {
296         return SVCAll;
297     }
298     for (std::vector<std::string>::const_iterator i = allowedS.begin(); i != allowedS.end(); ++i) {
299         const SUMOVehicleClass vc = getVehicleClassID(*i);
300         const std::string& realName = SumoVehicleClassStrings.getString(vc);
301         if (realName != *i) {
302             WRITE_WARNING("The vehicle class '" + (*i) + "' is deprecated, use '" + realName + "' instead.");
303         }
304         result |= getVehicleClassID(*i);
305     }
306     return result;
307 }
308 
309 
310 void
writePermissions(OutputDevice & into,SVCPermissions permissions)311 writePermissions(OutputDevice& into, SVCPermissions permissions) {
312     if (permissions == SVCAll) {
313         return;
314     } else if (permissions == 0) {
315         into.writeAttr(SUMO_ATTR_DISALLOW, "all");
316         return;
317     } else {
318         int num_allowed = 0;
319         for (int mask = 1; mask <= SUMOVehicleClass_MAX; mask = mask << 1) {
320             if ((mask & permissions) == mask) {
321                 ++num_allowed;
322             }
323         }
324         if (num_allowed <= (SumoVehicleClassStrings.size() - num_allowed) && num_allowed > 0) {
325             into.writeAttr(SUMO_ATTR_ALLOW, getVehicleClassNames(permissions));
326         } else {
327             into.writeAttr(SUMO_ATTR_DISALLOW, getVehicleClassNames(~permissions));
328         }
329     }
330 }
331 
332 
333 void
writePreferences(OutputDevice & into,SVCPermissions preferred)334 writePreferences(OutputDevice& into, SVCPermissions preferred) {
335     if (preferred == SVCAll || preferred == 0) {
336         return;
337     } else {
338         into.writeAttr(SUMO_ATTR_PREFER, getVehicleClassNames(preferred));
339     }
340 }
341 
342 
343 SUMOVehicleShape
getVehicleShapeID(const std::string & name)344 getVehicleShapeID(const std::string& name) {
345     if (SumoVehicleShapeStrings.hasString(name)) {
346         return SumoVehicleShapeStrings.get(name);
347     } else {
348         throw InvalidArgument("Unknown vehicle shape '" + name + "'.");
349     }
350 }
351 
352 
353 bool
canParseVehicleShape(const std::string & shape)354 canParseVehicleShape(const std::string& shape) {
355     return SumoVehicleShapeStrings.hasString(shape);
356 }
357 
358 
359 std::string
getVehicleShapeName(SUMOVehicleShape id)360 getVehicleShapeName(SUMOVehicleShape id) {
361     return SumoVehicleShapeStrings.getString(id);
362 }
363 
364 
isRailway(SVCPermissions permissions)365 bool isRailway(SVCPermissions permissions) {
366     return (permissions & SVC_RAIL_CLASSES) > 0 && (permissions & SVC_PASSENGER) == 0;
367 }
368 
369 
370 bool
isWaterway(SVCPermissions permissions)371 isWaterway(SVCPermissions permissions) {
372     return permissions == SVC_SHIP;
373 }
374 
375 
376 bool
isForbidden(SVCPermissions permissions)377 isForbidden(SVCPermissions permissions) {
378     return (permissions & SVCAll) == 0;
379 }
380 
381 
382 bool
isSidewalk(SVCPermissions permissions)383 isSidewalk(SVCPermissions permissions) {
384     return (permissions & SVCAll) == SVC_PEDESTRIAN;
385 }
386 
387 
388 bool
noVehicles(SVCPermissions permissions)389 noVehicles(SVCPermissions permissions) {
390     return isForbidden(permissions) || isSidewalk(permissions);
391 }
392 
393 
parseStopOffsets(const SUMOSAXAttributes & attrs,bool & ok)394 std::map<SVCPermissions, double> parseStopOffsets(const SUMOSAXAttributes& attrs, bool& ok) {
395     const std::string vClasses = attrs.getOpt<std::string>(SUMO_ATTR_VCLASSES, nullptr, ok, "");
396     const std::string exceptions = attrs.getOpt<std::string>(SUMO_ATTR_EXCEPTIONS, nullptr, ok, "");
397     if (attrs.hasAttribute(SUMO_ATTR_VCLASSES) && attrs.hasAttribute(SUMO_ATTR_EXCEPTIONS)) {
398         WRITE_ERROR("Simultaneous specification of vClasses and exceptions is not allowed!");
399         ok = false;
400         return std::map<SVCPermissions, double>();
401     }
402     const double value = attrs.get<double>(SUMO_ATTR_VALUE, nullptr, ok);
403 
404     int vClassBitset;
405     if (attrs.hasAttribute(SUMO_ATTR_VCLASSES)) {
406         vClassBitset = parseVehicleClasses(vClasses);
407     } else if (attrs.hasAttribute(SUMO_ATTR_EXCEPTIONS)) {
408         vClassBitset = ~parseVehicleClasses(exceptions);
409     } else {
410         // no vClasses specified, thus apply to all
411         vClassBitset = parseVehicleClasses("all");
412     }
413 
414     std::map<SVCPermissions, double> offsets;
415     offsets[vClassBitset] = value;
416     return offsets;
417 }
418 
419 /****************************************************************************/
420 
421