• Java解析OpenDrive,OpenDrive格式解析


    1 介绍

    项目地址:https://gitee.com/AiShiYuShiJiePingXing/open-drive-convert

    分支:dev

    找了很多笔记和参考资料,解析OpenDrive得很多开源项目几乎都是C++或者Python做的,奈何那两块都没那么熟悉,只能通过Java实现了,参考了一个项目,实现了Java解析OpenDrive。

    1.1 运行

    clone项目:

    git clone -b dev https://gitee.com/AiShiYuShiJiePingXing/open-drive-convert.git
    

    找到/src/main/java/OpenDriveConvert.java

    修改openDrivePath得路径,运行main方法即可完成测试。

    2 Java解析OpenDrive

    2.1 pom.xml

    先添加几个依赖,下酒菜。

    <dependencies>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.69</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.6</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>RELEASE</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.8.0</version>
            </dependency>
        </dependencies>
    

    2.2 读取本地xodr文件

    public static String readFromFile(String xodrPath) {
        log.info("OpenDRIVE地图文件路径:{}", xodrPath);
    	//xodrPath:eg:D://project//test.xodr
        String xodrStr = null;
        try {
            xodrStr = FileUtils.readFileToString(new File(xodrPath), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        return xodrStr;
    }
    

    2.3 开始解析Map

    public static MapDataContainer parse(String input) {
        log.info("开始解析地图...");
        List<Road> roads = new ArrayList<>();
        List<Junction> junctions = new ArrayList<>();
        List<LaneSection> laneSections = new ArrayList<>();
        List<Lane> lanes = new ArrayList<>();
        List<Connection> connections = new ArrayList<>();
        List<LaneLink> laneLinks = new ArrayList<>();
    
        roadMap = new HashMap<>();
        laneSectionMap = new HashMap<>();
        laneMap = new HashMap<>();
        junctionMap = new HashMap<>();
    
        laneSectionId = 0;
        laneSingleId = 0;
    
        roadIndex = 0;
        laneSectionIndex = 0;
        laneIndex = 0;
        junctionIndex = 0;
        connectionIndex = 0;
        laneLinkIndex = 0;
    
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder documentBuilder = factory.newDocumentBuilder();
            Document document = documentBuilder.parse(new InputSource(new StringReader(input)));
            Element root = document.getDocumentElement();
    
            // 1. 解析road及子元素
            NodeList roadList = root.getElementsByTagName("road");
            parseRoad(roadList, roads, laneSections, lanes);
    
            // 2. 解析junction及子元素
            NodeList junctionList = root.getElementsByTagName("junction");
            parseJunction(junctionList, junctions, connections, laneLinks);
    
            // 3. 初始化index; 初始化connection的direction
            initIndex(roads, laneSections, lanes, junctions, connections, laneLinks);
    
            log.info("解析地图完成!");
            return new MapDataContainer(roads, junctions, laneSections, lanes, connections, laneLinks);
    
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
            log.error("解析OpenDRIVE文件时发生错误!");
            return null;
        }
    
    }
    

    2.4 解析Road

    private static void parseRoad(NodeList roadList, List<Road> roads, List<LaneSection> laneSections, List<Lane> lanes) {
        try {
            for (int i = 0; i < roadList.getLength(); i++) {
                Element roadElement = (Element) roadList.item(i);
                Road road = new Road();
    
                //    int elementType;
                road.setElementType(ElementType.ROAD.getValue());
                //    int roadId;
                int roadId = Integer.parseInt(roadElement.getAttribute("id"));
                road.setRoadId(roadId);
    
                road.setIndex(roadIndex); // 初始化index
                roadMap.put(roadId, roadIndex++);
    
                //    int junctionId;
                int junctionId = Integer.parseInt(roadElement.getAttribute("junction"));
                road.setJunctionId(junctionId);
                //    int length;
                double length = Double.parseDouble(roadElement.getAttribute("length"));
                road.setLength(length);
                //    int predecessorElementType;
                //    int successorElementType;
                int predecessorId = -1;
                int successorId = -1;
                ElementType predecessorElementType = ElementType.NONE;
                ElementType successorElementType = ElementType.NONE;
    
                NodeList linkList = roadElement.getElementsByTagName("link");
                Element myLinkList = (Element) linkList.item(0);
                NodeList predecessorList = null, successorList = null;
                if (myLinkList != null) {
                    predecessorList = myLinkList.getElementsByTagName("predecessor");
                    successorList = myLinkList.getElementsByTagName("successor");
                }
    
                if (predecessorList != null) {
                    Element predecessor = (Element) predecessorList.item(0);
                    if (predecessor != null) {
                        String elementId = predecessor.getAttribute("elementId");
                        String elementType = predecessor.getAttribute("elementType");
                        if (elementId != null && elementType != null && elementId.length() != 0 && elementType.length() != 0) {
                            predecessorId = Integer.parseInt(elementId);
                            predecessorElementType = elementType.equalsIgnoreCase("junction")
                                ? ElementType.JUNCTION : ElementType.ROAD;
                            road.setPredecessorElementType(predecessorElementType.getValue());
                        }
                    }
                }
                road.setPredecessorElementType(predecessorElementType.getValue());
                road.setPredecessorId(predecessorId);
    
                if (successorList != null) {
                    Element successor = (Element) successorList.item(0);
                    if (successor != null) {
                        String elementId = successor.getAttribute("elementId");
                        String elementType = successor.getAttribute("elementType");
                        if (elementId != null && elementType != null && elementId.length() != 0 && elementType.length() != 0) {
                            successorId = Integer.parseInt(elementId);
                            successorElementType = elementType.equalsIgnoreCase("junction")
                                ? ElementType.JUNCTION : ElementType.ROAD;
                        }
                    }
                }
                road.setSuccessorElementType(successorElementType.getValue());
                road.setSuccessorId(successorId);
    
                //    int maxSpeed;
                NodeList typeNodeList = roadElement.getElementsByTagName("type");
                if (typeNodeList != null) {
                    Element typeElement = (Element) typeNodeList.item(0);
                    if (typeElement != null) {
                        NodeList speedNodeList = typeElement.getElementsByTagName("speed");
                        if (speedNodeList != null) {
                            Element speedElement = (Element) speedNodeList.item(0);
                            double maxSpeed = Double.parseDouble(speedElement.getAttribute("max"));
                            road.setMaxSpeed(maxSpeed);
                        }
                    }
                } else {
                    road.setMaxSpeed(UppaalUtil.INT16_MAX * 1.0 / UppaalUtil.K);
                }
    
                // laneSections
                NodeList lanesNodeList = roadElement.getElementsByTagName("lanes");
                Element lanesElement = (Element) lanesNodeList.item(0);
                NodeList laneSectionList = lanesElement.getElementsByTagName("laneSection");
                parseLaneSection(laneSectionList, road, laneSections, lanes);
    
                roads.add(road);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2.5 解析车道属性

    private static void parseLaneSection(NodeList laneSectionList, Road road, List<LaneSection> laneSections, List<Lane> lanes) {
        try {
            List<LaneSection> roadLaneSections = new ArrayList<>();
            List<Integer> laneSectionsIndex = new ArrayList<>();
            for (int i = 0; i < laneSectionList.getLength(); i++) {
                Element laneSectionElement = (Element) laneSectionList.item(i);
                LaneSection laneSection = new LaneSection();
                //private int elementType;
                laneSection.setElementType(ElementType.LANE_SECTION.getValue());
                //private int roadIndex;
                //private int roadId;
                laneSection.setRoadId(road.getRoadId());
                laneSection.setRoadIndex(road.getIndex());
    
                //private int laneSectionId;
                laneSection.setLaneSectionId(laneSectionId);
                laneSection.setIndex(laneSectionIndex);
                laneSectionsIndex.add(laneSectionIndex);
                laneSectionMap.put(laneSectionId++, laneSectionIndex++);
    
                //private double startPosition;
                double s = Double.parseDouble(laneSectionElement.getAttribute("s"));
                laneSection.setStartPosition(s);
    
                //private double length;
                double length = 0; // 本车道段起始位置减去上一个的起始位置
                laneSection.setLength(length);
    
                // lanes
                NodeList laneList = laneSectionElement.getElementsByTagName("lane");
                parseLane(laneList, laneSection, lanes);
    
                roadLaneSections.add(laneSection);
                laneSections.add(laneSection);
            }
            road.setLaneSectionsIndex(laneSectionsIndex);
            road.setLaneSections(roadLaneSections);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2.6 解析车道

    private static void parseLane(NodeList laneList, LaneSection laneSection, List<Lane> lanes) {
        try {
            List<Lane> laneSectionLanes = new ArrayList<>();
            List<Integer> lanesIndex = new ArrayList<>();
            for (int i = 0; i < laneList.getLength(); i++) {
                Element laneElement = (Element) laneList.item(i);
                Lane lane = new Lane();
    
                //                private int elementType;
                lane.setElementType(ElementType.LANE.getValue());
                //                private int roadId;
                lane.setRoadId(laneSection.getRoadId());
                //                private int roadIndex;
                lane.setRoadIndex(laneSection.getRoadIndex());
                //                private int laneSectionIndex;
                lane.setLaneSectionIndex(laneSection.getIndex());
                //                private int laneSectionId;
                lane.setLaneSectionId(laneSection.getLaneSectionId());
                //                private int laneId;
                lane.setLaneId(Integer.parseInt(laneElement.getAttribute("id")));
    
                lane.setSingleId(laneSingleId); //上面的setLaneId中是相对位置,这里是标识符
                lane.setIndex(laneIndex);
                lanesIndex.add(laneIndex);
                laneMap.put(laneSingleId++, laneIndex++);
    
                //                private int type;
                String type = laneElement.getAttribute("type");
                if (type.equals("driving")) {
                    lane.setType(1);
                } else {
                    lane.setType(0);
                }
    
                //                private int predecessorIndex;
                //                private int predecessorLaneId; // 与laneId同类,表示相对位置
                //                private int predecessorId; // 标识符
                NodeList predecessorList = laneElement.getElementsByTagName("predecessor");
                String predecessorLaneId;
                if (predecessorList != null) {
                    Element predecessorElement = (Element) predecessorList.item(0);
                    if (predecessorElement != null) {
                        predecessorLaneId = predecessorElement.getAttribute("id");
                        lane.setPredecessorLaneId(Integer.parseInt(predecessorLaneId));
                    }
                }
    
                //                private int successorIndex; 
                //                private int successorLaneId;
                //                private int successorId;
                NodeList successorList = laneElement.getElementsByTagName("successor");
                String successorLaneId;
                if (successorList != null) {
                    Element successorElement = (Element) successorList.item(0);
                    if (successorElement != null) {
                        successorLaneId = successorElement.getAttribute("id");
                        lane.setSuccessorLaneId(Integer.parseInt(successorLaneId));
                    }
                }
    
                //private int laneChange;
                NodeList roadMarkList = laneElement.getElementsByTagName("roadMark");
                Element roadMarkElement = (Element) roadMarkList.item(0);
                String laneChange = roadMarkElement.getAttribute("laneChange");
                lane.setLaneChange(laneChangeType.getOrDefault(laneChange, 0));
    
                // width
                NodeList widthList = laneElement.getElementsByTagName("width");
                Element widthElement = (Element) widthList.item(0);
                String width = "0.0";
                if (widthElement != null) { // 不是所有的lane都有width,比如center(中心线)没有
                    width = widthElement.getAttribute("a");
                }
                lane.setWidth(Double.parseDouble(width));
    
                laneSectionLanes.add(lane);
                lanes.add(lane);
            }
            laneSection.setLanesIndex(lanesIndex);
            laneSection.setLanes(laneSectionLanes);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2.7 解析交叉口

    private static void parseJunction(NodeList junctionList, List<Junction> junctions, List<Connection> connections, List<LaneLink> laneLinks) {
        try {
            for (int i = 0; i < junctionList.getLength(); i++) {
                Element junctionElement = (Element) junctionList.item(i);
    
                Junction junction = new Junction();
                // int elementType;
                junction.setElementType(ElementType.JUNCTION.getValue());
                // int junctionId;
                int junctionId = Integer.parseInt(junctionElement.getAttribute("id"));
    
                junction.setIndex(junctionIndex);
                junctionMap.put(junctionId, junctionIndex++);
    
                // connections;
                NodeList connectionList = junctionElement.getElementsByTagName("connection");
                parseConnection(connectionList, junction, connections, laneLinks);
    
                junctions.add(junction);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2.8 解析连接关系

    private static void parseConnection(NodeList connectionList, Junction junction, List<Connection> connections, List<LaneLink> laneLinks) {
        try {
            List<Connection> junctionConnections = new ArrayList<>();
            List<Integer> connectionsIndex = new ArrayList<>();
            for (int i = 0; i < connectionList.getLength(); i++) {
                Element connectionElement = (Element) connectionList.item(i);
    
                Connection connection = new Connection();
                int incomingRoadId = Integer.parseInt(connectionElement.getAttribute("incomingRoad"));
                int connectingRoadId = Integer.parseInt(connectionElement.getAttribute("connectingRoad"));
    
                connection.setIncomingRoadId(incomingRoadId);
                connection.setConnectingRoadId(connectingRoadId);
    
                connection.setIndex(connectionIndex);
                connectionsIndex.add(connectionIndex++); // 上级junction中connection索引
    
                // laneLinks
                NodeList laneLinkList = connectionElement.getElementsByTagName("laneLink");
                parseLaneLink(laneLinkList, connection, laneLinks);
    
                connections.add(connection);
                junctionConnections.add(connection);
            }
            junction.setConnectionsIndex(connectionsIndex);
            junction.setConnections(junctionConnections);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2.9 解析车道连接

    private static void parseLaneLink(NodeList laneLinkList, Connection connection, List<LaneLink> laneLinks) {
        try {
            List<LaneLink> connectionLaneLinks = new ArrayList<>();
            List<Integer> laneLinksIndex = new ArrayList<>();
            for (int i = 0; i < laneLinkList.getLength(); i++) {
                Element laneLinkElement = (Element) laneLinkList.item(i);
                LaneLink laneLink = new LaneLink();
    
                laneLink.setFrom(Integer.parseInt(laneLinkElement.getAttribute("from")));
                laneLink.setTo(Integer.parseInt(laneLinkElement.getAttribute("to")));
    
                laneLink.setIndex(laneLinkIndex);
                laneLinksIndex.add(laneLinkIndex++); // 上级laneLinks索引
    
                connectionLaneLinks.add(laneLink);
                laneLinks.add(laneLink);
            }
            connection.setLaneLinksIndex(laneLinksIndex);
            connection.setLaneLinks(connectionLaneLinks);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    2.10 初始化各结构的索引

    private static void initIndex(List<Road> roads, List<LaneSection> laneSections, List<Lane> lanes,
                                  List<Junction> junctions, List<Connection> connections, List<LaneLink> laneLinks) {
        // road: 需要初始化junctionIndex, predecessorIndex, successorIndex
        initRoad(roads);
        // lane: 需要初始化predecessorIndex, successorIndex
        initLane(lanes, laneSections, roads);
        // connection: 需要初始化incomingRoadIndex, connectionRoadIndex; direction
        initConnection(connections, junctions, roads);
    }
    

    2.11 初始化Road

    private static void initRoad(List<Road> roads) {
        // road: junctionIndex, predecessorIndex, successorIndex
        for (Road road : roads) {
            // junctionIndex
            road.setJunctionIndex(junctionMap.getOrDefault(road.getJunctionId(), -1));
            // predecessorIndex
            if (road.getPredecessorElementType() == 1) { // road
                road.setPredecessorIndex(roadMap.getOrDefault(road.getPredecessorId(), -1));
            } else if (road.getPredecessorElementType() == 4) { // junction
                road.setPredecessorIndex(junctionMap.getOrDefault(road.getPredecessorId(), -1));
            } else {
                road.setPredecessorIndex(-1);
            }
            // successorIndex
            if (road.getSuccessorElementType() == 1) { // road
                road.setSuccessorIndex(roadMap.getOrDefault(road.getSuccessorId(), -1));
            } else if (road.getSuccessorElementType() == 4) { // junction
                road.setSuccessorIndex(junctionMap.getOrDefault(road.getSuccessorId(), -1));
            } else {
                road.setSuccessorIndex(-1);
            }
        }
    }
    

    2.12 初始化车道

    private static void initLane(List<Lane> lanes, List<LaneSection> laneSections, List<Road> roads) {
        log.warn("Lane的前驱后继索引初始化尚未完成:跨road部分");
        for (Lane lane : lanes) {
            Road currentRoad = roads.get(lane.getRoadIndex());
            LaneSection currentLaneSection = laneSections.get(lane.getLaneSectionIndex());
    
            /*
                    前驱:
                    1 当前laneSection不是当前road的第一个车道段,那么
                    - 当前laneSection的index-1,即前一个laneSection,找到对应的predecessorLaneId即可
                    2 当前laneSection是当前road的第一个车道段,那么
                    - 找到当前road的前驱road,根据两条road的连接方式判断predecessorLaneId属于前驱road的第一个还是最后一个车道段
                */
            if (lane.getPredecessorLaneId() != 0) {
                LaneSection preLaneSection;
                if (currentLaneSection.getStartPosition() != 0.0) { // 不是第一个车道段
                    preLaneSection = laneSections.get(currentLaneSection.getIndex() - 1);
                } else { //是第一个车道段
                    if (StrUtil.isNotBlank(String.valueOf(currentRoad.getPredecessorId()))) {
                        if (ObjectUtil.isNotEmpty(roadMap.get(currentRoad.getPredecessorId()))) {
                            Road preRoad = roads.get(roadMap.get(currentRoad.getPredecessorId())); // 如果是Junction?
                            int connectType = 0; // TODO: 两个road的连接方式,影响着前一个laneSection是preRoad的第一个还是最后一个
                            if (connectType == 0) { // 第一个
                                preLaneSection = preRoad.getLaneSections().get(0);
                            } else { // 最后一个
                                int length = preRoad.getLaneSections().size();
                                preLaneSection = preRoad.getLaneSections().get(length - 1);
                            }
                            updatePreLaneIndex(lane, preLaneSection);
                        }
                    }
                }
    
            }
    
            /*
                    后继:
                    1 当前laneSection不是当前road的最后一个车道段,那么
                    - 当前laneSection的index+1,即后一个laneSection,找到对应的successorLaneId即可
                    2 当前laneSection是当前road的最后一个车道段,那么
                    - 找到当前road的后继road,根据两条road的连接方式判断successorLaneId属于后继road的第一个还是最后一个车道段
                 */
            if (lane.getSuccessorLaneId() != 0) {
                LaneSection sucLaneSection;
                // 最后一个车道段
                int lastIndex = currentRoad.getLaneSections().size() - 1;
                LaneSection lastLaneSection = currentRoad.getLaneSections().get(lastIndex);
    
                if (currentLaneSection.getStartPosition() != lastLaneSection.getStartPosition()) { // 不是最后一个车道段
                    sucLaneSection = laneSections.get(currentLaneSection.getIndex() + 1);
                } else { //是最后一个车道段
                    if (StrUtil.isNotBlank(String.valueOf(currentRoad.getSuccessorId()))) {
                        if (ObjectUtil.isNotEmpty(roadMap.get(currentRoad.getSuccessorId()))) {
                            Road sucRoad = roads.get(roadMap.get(currentRoad.getSuccessorId()));
                            int connectType = 0; // TODO: 两个road的连接方式,影响着前一个laneSection是preRoad的第一个还是最后一个
                            if (connectType == 0) { // 第一个
                                sucLaneSection = sucRoad.getLaneSections().get(0);
                            } else { // 最后一个
                                int length = sucRoad.getLaneSections().size();
                                sucLaneSection = sucRoad.getLaneSections().get(length - 1);
                            }
                            updateSucLaneIndex(lane, sucLaneSection);
                        }
                    }
                }
            }
    
        }
    }
    

    抽取出来的一个方法,通过前驱laneSection更新lane的前驱:

    private static void updatePreLaneIndex(Lane lane, LaneSection preLaneSection) {
        // 更新lane
        for (Lane preLane : preLaneSection.getLanes()) {
            if (preLane.getLaneId() == lane.getPredecessorLaneId()) {
                lane.setPredecessorSingleId(preLane.getSingleId());
                lane.setPredecessorIndex(preLane.getIndex());
                break;
            }
        }
    }
    

    抽取出来的一个方法,通过后继laneSection更新lane的后继:

    private static void updateSucLaneIndex(Lane lane, LaneSection sucLaneSection) {
        for (Lane preLane : sucLaneSection.getLanes()) {
            if (preLane.getLaneId() == lane.getPredecessorLaneId()) {
                lane.setSuccessorSingleId(preLane.getSingleId());
                lane.setSuccessorIndex(preLane.getIndex());
                break;
            }
        }
    }
    

    2.13 初始化连接

    private static void initConnection(List<Connection> connections, List<Junction> junctions, List<Road> roads) {
        // connection: incomingRoadIndex, connectionRoadIndex
        for (Connection connection : connections) {
            connection.setIncomingRoadIndex(roadMap.getOrDefault(connection.getIncomingRoadId(), -1));
            connection.setConnectingRoadIndex(roadMap.getOrDefault(connection.getConnectingRoadId(), -1));
        }
    
        // 设置direction
        for (Road road : roads) {
            if (road.getJunctionId() != -1) {
                int direction = 1; // 1左转 2直行 3右转 其他都不正常忽略掉
                for (Junction junction : junctions) {
                    for (Connection connection : junction.getConnections()) {
                        if (connection.getConnectingRoadId() == road.getRoadId()) { // 作为连接路
                            connection.setDirection(direction++);
                        }
                    }
                }
            }
        }
    }
    
  • 相关阅读:
    no,no,不要使用kill -9
    Linux中etc目录详解
    Quartz任务调度器的使用
    RMI(Remote Method invocation,远程方法访问)
    SilverLight扩展控件RadTreeView
    SiverLight和HTML交互
    SilverLight控件之ContextMenu和RadContextMenu(菜单)
    SilverLight之向后台请求数据-WebClient
    SilverLight控件样式及控件模版
    在SilverLight中代码编写可选择树节点
  • 原文地址:https://www.cnblogs.com/aixing/p/16247993.html
Copyright © 2020-2023  润新知