UE4根据真实地图来生成行走道路(二)

风格不统一 提交于 2019-11-30 07:54:07

上一节我们完成了数据的基础获取,现在我们需要在UE4中新建一个空白插件类,然后把上一节python文件和txt文件放在该插件类里的Content文件夹里面(作用是让UE4只需要读取相对位置就行,便于打包和其他项目使用)。

创建好C++插件工程后,我们需要创建一个函数用于读取txt里面的数据,我们可以看到txt生成的数据是double型,UE4的FVector2D位置坐标结构体是float型,所以我们需要创建一个结构体储存数据里面的double型数据,而且我们在每个拐弯处都分了段,所以创建了一个简单的结构体,用于储存每段结构的数据:

struct FVector2D_Double
{
    double X;
    double Y;

    FVector2D_Double operator-(const FVector2D_Double& Other) const
    {
        return FVector2D_Double(X - Other.X, Y - Other.Y);
    }

    FVector2D_Double operator+(const FVector2D_Double& Other) const
    {
        return FVector2D_Double(X + Other.X, Y + Other.Y);
    }

    FVector2D_Double operator/(const FVector2D_Double& Other) const
    {
        return FVector2D_Double(X * Other.X, Y * Other.Y);
    }

    FVector2D_Double operator*(const float& Other) const
    {
        return FVector2D_Double(X * Other, Y * Other);
    }

    FVector2D_Double operator/(const float& Other) const
    {
        return FVector2D_Double(X / Other, Y / Other);
    }

    FVector2D_Double operator/(const FVector2D& Other) const
    {
        return FVector2D_Double(X / Other.X, Y / Other.Y);
    }

    FVector2D_Double operator*(const FVector2D& Other) const
    {
        return FVector2D_Double(X * Other.X, Y * Other.Y);
    }

    FVector2D_Double()
        :X(0.f), Y(0.f)
    {}

    FVector2D_Double(double X,double Y)
        :X(X),Y(Y)
    {}

    double Size() const
    {
        return sqrt(X * X + Y * Y);
    }
};
.h
struct LevelArray
{
    unsigned int ID = 0;
    TArray<FVector2D_Double> Array;
};
.h

其中我重载了一些运算符,便于后面需要的计算,现在我们已经有了储存数据的结构,现在就需要读取txt里面的数据,我使用的是C++原生库里面的读取方法:

#include <iostream>
#include <fstream>
#include <cassert>
#include <string>
.h
TArray<LevelArray> LevelBaiData;
TArray<int> BaiduDataTimeAndDistance;
std::string file = TCHAR_TO_UTF8(*FPaths::ProjectPluginsDir()) + std::string("XXXXPlugins/Content/walking.txt");
    
    std::ifstream infile;
    infile.open(file.data());   //将文件流对象与文件连接起来 

    unsigned int AID = 0;

    if (infile.is_open())
    {

        std::string s;
        while (getline(infile, s))
        {
            std::string s1, s2, s3;
            
            std::size_t pos = s.find(",");
            if (s._Equal("------"))
            {
                LevelArray A;
                AID += 1;
                A.ID = AID;
                LevelBaiData.Add(A);
            }
            if (pos != std::string::npos)
            {
                s1 = s.substr(0, pos);
                s2 = s.substr(pos + 1, s.size());

                FVector2D_Double v2lf = FVector2D_Double(atof(s1.c_str()), atof(s2.c_str()));
                
                FVector2D_Double A = IBToXY(v2lf); // 把经纬度转化为平面坐标
                
                LevelBaiData[LevelBaiData.Num() - 1].Array.Add(A);
            }
            std::size_t pos_1 = s.find(":");
            if (pos_1 != std::string::npos)
            {
                s3 = s.substr(pos_1 + 1, s.size());
                BaiduDataTimeAndDistance.Add(atoi(s3.c_str()));
            }
        }
        infile.close();
    }
.cpp

这样我们就可以把数据存储在结构体LevelBaiDataBaiduDataTimeAndDistance里面。

我还创建了一个函数,用于把经纬度坐标转化为平面坐标,我使用的是米勒投影转换:

FVector2D_Double MyClass::IBToXY(FVector2D_Double IB)
{

    double L = 6378000 * PI * 2;//地球周长
    double W = L;// 平面展开后,x轴等于周长 
    double H = L / 2;// y轴约等于周长一半  
    double Mill = 2.3;// 米勒投影中的一个常数,范围大约在正负2.3之间  
    double x = IB.X * PI / 180;// 将经度从度数转换为弧度  
    double y = IB.Y * PI / 180;// 将纬度从度数转换为弧度  
    
    y = 1.25 * log(tan(0.25 * PI + 0.4 * y));// 米勒投影的转换 

    // 弧度转为实际距离  
    x = (W / 2) + (W / (2 * PI)) * x;
    y = (H / 2) - (H / (2 * Mill)) * y;

    return FVector2D_Double(x,y);
}

现在我们已经取得地球上的坐标数据,然后把该数据转化为UE4里的的float型数据,我们只需要知道UE4中起点位置,和缩放比例就可以实现该效果,起点位置好找,直接可以用Actor世界位置,可是缩放比例就有点难,我们可以知道UE4终点终点位置求得,也可以知道UE4地图比例就得,我使用的是获取另一个点的终点位置求得:

FVector Delate = EndActor - StartActor;
BaiduDataXY = UpDataLevelArrayData(LevelBaiData, Number, IsIgnoreSamllLen, Number <= 0);

    FVector2D_Double StartEndVector2D = (BaiduDataXY[BaiduDataXY.Num() - 1] - BaiduDataXY[0]); //米勒投影坐标向量

    double Scale = StartEndVector2D.Size() / FVector2D(Delate.X, Delate.Y).Size();
    
    for (auto &Item : BaiduDataXY)
    {
        FVector2D_Double p = (Item - BaiduDataXY[0]) / Scale;
        /*
        p.X = DistanceLngLat(BaiduData[0].X, Item.X, BaiduData[0].Y, BaiduData[0].Y) / Scale;
        p.Y = DistanceLngLat(BaiduData[0].X, BaiduData[0].X, BaiduData[0].Y, Item.Y) / Scale;
        */
        UE4Data.Add(FVector2D(p.X, p.Y));
        
    }
.cpp

UpDataLevelArrayData函数用于数据均匀分段,不会出现过多或者过少的拐点,这个算法不是当堂重点,当然你们需要参考可以在后面我贴出的源码里查看。

数据我们可以读取并且可在UE4中使用,但是如果我们需要在UE4中输入经纬度,然后C++调用python函数,获取的函数在UE4中显示出来,那就在下一节我讲解一下。

项目插件源码:https://github.com/a948022284/UE4RealRoadPlanning

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!