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

struct LevelArray { unsigned int ID = 0; TArray<FVector2D_Double> Array; };
其中我重載了一些運算符,便於后面需要的計算,現在我們已經有了儲存數據的結構,現在就需要讀取txt里面的數據,我使用的是C++原生庫里面的讀取方法:

#include <iostream> #include <fstream> #include <cassert> #include <string>

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(); }
這樣我們就可以把數據存儲在結構體LevelBaiData和BaiduDataTimeAndDistance里面。
我還創建了一個函數,用於把經緯度坐標轉化為平面坐標,我使用的是米勒投影轉換:
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)); }
UpDataLevelArrayData函數用於數據均勻分段,不會出現過多或者過少的拐點,這個算法不是當堂重點,當然你們需要參考可以在后面我貼出的源碼里查看。
數據我們可以讀取並且可在UE4中使用,但是如果我們需要在UE4中輸入經緯度,然后C++調用python函數,獲取的函數在UE4中顯示出來,那就在下一節我講解一下。