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 NIImporter_OpenDrive.h 11 /// @author Daniel Krajzewicz 12 /// @author Jakob Erdmann 13 /// @author Michael Behrisch 14 /// @date Mon, 14.04.2008 15 /// @version $Id$ 16 /// 17 // Importer for networks stored in openDrive format 18 /****************************************************************************/ 19 #ifndef NIImporter_OpenDrive_h 20 #define NIImporter_OpenDrive_h 21 22 23 // =========================================================================== 24 // included modules 25 // =========================================================================== 26 #include <config.h> 27 28 #include <string> 29 #include <map> 30 #include <utils/xml/GenericSAXHandler.h> 31 #include <utils/geom/PositionVector.h> 32 33 34 // =========================================================================== 35 // class declarations 36 // =========================================================================== 37 class NBNetBuilder; 38 class NBEdge; 39 class OptionsCont; 40 class NBNode; 41 class NBNodeCont; 42 43 44 #define UNSET_CONNECTION 100000 45 46 // =========================================================================== 47 // class definitions 48 // =========================================================================== 49 /** 50 * @class NIImporter_OpenDrive 51 * @brief Importer for networks stored in openDrive format 52 * 53 */ 54 class NIImporter_OpenDrive : public GenericSAXHandler { 55 public: 56 /** @brief Loads content of the optionally given SUMO file 57 * 58 * If the option "opendrive-files" is set, the file stored therein is read and 59 * the network definition stored therein is stored within the given network 60 * builder. 61 * 62 * If the option "opendrive-files" is not set, this method simply returns. 63 * 64 * The loading is done by parsing the network definition as an XML file 65 * using the SAXinterface and handling the incoming data via this class' 66 * methods. 67 * 68 * @param[in] oc The options to use 69 * @param[in] nb The network builder to fill 70 */ 71 static void loadNetwork(const OptionsCont& oc, NBNetBuilder& nb); 72 73 74 protected: 75 76 /** 77 * @enum OpenDriveXMLTag 78 * @brief Numbers representing openDrive-XML - element names 79 * @see GenericSAXHandler 80 */ 81 enum OpenDriveXMLTag { 82 OPENDRIVE_TAG_NOTHING, 83 OPENDRIVE_TAG_HEADER, 84 OPENDRIVE_TAG_ROAD, 85 OPENDRIVE_TAG_PREDECESSOR, 86 OPENDRIVE_TAG_SUCCESSOR, 87 /// @todo OPENDRIVE_TAG_NEIGHBOR, 88 /// @todo OPENDRIVE_TAG_TYPE, 89 OPENDRIVE_TAG_GEOMETRY, 90 OPENDRIVE_TAG_LINE, 91 OPENDRIVE_TAG_SPIRAL, 92 OPENDRIVE_TAG_ARC, 93 OPENDRIVE_TAG_POLY3, 94 OPENDRIVE_TAG_PARAMPOLY3, 95 OPENDRIVE_TAG_LANESECTION, 96 OPENDRIVE_TAG_LANEOFFSET, 97 OPENDRIVE_TAG_LEFT, 98 OPENDRIVE_TAG_CENTER, 99 OPENDRIVE_TAG_RIGHT, 100 OPENDRIVE_TAG_LANE, 101 OPENDRIVE_TAG_SIGNAL, 102 OPENDRIVE_TAG_JUNCTION, 103 OPENDRIVE_TAG_CONNECTION, 104 OPENDRIVE_TAG_LANELINK, 105 OPENDRIVE_TAG_WIDTH, 106 OPENDRIVE_TAG_SPEED, 107 OPENDRIVE_TAG_ELEVATION, 108 OPENDRIVE_TAG_GEOREFERENCE, 109 OPENDRIVE_TAG_OBJECT, 110 OPENDRIVE_TAG_REPEAT 111 }; 112 113 114 /** 115 * @enum OpenDriveXMLAttr 116 * @brief Numbers representing openDrive-XML - attributes 117 * @see GenericSAXHandler 118 */ 119 enum OpenDriveXMLAttr { 120 OPENDRIVE_ATTR_NOTHING, 121 OPENDRIVE_ATTR_REVMAJOR, 122 OPENDRIVE_ATTR_REVMINOR, 123 OPENDRIVE_ATTR_ID, 124 OPENDRIVE_ATTR_LENGTH, 125 OPENDRIVE_ATTR_WIDTH, 126 OPENDRIVE_ATTR_RADIUS, 127 OPENDRIVE_ATTR_DISTANCE, 128 OPENDRIVE_ATTR_TSTART, 129 OPENDRIVE_ATTR_TEND, 130 OPENDRIVE_ATTR_WIDTHSTART, 131 OPENDRIVE_ATTR_WIDTHEND, 132 OPENDRIVE_ATTR_JUNCTION, 133 OPENDRIVE_ATTR_ELEMENTTYPE, 134 OPENDRIVE_ATTR_ELEMENTID, 135 OPENDRIVE_ATTR_CONTACTPOINT, 136 OPENDRIVE_ATTR_S, 137 OPENDRIVE_ATTR_T, 138 OPENDRIVE_ATTR_X, 139 OPENDRIVE_ATTR_Y, 140 OPENDRIVE_ATTR_HDG, 141 OPENDRIVE_ATTR_CURVSTART, 142 OPENDRIVE_ATTR_CURVEND, 143 OPENDRIVE_ATTR_CURVATURE, 144 OPENDRIVE_ATTR_A, 145 OPENDRIVE_ATTR_B, 146 OPENDRIVE_ATTR_C, 147 OPENDRIVE_ATTR_D, 148 OPENDRIVE_ATTR_AU, 149 OPENDRIVE_ATTR_BU, 150 OPENDRIVE_ATTR_CU, 151 OPENDRIVE_ATTR_DU, 152 OPENDRIVE_ATTR_AV, 153 OPENDRIVE_ATTR_BV, 154 OPENDRIVE_ATTR_CV, 155 OPENDRIVE_ATTR_DV, 156 OPENDRIVE_ATTR_PRANGE, 157 OPENDRIVE_ATTR_TYPE, 158 OPENDRIVE_ATTR_LEVEL, 159 OPENDRIVE_ATTR_ORIENTATION, 160 OPENDRIVE_ATTR_DYNAMIC, 161 OPENDRIVE_ATTR_INCOMINGROAD, 162 OPENDRIVE_ATTR_CONNECTINGROAD, 163 OPENDRIVE_ATTR_FROM, 164 OPENDRIVE_ATTR_TO, 165 OPENDRIVE_ATTR_MAX, 166 OPENDRIVE_ATTR_SOFFSET, 167 OPENDRIVE_ATTR_NAME, 168 OPENDRIVE_ATTR_UNIT // xodr v1.4 169 }; 170 171 172 /** @brief OpenDrive link type enumeration 173 */ 174 enum LinkType { 175 OPENDRIVE_LT_SUCCESSOR, 176 OPENDRIVE_LT_PREDECESSOR 177 }; 178 179 180 /** @brief OpenDrive element type enumeration 181 */ 182 enum ElementType { 183 OPENDRIVE_ET_UNKNOWN, 184 OPENDRIVE_ET_ROAD, 185 OPENDRIVE_ET_JUNCTION 186 }; 187 188 189 /** @brief OpenDrive contact type enumeration 190 */ 191 enum ContactPoint { 192 OPENDRIVE_CP_UNKNOWN, 193 OPENDRIVE_CP_START, 194 OPENDRIVE_CP_END 195 }; 196 197 /** @brief OpenDrive geometry type enumeration 198 */ 199 enum GeometryType { 200 OPENDRIVE_GT_UNKNOWN, 201 OPENDRIVE_GT_LINE, 202 OPENDRIVE_GT_SPIRAL, 203 OPENDRIVE_GT_ARC, 204 OPENDRIVE_GT_POLY3, 205 OPENDRIVE_GT_PARAMPOLY3 // rev 1.4 206 }; 207 208 209 210 /** 211 * @struct OpenDriveLink 212 * @brief Representation of an OpenDrive link 213 */ 214 struct OpenDriveLink { 215 /** @brief Constructor 216 * @param[in] linkTypeArg The link type 217 * @param[in] elementIDArg The element id 218 */ OpenDriveLinkOpenDriveLink219 OpenDriveLink(LinkType linkTypeArg, const std::string& elementIDArg) 220 : linkType(linkTypeArg), elementID(elementIDArg), 221 elementType(OPENDRIVE_ET_UNKNOWN), contactPoint(OPENDRIVE_CP_UNKNOWN) { } 222 223 LinkType linkType; 224 std::string elementID; 225 ElementType elementType; 226 ContactPoint contactPoint; 227 }; 228 229 230 /** 231 * @struct OpenDriveGeometry 232 * @brief Representation of an OpenDrive geometry part 233 */ 234 struct OpenDriveGeometry { 235 /** @brief Constructor 236 * @param[in] lengthArg The length of this geometry part 237 * @param[in] sArg The offset from the start, counted from the begin 238 * @param[in] xArg x-position at this part's begin 239 * @param[in] yArg y-position at this part's begin 240 * @param[in] hdgArg heading at this part's begin 241 */ OpenDriveGeometryOpenDriveGeometry242 OpenDriveGeometry(double lengthArg, double sArg, double xArg, double yArg, double hdgArg) 243 : length(lengthArg), s(sArg), x(xArg), y(yArg), hdg(hdgArg), 244 type(OPENDRIVE_GT_UNKNOWN) { } 245 246 double length; 247 double s; 248 double x; 249 double y; 250 double hdg; 251 GeometryType type; 252 std::vector<double> params; 253 }; 254 255 /** 256 * @struct OpenDriveElevation 257 * @brief Coefficients of an elevation profile (3rd degree polynomial) 258 */ 259 struct Poly3 { 260 /** @brief Constructor 261 * @param[in] s The start offset 262 * @param[in] a constant 263 * @param[in] b first order 264 * @param[in] c second order 265 * @param[in] d third order 266 */ Poly3Poly3267 Poly3(double _s, double _a, double _b, double _c, double _d) : 268 s(_s), a(_a), b(_b), c(_c), d(_d) {} 269 computeAtPoly3270 double computeAt(double pos) const { 271 const double ds = pos - s; 272 return a + b * ds + c * ds * ds + d * ds * ds * ds; 273 } 274 275 double s; 276 double a; 277 double b; 278 double c; 279 double d; 280 }; 281 282 /// LaneOffset has the same fields as Elevation 283 typedef Poly3 OpenDriveElevation; 284 typedef Poly3 OpenDriveLaneOffset; 285 typedef Poly3 OpenDriveWidth; 286 287 288 /** 289 * @struct OpenDriveLane 290 * @brief Representation of a lane 291 */ 292 struct OpenDriveLane { 293 /** @brief Constructor 294 * @param[in] idArg The OpenDrive id of the lane 295 * @param[in] levelArg The level 296 * @param[in] typeArg type of the lane 297 */ OpenDriveLaneOpenDriveLane298 OpenDriveLane(int idArg, const std::string& levelArg, const std::string& typeArg) : 299 id(idArg), level(levelArg), type(typeArg), successor(UNSET_CONNECTION), predecessor(UNSET_CONNECTION), 300 speed(0), width(NBEdge::UNSPECIFIED_WIDTH) { } 301 302 int id; //!< The lane's id 303 std::string level; //!< The lane's level (not used) 304 std::string type; //!< The lane's type 305 int successor; //!< The lane's successor lane 306 int predecessor; //!< The lane's predecessor lane 307 std::vector<std::pair<double, double> > speeds; //!< List of positions/speeds of speed changes 308 double speed; //!< The lane's speed (set in post-processing) 309 double width; //The lane's maximum width 310 std::vector<OpenDriveWidth> widthData; 311 }; 312 313 314 /** 315 * @struct OpenDriveLaneSection 316 * @brief Representation of a lane section 317 */ 318 struct OpenDriveLaneSection { 319 /** @brief Constructor 320 * @param[in] sArg The offset from the start, counted from the begin 321 */ 322 OpenDriveLaneSection(double sArg); 323 324 325 /** @brief Build the mapping from OpenDrive to SUMO lanes 326 * 327 * Not all lanes are converted to SUMO-lanes; the mapping includes only those 328 * which are included in the SUMO network. 329 * @param[in] tc The type container needed to determine whether a lane shall be imported by using the lane's type 330 */ 331 void buildLaneMapping(const NBTypeCont& tc); 332 333 334 /** @brief Returns the links from the previous to this lane section 335 * @param[in] dir The OpenDrive-direction of drive 336 * @param[in] pre The previous lane section 337 * @return which lane is approached from which lane of the given previous lane section 338 */ 339 std::map<int, int> getInnerConnections(OpenDriveXMLTag dir, const OpenDriveLaneSection& prev); 340 341 342 bool buildSpeedChanges(const NBTypeCont& tc, std::vector<OpenDriveLaneSection>& newSections); 343 OpenDriveLaneSection buildLaneSection(double startPos); 344 345 /// @brief The starting offset of this lane section 346 double s; 347 /// @brief The original starting offset of this lane section (differs from s if the section had to be split) 348 double sOrig; 349 /// @brief A mapping from OpenDrive to SUMO-index (the first is signed, the second unsigned) 350 std::map<int, int> laneMap; 351 /// @brief The lanes, sorted by their direction 352 std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> > lanesByDir; 353 /// @brief The id (generic, without the optionally leading '-') of the edge generated for this section 354 std::string sumoID; 355 /// @brief The number of lanes on the right and on the left side, respectively 356 int rightLaneNumber, leftLaneNumber; 357 /// @brief the composite type built from all used lane types 358 std::string rightType; 359 std::string leftType; 360 }; 361 362 363 364 /** 365 * @struct OpenDriveSignal 366 * @brief Representation of a signal 367 */ 368 struct OpenDriveSignal { 369 /** @brief Constructor 370 * @param[in] idArg The OpenDrive id of the signal 371 * @param[in] typeArg The type of the signal 372 * @param[in] nameArg The type of the signal 373 * @param[in] orientationArg The direction the signal belongs to 374 * @param[in] dynamicArg Whether the signal is dynamic 375 * @param[in] sArg The offset from the start, counted from the begin 376 */ OpenDriveSignalOpenDriveSignal377 OpenDriveSignal(const std::string& idArg, const std::string typeArg, const std::string nameArg, int orientationArg, bool dynamicArg, double sArg) 378 : id(idArg), type(typeArg), name(nameArg), orientation(orientationArg), dynamic(dynamicArg), s(sArg) { } 379 380 std::string id; 381 std::string type; 382 std::string name; 383 int orientation; 384 bool dynamic; 385 double s; 386 }; 387 388 389 /** 390 * @struct Connection 391 * @brief A connection between two roads 392 */ 393 struct Connection { 394 std::string fromEdge; 395 std::string toEdge; 396 int fromLane; 397 int toLane; 398 ContactPoint fromCP; 399 ContactPoint toCP; 400 bool all; 401 std::string origID; 402 int origLane; 403 PositionVector shape; 404 getDescriptionConnection405 std::string getDescription() const { 406 return "Connection from=" + fromEdge + "_" + toString(fromLane) 407 + " to=" + toEdge + "_" + toString(toLane) 408 + " fromCP=" + (fromCP == OPENDRIVE_CP_START ? "start" : fromCP == OPENDRIVE_CP_END ? "end" : "unknown") 409 + " toCP=" + (toCP == OPENDRIVE_CP_START ? "start" : toCP == OPENDRIVE_CP_END ? "end" : "unknown") 410 + " all=" + toString(all); 411 //+ " origID=" + origID + " origLane=" + toString(origLane); 412 } 413 }; 414 415 /** 416 * @struct Object 417 * @brief A road object (e.g. parkingSpace) 418 */ 419 struct OpenDriveObject { 420 std::string type; 421 std::string name; 422 std::string id; 423 double s; 424 double t; 425 double zOffset; 426 double length; 427 double width; 428 double height; 429 double radius; 430 double hdg; 431 double pitch; 432 double roll; 433 }; 434 435 /** 436 * @struct OpenDriveEdge 437 * @brief Representation of an openDrive "link" 438 */ 439 struct OpenDriveEdge { OpenDriveEdgeOpenDriveEdge440 OpenDriveEdge(const std::string& idArg, const std::string& streetNameArg, const std::string& junctionArg, double lengthArg) : 441 id(idArg), 442 streetName(streetNameArg), 443 junction(junctionArg), 444 length(lengthArg), 445 from(0), 446 to(0) { 447 isInner = junction != "" && junction != "-1"; 448 } 449 450 451 /** @brief Returns the edge's priority, regarding the direction 452 * 453 * The priority is determined by evaluating the signs located at the road 454 * @param[in] dir The direction which priority shall be returned 455 * @return The priority of the given direction 456 */ 457 int getPriority(OpenDriveXMLTag dir) const; 458 459 460 /// @brief The id of the edge 461 std::string id; 462 /// @brief The road name of the edge 463 std::string streetName; 464 /// @brief The id of the junction the edge belongs to 465 std::string junction; 466 /// @brief The length of the edge 467 double length; 468 std::vector<OpenDriveLink> links; 469 std::vector<OpenDriveGeometry> geometries; 470 std::vector<OpenDriveElevation> elevations; 471 std::vector<OpenDriveLaneOffset> offsets; 472 NBNode* from; 473 NBNode* to; 474 PositionVector geom; 475 std::vector<OpenDriveLaneSection> laneSections; 476 std::vector<OpenDriveSignal> signals; 477 std::set<Connection> connections; 478 std::vector<OpenDriveObject> objects; 479 bool isInner; 480 }; 481 482 483 /** @brief A class for sorting lane sections by their s-value */ 484 class sections_by_s_sorter { 485 public: 486 /// @brief Constructor sections_by_s_sorter()487 explicit sections_by_s_sorter() { } 488 489 /// @brief Sorting function; compares OpenDriveLaneSection::s operator()490 int operator()(const OpenDriveLaneSection& ls1, const OpenDriveLaneSection& ls2) { 491 return ls1.s < ls2.s; 492 } 493 }; 494 495 /* @brief A class for search in position/speed tuple vectors for the given position */ 496 class same_position_finder { 497 public: 498 /** @brief constructor */ same_position_finder(double pos)499 explicit same_position_finder(double pos) : myPosition(pos) { } 500 501 /** @brief the comparing function */ operator()502 bool operator()(const std::pair<double, double>& ps) { 503 return ps.first == myPosition; 504 } 505 506 private: 507 same_position_finder& operator=(const same_position_finder&); // just to avoid a compiler warning 508 private: 509 /// @brief The position to search for 510 double myPosition; 511 512 }; 513 514 protected: 515 /** @brief Constructor 516 * @param[in] tc The type container used to determine whether a lane shall kept 517 * @param[in] nc The edge map to fill 518 */ 519 NIImporter_OpenDrive(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges); 520 521 522 /// @brief Destructor 523 ~NIImporter_OpenDrive(); 524 525 526 527 /// @name inherited from GenericSAXHandler 528 //@{ 529 530 /** @brief Called on the opening of a tag; 531 * 532 * In dependence to the obtained type, an appropriate parsing 533 * method is called ("addEdge" if an edge encounters, f.e.). 534 * 535 * @param[in] element ID of the currently opened element 536 * @param[in] attrs Attributes within the currently opened element 537 * @exception ProcessError If something fails 538 * @see GenericSAXHandler::myStartElement 539 */ 540 void myStartElement(int element, const SUMOSAXAttributes& attrs); 541 542 /** 543 * @brief Callback method for characters to implement by derived classes 544 * 545 * Called by "endElement" (see there). 546 * @param[in] element The opened element, given as a int 547 * @param[in] chars The complete embedded character string 548 * @exceptions ProcessError These method may throw a ProcessError if something fails 549 */ 550 void myCharacters(int element, const std::string& chars); 551 552 553 /** @brief Called when a closing tag occurs 554 * 555 * @param[in] element ID of the currently opened element 556 * @exception ProcessError If something fails 557 * @see GenericSAXHandler::myEndElement 558 */ 559 void myEndElement(int element); 560 //@} 561 562 563 564 private: 565 void addLink(LinkType lt, const std::string& elementType, const std::string& elementID, 566 const std::string& contactPoint); 567 void addGeometryShape(GeometryType type, const std::vector<double>& vals); 568 static void setEdgeLinks2(OpenDriveEdge& e, const std::map<std::string, OpenDriveEdge*>& edges); 569 static void buildConnectionsToOuter(const Connection& c, const std::map<std::string, OpenDriveEdge*>& innerEdges, std::vector<Connection>& into, std::set<Connection>& seen); 570 static bool laneSectionsConnected(OpenDriveEdge* edge, int in, int out); 571 friend bool operator<(const Connection& c1, const Connection& c2); 572 static std::string revertID(const std::string& id); 573 const NBTypeCont& myTypeContainer; 574 OpenDriveEdge myCurrentEdge; 575 576 std::map<std::string, OpenDriveEdge*>& myEdges; 577 std::vector<int> myElementStack; 578 OpenDriveXMLTag myCurrentLaneDirection; 579 std::string myCurrentJunctionID; 580 std::string myCurrentIncomingRoad; 581 std::string myCurrentConnectingRoad; 582 ContactPoint myCurrentContactPoint; 583 bool myConnectionWasEmpty; 584 585 static bool myImportAllTypes; 586 static bool myImportWidths; 587 static double myMinWidth; 588 static bool myImportInternalShapes; 589 590 591 protected: 592 /** @brief Builds a node or returns the already built 593 * 594 * If the node is already known, it is returned. Otherwise, the 595 * node is built. If the newly built node can not be added to 596 * the container, a ProcessError is thrown. 597 * Otherwise this node is returned. 598 * 599 * @param[in] id The id of the node to build/get 600 * @param[in, changed] pos The position of the node to build/get 601 * @param[filled] nc The node container to retrieve/add the node to 602 * @return The retrieved/built node 603 * @exception ProcessError If the node could not be built/retrieved 604 */ 605 static NBNode* getOrBuildNode(const std::string& id, const Position& pos, NBNodeCont& nc); 606 607 608 static PositionVector geomFromLine(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution); 609 static PositionVector geomFromSpiral(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution); 610 static PositionVector geomFromArc(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution); 611 static PositionVector geomFromPoly(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution); 612 static PositionVector geomFromParamPoly(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution); 613 static Position calculateStraightEndPoint(double hdg, double length, const Position& start); 614 static void calculateCurveCenter(double* ad_x, double* ad_y, double ad_radius, double ad_hdg); 615 static void calcPointOnCurve(double* ad_x, double* ad_y, double ad_centerX, double ad_centerY, 616 double ad_r, double ad_length); 617 618 619 /** @brief Computes a polygon representation of each edge's geometry 620 * @param[in] edges The edges which geometries shall be converted 621 */ 622 static void computeShapes(std::map<std::string, OpenDriveEdge*>& edges); 623 624 static bool hasNonLinearElevation(OpenDriveEdge& e); 625 626 /** @brief Rechecks lane sections of the given edges 627 * 628 * 629 * @param[in] edges The edges which lane sections shall be reviewed 630 */ 631 static void revisitLaneSections(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges); 632 633 static void setNodeSecure(NBNodeCont& nc, OpenDriveEdge& e, 634 const std::string& nodeID, NIImporter_OpenDrive::LinkType lt); 635 636 637 static void splitMinWidths(OpenDriveEdge* e, const NBTypeCont& tc, double minDist); 638 639 static void findWidthSplit(const NBTypeCont& tc, std::vector<OpenDriveLane>& lanes, 640 int section, double sectionStart, double sectionEnd, 641 std::vector<double>& splitPositions); 642 643 static void setStraightConnections(std::vector<OpenDriveLane>& lanes); 644 static void recomputeWidths(OpenDriveLaneSection& sec, double start, double end, double sectionStart, double sectionEnd); 645 static void recomputeWidths(std::vector<OpenDriveLane>& lanes, double start, double end, double sectionStart, double sectionEnd); 646 647 /// The names of openDrive-XML elements (for passing to GenericSAXHandler) 648 static StringBijection<int>::Entry openDriveTags[]; 649 650 /// The names of openDrive-XML attributes (for passing to GenericSAXHandler) 651 static StringBijection<int>::Entry openDriveAttrs[]; 652 653 654 655 }; 656 657 658 #endif 659 660 /****************************************************************************/ 661 662