UE4根據真實地圖來生成行走道路(二)


上一節我們完成了數據的基礎獲取,現在我們需要在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/Monocluar/UE4RealRoadPlanning


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM