醉月思 发布的文章

目前,我采用的是迪杰斯特拉算法计算所有点的最短路径(感觉弗洛伊德算法会更好些?)。迪杰斯特拉算法算的是单源(V_begin)到所有点的最短距离,也就是说需要遍历一次所有的点。

遍历V_begin

for (int V_begin = 0; V_begin < G->m_CrossRoad_v.size(); V_begin++) {
}
下面是迪杰斯特拉算法的流程

1. 声明dist数组

vector<double> Determined_dist(G->m_CrossRoad_v.size(), 0.0);

2. 初始化顶点集

void calcShortestPath(Graph *G) {
    int currentPointSite,nextPointSite;
    ofstream PointPathFile(DIR_RES"PointPath.txt"),RoadPathFile(DIR_RES"RoadPath.txt");
    //对点进行的一级遍历
    for (int V_begin = 0; V_begin < G->m_CrossRoad_v.size(); V_begin++) {
        // =================== 迪杰斯特拉算法开始 ===============================
        vector<bool> S(G->m_CrossRoad_v.size(), false); //判断是否选中
        vector<double> dist(G->m_CrossRoad_v.size(), DBL_MAX/2);// dist
        vector<double> compare_dist(G->m_CrossRoad_v.size(), DBL_MAX/2);// 辅助dist用来取最短距离点
        vector<int> path(G->m_CrossRoad_v.size(),-2); // path
        S[V_begin] = true;
        path[V_begin] = -1;
        for(auto crossroad : G->m_CrossRoad_v[V_begin].JunctionRoad){
            nextPointSite = G->m_Road_v[crossroad.outRoadID].m_CrossRoadToSite;
            dist[nextPointSite] = G->m_Road_v[crossroad.outRoadID].m_dLength;
            compare_dist[nextPointSite] = dist[nextPointSite];
        }
        auto min = min_element(compare_dist.begin(), compare_dist.end());
        int min_element_index = distance(compare_dist.begin(), min);
        compare_dist[min_element_index] = DBL_MAX/2;
        // 循环size-1次
        for(int i = 0; i < G->m_CrossRoad_v.size()-1; i++){
            for(auto crossroad : G->m_CrossRoad_v[min_element_index].JunctionRoad){
                currentPointSite = min_element_index;
                nextPointSite = G->m_Road_v[crossroad.outRoadID].m_CrossRoadToSite;
                if(S[nextPointSite]){
                    continue;
                }
                if(dist[nextPointSite] > dist[currentPointSite] + G->m_Road_v[crossroad.outRoadID].m_dLength) {
                    dist[nextPointSite] = dist[currentPointSite] + G->m_Road_v[crossroad.outRoadID].m_dLength;
                    compare_dist[nextPointSite] = dist[nextPointSite];
                    path[nextPointSite] = currentPointSite;
                }
            }
            min = min_element(compare_dist.begin(), compare_dist.end());
            min_element_index = distance(compare_dist.begin(), min);
            S[min_element_index] = true;
            compare_dist[min_element_index] = DBL_MAX/2;
        }
        for(int i = 0;i<path.size();i++){
            int j = i;
            bool flag = false;
            while( path[j] >= 0) {
                flag = true;
                PointPathFile << path[j] << " ";
                for(auto node:G->m_CrossRoad_v[j].JunctionRoad){
                    if(G->m_Road_v[node.outRoadID].m_CrossRoadToSite == path[j]){
                        RoadPathFile << node.outRoadID << " ";
                    }
                }
                j = path[j];
            }
            if(flag){RoadPathFile << endl;PointPathFile << endl ;}
        }
    }
}

runSimulation(Graph &G)

1. 遍历每条道路

2. 遍历该道路的车辆

a. 计算特定时间间隔后的位置

b. 若应行驶至其他道路

进入对应的路口缓冲区,根据路口类的红绿灯对象判断是否能通行。

若能通行,则填至目标道路

若不能,则继续停留在路口缓冲区

c. 若仍停留在原道路

改变该车在当前道路的位置。

  for (auto &road:G.m_Road_v) {
        auto src = road.m_queVehicle;
        decltype(road.m_queVehicle) obj;
        //路内车的遍历
        while (!src.empty()) {
            //弹出一辆车
            auto it = src.front();
            src.pop_front();
            // 当车的时间戳小于实际时间时,才模拟运行
            if (it.time < SYSTEM_TIME) {
                it.fSpec = (100 - road.get_Congestion() - 20) / 3.6;
                dist = it.dDistance + it.fSpec * 10;
                it.time++;

                it.showself();
                //如果车十秒后不在此路
                if (dist >= road.m_dLength) {
                    //路径擦除
                    auto route = it.queRoute;
                    int site = it.m_nSiteRoadID;
                    route.pop();
                    //如果抵达终点
                    if (route.empty()) {
                        cout << "it is be shutdown" << endl;
                        exit(0);
                        // 否侧没有抵达终点
                    } else {
                        //获取所在路和下一条路的ID
                        int next = route.front();
                        //判断红绿灯情况
                        cout << site << endl;
                        G.m_CrossRoad_v[site].m_CTrafficLight_Light.clock(SYSTEM_TIME);
                        //如果可以通行
                        if (G.m_CrossRoad_v[site].m_CTrafficLight_Light.getStatus(it.m_nSiteRoadID, next)) {
                            cout << GREEN << "绿灯通行:" << endl;
                            it.queRoute = route;
                            it.dDistance = 0;
                            it.m_nSiteRoadID = next;
                            auto *site_road = &G.m_Road_v[next].m_queVehicle;
                            site_road->push_back(it);
                            //如果不能通行
                        } else {
                            //将距离置为道路长度,表示正在等候红灯
                            it.dDistance = G.m_Road_v[it.m_nSiteRoadID].m_dLength;
                            cout << YELLOW << "等待红灯" << endl;
                            //车辆塞回去
                            obj.push_back(it);
                        }
                    }
                    //否则,当车十秒后还在此路时
                } else {
                    it.dDistance = dist;
                    obj.push_back(it);
                }
                //否则直接填入
            } else {
                obj.push_back(it);
            }
        }
        road.m_queVehicle = obj;
    }

generateVehicle(Map_Graph);

1. 随机车辆总数

  • [ ] 此处未随机,待完善
std::random_device rd;
std::mt19937 mt(rd());

2. 遍历车辆,为车辆设立起点和路线

a. 在道路向量中随机选一条路径

-[ ] 此处未随机,待完善

auto route = v_Route[3];

b. 以该路径的首序列为起点

Vehicle car(n_VehicleNum, route, 0, 0, route.front());
G.m_Road_v[route.front()].m_queVehicle.push_back(car);

介绍

TmWeBlog--微信小程序版WeTypecho魔改版

原项目介绍

众所周知,现在由于移动互联网的普及,网站访问量下降,导致个人站长非常难混。

WeTypecho则能帮您快速搭建微信小程序,将Typecho博客的内容映射到微信小程序。
帮助您在一定程度上获取更多来自微信的流量。WeTypecho的安非常简单,只需三分钟,就能搭建。


原项目自定义的修改版

项目地址

原项目地址
当前项目地址

功能

目前支持的基本功能如下:

  • 首页预览置顶文章
  • 评论,回复,点赞
  • 转发,分享到朋友圈
  • 图片视频显示
  • 支持markdown,html解析

扫码预览

gh_3d207c9d6dd4_258.jpg

ToDoList

  • [ ] 留言回复通知

1. 从文件(route.txt)中读取路径

形如以下格式

0 1 
0 1 2 
0 1 2 3 
0 1 2 3 4 
0 1 2 3 4 5 
0 1 2 3 4 5 6 
0 1 2 3 4 5 6 7 

其中,一行表示一条可完全畅通的道路编号序列。将所有道路存入v_Route

vector<queue<int>> v_Route;

/**
 * load route from route file
 * @param Map_graph
 */
void loadRoute(Graph &Map_graph) {
    string str_Path;
    ifstream fin_Route(DIR_RES"route.txt");
    while (getline(fin_Route, str_Path)) {
        stringstream ss_Temp(str_Path);
        queue<int> q_Path_Temp;
        int n_Temp;
        while (ss_Temp >> n_Temp) {
            q_Path_Temp.push(n_Temp);
        }
        v_Route.push_back(q_Path_Temp);
    }
}

道路类型的设置

it->m_CTrafficLight_Light.setType(it->JunctionRoad.size());

根据路口道路条数, 设置路灯类型(是T字路口还是+字路口)

/**
 * 交通灯类
 */
class TrafficLight {
public:
    TrafficLight() {
        for (int i = 0; i < 8; i++) {
            roadID[i] = -1;
        }

    };
    void changeStatus();

    void clock(int time);

    void setAllRed();

    void setAllGreen();

    bool getStatus(int from, int to);
    /**
     * 设置灯的类型, 是T字路口还是+字路口
     * @param type 
     */
    void setType(int type) { this->type = type; };
    //路口标号
    // nLeftIn,nLeftOut,nDownIn,nDownOut,nRightIn,nRightOut,nUpIn,nUpOut;
    int roadID[8];
    //路口是否能走通
    bool status[4][4] = {false};
    int type;
    //表示可通过的方向(目标方向)
    //AllRED = 0,LeftGreen = 1,DownGreen = 2,RightGreen = 3,UpGreen = 4,UpDownGreen = 5,LeftRightGreen = 6,cross1 = 7,cross2 = 8
    int emStatus = 0;
    long long int time = 0;
};

对接各路口

it->m_CTrafficLight_Light.roadID[4] = it->JunctionRoad[0].inID;
it->m_CTrafficLight_Light.roadID[5] = it->JunctionRoad[0].outID;

it->m_CTrafficLight_Light.roadID[0] = it->JunctionRoad[1].inID;
it->m_CTrafficLight_Light.roadID[1] = it->JunctionRoad[1].outID;
switch (it->JunctionRoad.size()) {
    case 4:
       it->m_CTrafficLight_Light.roadID[6] = it->JunctionRoad[3].inID;
       it->m_CTrafficLight_Light.roadID[7] = it->JunctionRoad[3].outID;
       //你是不是想说没有break?这里不需要break;
    case 3:
       it->m_CTrafficLight_Light.roadID[2] = it->JunctionRoad[2].inID;
       it->m_CTrafficLight_Light.roadID[3] = it->JunctionRoad[2].outID;
    }

交通灯初始化完毕.

2019-02-12 12-19-50屏幕截图.png

思路篇

思路篇主要记录程序流程思路

毕业设计思路篇(一)之道路数据的抽象

毕业设计思路篇(二)之交通灯的初始化

毕业设计思路篇(三)之预加载车辆路线

毕业设计思路篇(四)之生成车辆

毕业设计思路篇(五)之交通流量模拟

番外篇

番外篇主要记录非主要流程(即并非每次运行都会执行的模块,比如预处理等)。每个模块可单独修改或维护,而不影响主流程。

毕业设计番外篇(一)之车辆路径的构建

简单的python版本管理器: pyenv

pyenv可以让你轻松的在各版本的python环境中切换自如,它是一个简单而又不引人注目并遵循UNIX传统的专用工具。

这个项目是从rbenvruby-buildfork而来, 并且在配合Python的情况下做了适当的修改.

Terminal output example

pyenv能做什么?

  • 让你在用户基础上改变全局Python版本.
  • 支持为每一个项目设立一个Python版本.
  • 允许您使用环境变量覆盖Python版本.
  • 多个python环境中搜索命令,这有助于在Python版本中进行测试 tox.

与pythonbrew和pythonz相比,pyenv不能做什么?

  • 不依赖于Python本身。 pyenv是由纯shell脚本制作的。没有Python的引导问题。
  • 不需要加载到你的shell中。相反,pyenv的shim方法的工作原理是在$ PATH中添加一个目录。
  • 不能管理virtualenv 当然你可以自行创建virtualenv virtualenv或者使用pyenv-virtualenv去自动化构建

工作原理

在较高的层次上,pyenv使用shim拦截Python命令注入PATH的可执行文件, 确定哪个Python版本已由您的应用程序指定,并传递您的命令使用你想要的Python安装版本。

理解PATH(环境变量路径)

当你执行命令,如python或者pip, 你的操作系统会搜索目录列表以查找可执行文件的那个名字.此目录列表位于环境变量中称为PATH, 列表中的每个目录使用用冒号分隔.

PATH.png

PATH中的目录从左到右搜索,因此首先匹配在列表开头的目录中的可执行文件, 然后一次往右匹配。在这个例子中,首先搜索/usr/local/sbin目录,然后搜索/usr/local/bin,然后是/usr/sbin

理解Shims(垫片)

pyenv的工作原理是在你的PATH前面插入一个shims目录,这样一来系统在搜索Python的时候第一个找到的就是pyenv管理的Python环境。这个插到最前面的路径就叫做垫片(shims)

$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin

通过一个叫做为_rehashing_的进程, pyenv维护shims目录以匹配每个已安装版本的每个Python命令,比如pythonpip等。

垫片是轻量级可执行文件,只是简单地传递命令到pyenv。所以只要安装了pyenv,当你运行时,比如说,pip,你的操作系统将执行以下操作:

  • PATH中搜索名为pip的可执行文件
  • PATH的开头找到名为pip的pyenv垫片
  • 运行名为pip的垫片,然后将命令传递给属于pyenv的pip命令

选择Python版本

执行shims程序时,pyenv会确定要使用的Python版本,并按此以下资源顺序读取:

  1. PYENV_VERSION环境变量(如果指定). 你可以使用pyenv shell 去设置环境变量在你当前shell session.
  2. 当前特定于应用程序的.python-version文件目录(如果有). 您可以使用 pyenv local修改当前目录.python-version文件.
  3. 通过搜索每个上层目录,找到第一个.python-version文件(如果有的话),直到到达文件系统的根目录
  4. 全局$(pyenv root)/version文件. 您可以使用pyenv global 修改这个文件. 如果是该全局文件不存在,pyenv假设您要使用“系统”Python。(换句话说,如果pyenv不在您的PATH中,那么任何版本都会运行.)

NOTE: 您可以同时激活多个版本,甚至包括Python2或Python3的任何版本. 这允许平行使用Python2和Python3,并且需要像tox这样的工具. 例如,要设置你的首次使用的系统Python和Python3的路径(在这个例子中设置为2.7.9和3.4.2),但也可以在你的PATH使用Python 3.3.6,3.2和2.5,首先是pyenv install缺少的版本,然后设置pyenv全局3.3.6 3.2 2.5.这时, 使用pyenv which应该能够找到每个可执行路径, 例如pyenv which python2.5(应该显示$(pyenv root/versions/2.5 /bin/python2.5) 或者pyenv which python3.4(应该显示系统Python3路径). 您还可以指定多个.python-version`文件中的版本,由换行符或任何空格分隔。

定位Python的安装路径

一旦pyenv确定了您的应用程序具有哪个版本的Python, 它将命令传递给相应的Python.

每个Python版本都安装在自己的目录下
$(pyenv root)/versions.

例如,您可能安装了这些版本:

  • $(pyenv root)/versions/2.7.8/
  • $(pyenv root)/versions/3.4.2/
  • $(pyenv root)/versions/pypy-2.4.0/

就pyenv而言,版本名称只是其中的目录名

$(pyenv root)/versions.

管理虚拟环境

有一个叫做pyenv-virtualenv的pyenv插件, 它有很多功能,可帮助pyenv用户管理virtualenv或Anaconda创建的虚拟环境。因为那些虚拟环境的activate脚本依赖于改变shell的$ PATH变量,
它会去hook拦截pyenv的shim样式命令钩子.如果您有计划使用这些虚拟环境,我们建议您安装pyenv-virtualenv。


安装

如果您是macOS,推荐转至installing with Homebrew.

自动化安装器

访问以下项目:
https://github.com/pyenv/pyenv-installer

基于GitHub检出

这可以让你一直保持最新版本的pyenv, 并且fork上游分支的任何变化

  1. 在哪里检出.
    我们建议$HOME/.pyenv (但其实您可以安装在任何地方).

     $ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
    
    
  2. Define environment variable PYENV_ROOT to point to the path where
    pyenv repo is cloned and add $PYENV_ROOT/bin to your $PATH for access
    to the pyenv command-line utility.

    $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
    $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile

    Zsh note: Modify your ~/.zshenv file instead of ~/.bash_profile.
    Ubuntu and Fedora note: Modify your ~/.bashrc file instead of ~/.bash_profile.
    Proxy note: If you use a proxy, export http_proxy and HTTPS_PROXY too.

  3. Add pyenv init to your shell to enable shims and autocompletion.
    Please make sure eval "$(pyenv init -)" is placed toward the end of the shell
    configuration file since it manipulates PATH during the initialization.

    $ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bash_profile
    • Zsh note: Modify your ~/.zshenv file instead of ~/.bash_profile.
    • fish note: Use pyenv init - | source instead of eval (pyenv init -).
    • Ubuntu and Fedora note: Modify your ~/.bashrc file instead of ~/.bash_profile.

    General warning: There are some systems where the BASH_ENV variable is configured
    to point to .bashrc. On such systems you should almost certainly put the abovementioned line
    eval "$(pyenv init -)" into .bash_profile, and not into .bashrc. Otherwise you
    may observe strange behaviour, such as pyenv getting into an infinite loop.
    See #264 for details.

  4. Restart your shell so the path changes take effect.
    You can now begin using pyenv.

    $ exec "$SHELL"
  5. Install Python build dependencies before attempting to install a new Python version. The
    pyenv wiki provides suggested installation packages
    and commands for various operating systems.
  6. Install Python versions into $(pyenv root)/versions.
    For example, to download and install Python 2.7.8, run:

    $ pyenv install 2.7.8

    NOTE: If you need to pass configure option to build, please use
    CONFIGURE_OPTS environment variable.

    NOTE: If you want to use proxy to download, please use http_proxy and https_proxy
    environment variable.

    NOTE: If you are having trouble installing a python version,
    please visit the wiki page about
    Common Build Problems

Upgrading

If you've installed pyenv using the instructions above, you can
upgrade your installation at any time using git.

To upgrade to the latest development version of pyenv, use git pull:

$ cd $(pyenv root)
$ git pull

To upgrade to a specific release of pyenv, check out the corresponding tag:

$ cd $(pyenv root)
$ git fetch
$ git tag
v0.1.0
$ git checkout v0.1.0

Uninstalling pyenv

The simplicity of pyenv makes it easy to temporarily disable it, or
uninstall from the system.

  1. To disable pyenv managing your Python versions, simply remove the
    pyenv init line from your shell startup configuration. This will
    remove pyenv shims directory from PATH, and future invocations like
    python will execute the system Python version, as before pyenv.

    pyenv will still be accessible on the command line, but your Python
    apps won't be affected by version switching.

  2. To completely uninstall pyenv, perform step (1) and then remove
    its root directory. This will delete all Python versions that were
    installed under $(pyenv root)/versions/ directory:

    rm -rf $(pyenv root)

    If you've installed pyenv using a package manager, as a final step
    perform the pyenv package removal. For instance, for Homebrew:

      brew uninstall pyenv
    

Homebrew on macOS

You can also install pyenv using the Homebrew
package manager for macOS.

$ brew update
$ brew install pyenv

To upgrade pyenv in the future, use upgrade instead of install.

Then follow the rest of the post-installation steps under Basic GitHub Checkout above, starting with #3 ("Add pyenv init to your shell to enable shims and autocompletion").

Advanced Configuration

Skip this section unless you must know what every line in your shell
profile is doing.

pyenv init is the only command that crosses the line of loading
extra commands into your shell. Coming from rvm, some of you might be
opposed to this idea. Here's what pyenv init actually does:

  1. Sets up your shims path. This is the only requirement for pyenv to
    function properly. You can do this by hand by prepending
    $(pyenv root)/shims to your $PATH.
  2. Installs autocompletion. This is entirely optional but pretty
    useful. Sourcing $(pyenv root)/completions/pyenv.bash will set that
    up. There is also a $(pyenv root)/completions/pyenv.zsh for Zsh
    users.
  3. Rehashes shims. From time to time you'll need to rebuild your
    shim files. Doing this on init makes sure everything is up to
    date. You can always run pyenv rehash manually.
  4. Installs the sh dispatcher. This bit is also optional, but allows
    pyenv and plugins to change variables in your current shell, making
    commands like pyenv shell possible. The sh dispatcher doesn't do
    anything crazy like override cd or hack your shell prompt, but if
    for some reason you need pyenv to be a real script rather than a
    shell function, you can safely skip it.

To see exactly what happens under the hood for yourself, run pyenv init -.

Uninstalling Python Versions

As time goes on, you will accumulate Python versions in your
$(pyenv root)/versions directory.

To remove old Python versions, pyenv uninstall command to automate
the removal process.

Alternatively, simply rm -rf the directory of the version you want
to remove. You can find the directory of a particular Python version
with the pyenv prefix command, e.g. pyenv prefix 2.6.8.


Command Reference

See COMMANDS.md.


Environment variables

You can affect how pyenv operates with the following settings:

namedefaultdescription
PYENV_VERSION Specifies the Python version to be used.
Also see pyenv shell
PYENV_ROOT~/.pyenvDefines the directory under which Python versions and shims reside.
Also see pyenv root
PYENV_DEBUG Outputs debug information.
Also as: pyenv --debug <subcommand>
PYENV_HOOK_PATHsee wikiColon-separated list of paths searched for pyenv hooks.
PYENV_DIR$PWDDirectory to start searching for .python-version files.
PYTHON_BUILD_ARIA2_OPTS Used to pass additional parameters to aria2.
if aria2c binary is available on PATH, pyenv use aria2c instead of curl or wget to download the Python Source code. If you have an unstable internet connection, you can use this variable to instruct aria2 to accelerate the download.
In most cases, you will only need to use -x 10 -k 1M as value to PYTHON_BUILD_ARIA2_OPTS environment variable

Development

The pyenv source code is [hosted on
GitHub](https://github.com/pyenv/pyenv). It's clean, modular,
and easy to understand, even if you're not a shell hacker.

Tests are executed using Bats:

$ bats test
$ bats/test/<file>.bats

Please feel free to submit pull requests and file bugs on the [issue
tracker](https://github.com/pyenv/pyenv/issues).

Version History

See CHANGELOG.md.

License

The MIT License

2019-01-13 10-50-54屏幕截图.png

1. 导入道路地图

道路地图来自网络数据,已预处理为xml格式。

<?xml version='1.0' encoding='UTF-8'?>
<Roads>
  <road m_ID="71283896--1" len="620.98">
    <from lon="113.9205606" lat="22.9317667" id="848388981"/>
    <to lon="113.9260573" lat="22.9341232" id="2522072722"/>
  </road>
  <road m_ID="553852656--2" len="322.34">
    <from lon="113.9529339" lat="22.9448978" id="5345735265"/>
    <to lon="113.9516926" lat="22.9475618" id="5345735267"/>
  </road>
</Roads>
解析:一个road节点代表一条道路,len代表道路抽象长度,from,to子节点分别表示道路两端端点。

2. 解析道路数据

a. 构建交通图

赋值道路端点.
/**
*  路口类,记录着该路口的点坐标,以及其相连的方向道路节点组
 *               |           |
 *               |     |     |
 *               |  1     2  |
 *               |     |     |
 *        --------           --------
 *           3                  5
 *        - - - -            - - - -
 *           4                  6
 *        --------           --------
 *               |     |     |
 *               |  7     8  |
 *               |     |     |
 *               |           |
 *    如上图(1,2), (3,4), (5,6), (7,8)在同一个方向,我将其称为四组方向道路节点Node.
 *    其中,Node.inRoadID=1, Node.outRoadID=2;
 *         Node.inRoadID=4, Node.outRoadID=3;
 *         ...
 *         根据车辆靠右行原则以此类推.
*/
class CrossRoad {
public:
    CrossRoad(float fLon,float fLat) : m_fLat(fLat),m_fLon(fLon){};
    /**
     * 重载运算符 (==) 判断两个路口是否为同一个
     */
    bool operator==(CrossRoad &crossRoad);
    /**
     * 添加道路节点ID
     * @param in 入度
     * @param out 出度
     * @param atan2 该点与方向道路的atan2值
     */
    void addNode(int in,int out,double atan2);
public:
    //唯一标示符
    int m_nID;
    //经纬度的定义
    float m_fLon, m_fLat;
    vector<Node> JunctionRoad;
    //该路口的交通灯
    TrafficLight m_CTrafficLight_Light;
};

CrossRoad A,B

添加道路到交通图
void addRoad(Graph &Map_Graph, CrossRoad A, CrossRoad B, double length) {
    // 初始化A,B路口的索引位置为-1
    int CrossRoadSiteB = -1, CrossRoadSiteA = -1;
    auto CrossRoadNum = Map_Graph.m_CrossRoad_v.size(), RoadNum = Map_Graph.m_Road_v.size();
    //循环判断是否有重合点
    for (int i = 0; i < CrossRoadNum; i++) {
        if (Map_Graph.m_CrossRoad_v[i] == A) {
            CrossRoadSiteA = i;
        }
        if (Map_Graph.m_CrossRoad_v[i] == B) {
            CrossRoadSiteB = i;
        }
    }
    //如果不存在与A点重合的路口,添加路口,保存路口索引
    if (CrossRoadSiteA == -1) {
        Map_Graph.m_CrossRoad_v.push_back(A);
        CrossRoadSiteA = CrossRoadNum++;
        Map_Graph.m_CrossRoad_v[CrossRoadSiteA].m_nID = CrossRoadSiteA;
    }
    if (CrossRoadSiteB == -1) {
        Map_Graph.m_CrossRoad_v.push_back(B);
        CrossRoadSiteB = CrossRoadNum++;
        Map_Graph.m_CrossRoad_v[CrossRoadSiteB].m_nID = CrossRoadSiteB;
    }
    int RoadSiteA = RoadNum, RoadSiteB = RoadNum + 1;
    // 确定A,B路的site,加入模型图
    Road roadA(RoadSiteA, CrossRoadSiteA, CrossRoadSiteB, length);
    Map_Graph.m_Road_v.push_back(roadA);
    Road roadB(RoadSiteB, CrossRoadSiteB, CrossRoadSiteA, length);
    Map_Graph.m_Road_v.push_back(roadB);
    // 对接A,B路口节点数据
    Map_Graph.m_CrossRoad_v[CrossRoadSiteA].addNode(RoadSiteA, RoadSiteB,
                                                    atan2((B.m_fLat - A.m_fLat), (B.m_fLon - A.m_fLon)));
    Map_Graph.m_CrossRoad_v[CrossRoadSiteB].addNode(RoadSiteB, RoadSiteA,atan2((A.m_fLat - B.m_fLat), (A.m_fLon - B.m_fLon)));
}
解析的结果如下
road.txt
RoadTable.txt

遇到的一些问题

Imageio: 'ffmpeg-linux64-v3.3.1' was not found on your computer; downloading it now.

解决办法:
sudo add-apt-repository -y ppa:djcj/hybrid && sudo apt update && sudo apt install -y ffmpeg
我直接运行了,然后它自动下载安装了。