Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file NIImporter_VISUM.h
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @date Fri, 19 Jul 2002
18 : ///
19 : // A VISUM network importer
20 : /****************************************************************************/
21 : #pragma once
22 : #include <config.h>
23 :
24 : #include <string>
25 : #include <map>
26 : #include <vector>
27 : #include <netbuild/NBCapacity2Lanes.h>
28 : #include <utils/importio/LineHandler.h>
29 : #include <utils/importio/LineReader.h>
30 : #include <utils/importio/NamedColumnsParser.h>
31 : #include "NIVisumTL.h"
32 :
33 :
34 : // ===========================================================================
35 : // class declaration
36 : // ===========================================================================
37 : class OptionsCont;
38 : class NBNetBuilder;
39 : class NBNodeCont;
40 : class NBEdgeCont;
41 : class NBNode;
42 : class NBEdge;
43 :
44 :
45 : // ===========================================================================
46 : // class declaration
47 : // ===========================================================================
48 : /**
49 : * @class NIImporter_VISUM
50 : * @brief A VISUM network importer
51 : *
52 : * This class build an internal list of those VISUM-db entries which are
53 : * supported, first. This list is sorted in a way that the parsed dbs can
54 : * build upon each other as their related structures within the XML-input.
55 : * So, nodes are loaded first, then edges, etc.
56 : *
57 : * Because these structures may have a different order within the VISUM-file
58 : * than we need, at first the file is scanned and any occurrence of one of the
59 : * searched dbs is saved. That's where the "Found $XXX at YYY" are printed.
60 : * "YYY" is the character position within the file.
61 : *
62 : * In a second step, the dbs are parsed in the order we need. It is asked for
63 : * each subsequently whether it was found and if so, the proper parse_XXX()
64 : * method is called.
65 : */
66 : class NIImporter_VISUM {
67 : public:
68 : /** @brief Loads network definition from the assigned option and stores it in the given network builder
69 : *
70 : * If the option "visum" is set, the file stored therein is read and
71 : * the network definition stored therein is stored within the given network
72 : * builder.
73 : *
74 : * If the option "visum" is not set, this method simply returns.
75 : *
76 : * @param[in] oc The options to use
77 : * @param[in] nb The network builder to fill
78 : */
79 : static void loadNetwork(const OptionsCont& oc, NBNetBuilder& nb);
80 :
81 :
82 : protected:
83 : /** @brief constructor
84 : *
85 : * Builds the list of typed db parsers ("TypeParser") and stores them in
86 : * mySingleDataParsers in the order the according db values must be parsed.
87 : *
88 : * @param[in,out] nb the network builder (storage) to fill with parsed values
89 : * @param[in] file The name of the file to parse
90 : * @param[in] capacity2Lanes The converter from flow to lanes
91 : * @param[in] useVisumPrio Information whether the VISUM type's priority shall be used
92 : */
93 : NIImporter_VISUM(NBNetBuilder& nb, const std::string& file,
94 : NBCapacity2Lanes capacity2Lanes, bool useVisumPrio,
95 : const std::string& languageFile);
96 :
97 :
98 : /// @brief destructor
99 : ~NIImporter_VISUM();
100 :
101 :
102 : /** @brief Parses the VISUM-network file storing the parsed structures within myNetBuilder
103 : *
104 : * At first, it is checked whether the file can be opened. A ProcessError is thrown
105 : * if not. Otherwise, the file is scanned for occurrences of db table begins. For each found
106 : * db, its position within the file, and the column names are stored in the according
107 : * TypeParser. After this, the sorted list of type parsers is one through and each
108 : * found is used to parse the entries at the found positions using the found column names.
109 : *
110 : * @exception ProcessError If the file could not be opened
111 : */
112 : void load();
113 :
114 : private:
115 : /** @brief Returns the value from the named column as a float
116 : *
117 : * @param[in] fieldName Name of the column to extract the float from
118 : * @return The parsed real
119 : * @exception OutOfBoundsException If the current data line has less entries than the float's position
120 : * @exception NumberFormatException If the float is not numeric
121 : * @exception UnknownElement If the named data field is not in the line
122 : */
123 : double getNamedFloat(const std::string& fieldName);
124 :
125 : /** @brief The same, but two different names for the field are allowed
126 : *
127 : * @param[in] fieldName1 Name of the first column to extract the float from
128 : * @param[in] fieldName2 Name of the second column to extract the efloat from
129 : * @return The parsed real
130 : * @exception OutOfBoundsException If the current data line has less entries than the float's position
131 : * @exception NumberFormatException If the float is not numeric
132 : * @exception UnknownElement If the named data field is not in the line
133 : */
134 : double getNamedFloat(const std::string& fieldName1, const std::string& fieldName2);
135 :
136 :
137 : /** @brief Returns the value from the named column as a float or the default value if an error occurs
138 : *
139 : * @param[in] fieldName Name of the column to extract the float from
140 : * @param[in] defaultValue The default to return in the case of an error
141 : * @return The parsed real or the default value if an error while parsing occurred
142 : */
143 : double getNamedFloat(const std::string& fieldName, double defaultValue);
144 :
145 : /** @brief The same, but two different names for the field are allowed
146 : *
147 : * @param[in] fieldName1 Name of the first column to extract the float from
148 : * @param[in] fieldName2 Name of the second column to extract the efloat from
149 : * @param[in] defaultValue The default to return in the case of an error
150 : * @return The parsed real or the default value if an error while parsing occurred
151 : */
152 : double getNamedFloat(const std::string& fieldName1, const std::string& fieldName2,
153 : double defaultValue);
154 :
155 :
156 : /** @brief Returns the value from the named column as a normalised string
157 : *
158 : * "Normalised" means herein that the leading '0' (zeros) are prunned.
159 : *
160 : * @param[in] fieldName Name of the column to extract the string from
161 : * @return The parsed, normalised string
162 : * @exception OutOfBoundsException If the current data line has less entries than the string's position
163 : * @exception NumberFormatException If the string is not numeric
164 : * @exception UnknownElement If the named data field is not in the line
165 : */
166 : std::string getNamedString(const std::string& fieldName);
167 :
168 : /** @brief The same, but two different names for the field are allowed
169 : *
170 : * @param[in] fieldName1 Name of the first column to extract the string from
171 : * @param[in] fieldName2 Name of the second column to extract the string from
172 : * @return The parsed, normalised string
173 : * @exception OutOfBoundsException If the current data line has less entries than the string's position
174 : * @exception NumberFormatException If the string is not numeric
175 : * @exception UnknownElement If the named data field is not in the line
176 : */
177 : std::string getNamedString(const std::string& fieldName1, const std::string& fieldName2);
178 :
179 :
180 : /** @brief tries to get a double which is possibly assigned to a certain modality
181 : *
182 : * When the double cannot be extracted using the given name, "(IV)" is
183 : * appended to the begin of the name. Note that this function does not
184 : * yet support public traffic.
185 : *
186 : * @param[in] name Name of the column to extract the real from
187 : * @return The real stored under the named column, or if not found the one from name + suffix, or if not found -1
188 : */
189 : double getWeightedFloat(const std::string& name, const std::string& suffix);
190 :
191 : /// @brief as above but with two alternative names
192 : double getWeightedFloat2(const std::string& name, const std::string& name2, const std::string& suffix);
193 :
194 : /// @brief parse permissions
195 : SVCPermissions getPermissions(const std::string& name, bool warn = false, SVCPermissions unknown = SVCAll);
196 :
197 : /** @brief tries to get a bool which is possibly assigned to a certain modality
198 : *
199 : * When the bool cannot be extracted using the given name, "IV" is
200 : * appended to the begin of the name. Note that this function does not
201 : * yet support public traffic.
202 : *
203 : * @param[in] name Name of the column to extract the bool from
204 : * @return The bool stored under the named column, or if not found the one from "(IV)"+name, or if not found false
205 : */
206 : bool getWeightedBool(const std::string& name);
207 :
208 :
209 : /** @brief Tries to get the node which name is stored in the given field
210 : *
211 : * If the field can not be parsed, an exception is thrown. Prints an error if the
212 : * node could not be found, returning 0. Otherwise, if the field could be parsed
213 : * and the node was found, this node is returned.
214 : *
215 : * @param[in] fieldName Name of the column to extract the node's name from
216 : * @return An already known node with the found name
217 : * @exception OutOfBoundsException If the current data line has less entries than the node id's position
218 : * @exception NumberFormatException If the node id is not numeric
219 : * @exception UnknownElement If the named data field is not in the line
220 : */
221 : NBNode* getNamedNode(const std::string& fieldName);
222 : NBNode* getNamedNodeSecure(const std::string& fieldName, NBNode* fallback = 0);
223 :
224 : /** @brief The same, but two different names for the field are allowed
225 : *
226 : * @param[in] fieldName1 Name of the first column to extract the node's name from
227 : * @param[in] fieldName2 Name of the second column to extract the node's name from
228 : * @return An already known node with the found name
229 : * @exception OutOfBoundsException If the current data line has less entries than the node id's position
230 : * @exception NumberFormatException If the node id is not numeric
231 : * @exception UnknownElement If the named data field is not in the line
232 : */
233 : NBNode* getNamedNode(const std::string& fieldName1, const std::string& fieldName2);
234 :
235 :
236 : /** @brief Tries to get the edge which name is stored in the given field
237 : *
238 : * If the field can not be parsed, an exception is thrown. Prints an error if the
239 : * edge could not be found, returning 0. Otherwise, if the field could be parsed
240 : * and the edge was found, this edge is returned.
241 : *
242 : * @param[in] fieldName Name of the column to extract the edge's name from
243 : * @return An already known edge with the found name
244 : * @exception OutOfBoundsException If the current data line has less entries than the edge id's position
245 : * @exception NumberFormatException If the edge id is not numeric
246 : * @exception UnknownElement If the named data field is not in the line
247 : */
248 : NBEdge* getNamedEdge(const std::string& fieldName);
249 :
250 : /** @brief The same, but two different names for the field are allowed
251 : *
252 : * @param[in] fieldName1 Name of the first column to extract the edge's name from
253 : * @param[in] fieldName2 Name of the second column to extract the edge's name from
254 : * @return An already known edge with the found name
255 : * @exception OutOfBoundsException If the current data line has less entries than the edge id's position
256 : * @exception NumberFormatException If the edge id is not numeric
257 : * @exception UnknownElement If the named data field is not in the line
258 : */
259 : NBEdge* getNamedEdge(const std::string& fieldName1, const std::string& fieldName2);
260 :
261 :
262 : /** @brief Tries to get the edge which name is stored in the given field
263 : * continuating the search for a subedge that ends at the given node
264 : *
265 : * If the field can not be parsed, an exception is thrown. Prints an error if the
266 : * edge could not be found, returning 0. Otherwise, if the field could be parsed
267 : * and the edge was found, this edge is returned.
268 : *
269 : * @param[in] fieldName Name of the column to extract the edge's name from
270 : * @param[in] node The node the consecutive edge must end at in order to be returned
271 : * @return The edge's continuation up to the given node, 0 if not found
272 : * @exception OutOfBoundsException If the current data line has less entries than the edge id's position
273 : * @exception NumberFormatException If the edge id is not numeric
274 : * @exception UnknownElement If the named data field is not in the line
275 : */
276 : NBEdge* getNamedEdgeContinuating(const std::string& fieldName, NBNode* node);
277 :
278 : /** @brief The same, but two different names for the field are allowed
279 : *
280 : * @param[in] fieldName1 Name of the first column to extract the edge's name from
281 : * @param[in] fieldName2 Name of the second column to extract the edge's name from
282 : * @param[in] node The node the consecutive edge must end at in order to be returned
283 : * @return The edge's continuation up to the given node, 0 if not found
284 : * @exception OutOfBoundsException If the current data line has less entries than the edge id's position
285 : * @exception NumberFormatException If the edge id is not numeric
286 : * @exception UnknownElement If the named data field is not in the line
287 : */
288 : NBEdge* getNamedEdgeContinuating(const std::string& fieldName1, const std::string& fieldName2,
289 : NBNode* node);
290 :
291 : /** @brief The same, but for an already given edge
292 : *
293 : * @param[in] begin The edge to get the continuation of
294 : * @param[in] node The node the consecutive edge must end at in order to be returned
295 : * @return The edge's continuation up to the given node, 0 if not found
296 : */
297 : NBEdge* getNamedEdgeContinuating(NBEdge* begin, NBNode* node);
298 :
299 :
300 : /** @brief Returns the edge that connects both nodes
301 : *
302 : * @param[in] FromNode Name of the node the edge shall start at
303 : * @param[in] ToNode Name of the node the edge shall end at
304 : * @return The edge connecting both nodes, 0 if no such edge exists
305 : */
306 : NBEdge* getEdge(NBNode* FromNode, NBNode* ToNode);
307 :
308 :
309 : /** @brief Returns the opposite direction of the given edge
310 : *
311 : * Because the opposite direction edge may be split, not the plain opposite
312 : * edge, the one which name is obtained by adding/removing the leading '-', is returned,
313 : * but its continuation until the named node.
314 : *
315 : * @param[in] edge Name of the edge to find the opposite of
316 : * @param[in] node Name of the node the opposite edge's continuation must end at
317 : * @return The found opposite edge's continuation, 0 if not found
318 : */
319 : NBEdge* getReversedContinuating(NBEdge* edge, NBNode* node);
320 :
321 :
322 : /** @brief Builds a node for the given district and returns it
323 : *
324 : * If the district does not exist, an error is generated and 0 returned. Otherwise
325 : * a position for the new node is computed and the new node is built using a combination
326 : * of the district name and the node name as id. If Inserting this node into
327 : * the net builder fails, zero is returned.
328 : *
329 : * @param[in] id Name of the district
330 : * @param[in] dest Name of the according network node
331 : * @param[in] isSource Information whether this node will be used as a source
332 : * @return The built node, zero if an error occurred
333 : */
334 : NBNode* buildDistrictNode(const std::string& id, NBNode* dest, bool isSource);
335 :
336 :
337 : /** @brief Returns whether both nodes are a valid combination of from/to-nodes
338 : *
339 : * They are valid if both are !=0 and differ.
340 : *
341 : * @param[in] from The from-node
342 : * @param[in] from The to-node
343 : * @return Whether the nodes may be used
344 : */
345 : bool checkNodes(NBNode* from, NBNode* to);
346 :
347 :
348 : private:
349 : /**
350 : * @brief Definition of a function for parsing a single line from a certain db
351 : *
352 : * This function may assume that both the LineParser is initialised
353 : * with the current line.
354 : */
355 : typedef void (NIImporter_VISUM::*ParsingFunction)();
356 :
357 : /**
358 : * @struct TypeParser
359 : * @brief A complete call description for parsing a single db.
360 : */
361 712 : struct TypeParser {
362 : /** @brief The name of the db
363 : *
364 : * Initialised in the constructor */
365 : std::string name;
366 :
367 : /** @brief Pointer to the function used for parsing
368 : *
369 : * Initialised in the constructor */
370 : ParsingFunction function;
371 :
372 : /** @brief Position of the according db within the file
373 : *
374 : * Set to -1 in the constructor, and reset to the position while
375 : * scanning the file if the according db was found */
376 : long position;
377 :
378 : /** @brief The column names
379 : *
380 : * Set while scanning the file if the according db was found */
381 : std::string pattern;
382 :
383 : };
384 :
385 :
386 :
387 : /// @brief Parses VSYS
388 : void parse_VSysTypes();
389 :
390 : /// @brief Parses STRECKENTYP
391 : void parse_Types();
392 :
393 : /// @brief Parses KNOTEN
394 : void parse_Nodes();
395 :
396 : /// @brief Parses BEZIRK
397 : void parse_Districts();
398 :
399 : /// @brief Parses PUNKT
400 : void parse_Point();
401 :
402 :
403 : /// @brief Parses STRECKE/STRECKEN
404 : void parse_Edges();
405 :
406 : /// @brief Parses FLAECHENELEMENT
407 : void parse_PartOfArea();
408 :
409 : /// @brief Parses FLAECHENELEMENT
410 : void parse_Kante();
411 :
412 :
413 : /// @brief Parses ANBINDUNG
414 : void parse_Connectors();
415 : void parse_Connectors_legacy();
416 :
417 : /// @brief Parses ABBIEGEBEZIEHUNG/ABBIEGER
418 : void parse_Turns();
419 :
420 : /// @brief Parses STRECKENPOLY
421 : void parse_EdgePolys();
422 :
423 : /// @brief Parses FAHRSTREIFEN
424 : void parse_Lanes();
425 :
426 : /// @brief Parses LSA/SIGNALANLAGE
427 : void parse_TrafficLights();
428 :
429 : /// @brief Parses KNOTENZULSA/SIGNALANLAGEZUKNOTEN
430 : void parse_NodesToTrafficLights();
431 :
432 : /// @brief Parses LSASIGNALGRUPPE/SIGNALGRUPPE
433 : void parse_SignalGroups();
434 :
435 : /// @brief Parses ABBZULSASIGNALGRUPPE/SIGNALGRUPPEZUABBIEGER
436 : void parse_TurnsToSignalGroups();
437 :
438 : /// @brief Parses ABBZULSASIGNALGRUPPE/SIGNALGRUPPEZUABBIEGER
439 : void parse_AreaSubPartElement();
440 :
441 : /// @brief Parses LSAPHASE/PHASE
442 : void parse_Phases();
443 :
444 : /// @brief Parses LSASIGNALGRUPPEZULSAPHASE
445 : void parse_SignalGroupsToPhases();
446 :
447 : /// @brief Parses FAHRSTREIFENABBIEGER
448 : void parse_LanesConnections();
449 :
450 : /// @brief Parses HALTEPUNKT (public transport stop locations)
451 : void parse_stopPoints();
452 :
453 : /** @brief Adds a parser into the sorted list of parsers to use
454 : *
455 : * @param[in] name db name to assign the parser to
456 : * @param[in] function The function to use for parsing the named db
457 : */
458 : void addParser(const std::string& name, ParsingFunction function);
459 :
460 : private:
461 :
462 : /// @brief whether the edge id ends with _nodeID
463 : static bool isSplitEdge(NBEdge* edge, NBNode* node);
464 :
465 :
466 : private:
467 : /// @brief The network builder to fill with loaded values
468 : NBNetBuilder& myNetBuilder;
469 :
470 : /// @brief The name of the parsed file, for error reporting
471 : std::string myFileName;
472 :
473 : /// @brief The line reader to use to read from the file
474 : LineReader myLineReader;
475 :
476 : /** @brief the parser to parse the information from the data lines
477 : *
478 : * the order of columns within the visum format seems to vary, so a named parser is needed */
479 : NamedColumnsParser myLineParser;
480 :
481 : /// @brief The converter to compute the lane number of edges from their capacity
482 : NBCapacity2Lanes myCapacity2Lanes;
483 :
484 : /// @brief Definition of a storage for vsystypes
485 : typedef std::map<std::string, std::string> VSysTypeNames;
486 : /// @brief The used vsystypes
487 : VSysTypeNames myVSysTypes;
488 :
489 : /// @brief Definition of the list of known parsers
490 : typedef std::vector<TypeParser> ParserVector;
491 : /// @brief List of known parsers
492 : ParserVector mySingleDataParsers;
493 :
494 : /// @brief Definition of a map for loaded traffic lights (id->tls)
495 : typedef std::map<std::string, NIVisumTL*> NIVisumTL_Map;
496 : /// @brief List of visum traffic lights
497 : NIVisumTL_Map myTLS;
498 :
499 : /// @brief Already read edges
500 : std::vector<std::string > myTouchedEdges;
501 :
502 : /// @brief Information whether VISUM priority information shall be used
503 : bool myUseVisumPrio;
504 :
505 : /// @brief The name of the currently parsed item used for error reporting
506 : std::string myCurrentID;
507 :
508 :
509 : /// @brief A map of point ids to positions
510 : std::map<long long int, Position> myPoints;
511 :
512 : /// @brief A map of edge (not road, but "edge" in this case) ids to from/to-points
513 : std::map<long long int, std::pair<long long int, long long int> > myEdges;
514 :
515 : /// @brief A map from district shape definition name to the district
516 : std::map<long long int, NBDistrict*> myShapeDistrictMap;
517 :
518 : /// @brief A map from area parts to area ids
519 : std::map<long long int, std::vector<long long int> > mySubPartsAreas;
520 :
521 : /// @brief A temporary storage for district shapes as they are filled incrementally
522 : std::map<NBDistrict*, PositionVector> myDistrictShapes;
523 :
524 : protected:
525 : /**
526 : * @enum VISUM keys
527 : * @brief Numbers representing VISUM keywords
528 : */
529 : enum VISUM_KEY {
530 : VISUM_SYS,
531 : VISUM_LINKTYPE,
532 : VISUM_NODE,
533 : VISUM_DISTRICT,
534 : VISUM_POINT,
535 : VISUM_LINK,
536 : VISUM_V0,
537 : VISUM_TYPES,
538 : VISUM_RANK,
539 : VISUM_CAPACITY,
540 : VISUM_XCOORD,
541 : VISUM_YCOORD,
542 : VISUM_FROMNODE,
543 : VISUM_TONODE,
544 : VISUM_TYPE,
545 : VISUM_TYP,
546 : VISUM_ID,
547 : VISUM_CODE,
548 : VISUM_DISTRICT_CONNECTION,
549 : VISUM_SOURCE_DISTRICT,
550 : VISUM_FROMNODENO,
551 : VISUM_DIRECTION,
552 : VISUM_SURFACEID,
553 : VISUM_FACEID,
554 : VISUM_FROMPOINTID,
555 : VISUM_TOPOINTID,
556 : VISUM_EDGE,
557 : VISUM_VIANODENO,
558 : VISUM_NUMLANES,
559 : VISUM_TURN,
560 : VISUM_INDEX,
561 : VISUM_LINKPOLY,
562 : VISUM_SURFACEITEM,
563 : VISUM_FACEITEM,
564 : VISUM_EDGEID,
565 : VISUM_ORIGIN,
566 : VISUM_DESTINATION,
567 : VISUM_STOPPOINT,
568 : VISUM_NAME,
569 : VISUM_LINKNO,
570 : VISUM_RELPOS,
571 : // polyconvert keys added to avoid warnings
572 : VISUM_CATID,
573 : VISUM_EDGEITEM,
574 : VISUM_POICATEGORY,
575 : VISUM_NO // must be the last one
576 : };
577 :
578 : /// Strings for the keywords
579 : static StringBijection<VISUM_KEY>::Entry KEYS_DE[];
580 :
581 : /// @brief link directions
582 : static StringBijection<VISUM_KEY> KEYS;
583 :
584 : void loadLanguage(const std::string& file);
585 : };
|