using ExportMap.db;
using ExportMap.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
namespace ExportMap.cs
{
public class TerrainUtils
{
private static int terrainMaxLevel = 0;
private const string EPSG4326 = "EPSG:4326";
///
/// 地形最大级别
///
public static int TERRAIN_MAX_LEVEL
{
get
{
if (0 == terrainMaxLevel)
{
string str = Tools.GetSetting("terrainMaxLevel");
if (!int.TryParse(str, out terrainMaxLevel))
{
terrainMaxLevel = 14;
}
}
return terrainMaxLevel;
}
}
///
/// 默认最大文件大小:5GB
///
public static long DEFAULT_MAX_SIZE = 5L * 1024 * 1024 * 1024;
///
/// 获取发布地址
///
public static string GetReleaseUrl(string dircode)
{
return "http://{host}/LFData/3d/terrain/" + dircode;
}
///
/// 获取地形路径
///
public static string GetTerrainPath(string dircode)
{
return Path.Combine(SGUtils.LFData, "3d\\terrain", dircode);
}
///
/// 生成
///
/// XYZ参数
/// 错误信息
/// 数据发布ID集合
public static List Generate(XYZArgs args, ref string err)
{
try
{
List metas = XYZUtils.SelectMetas(args.ids, "and type in ('tif', 'tiff', 'dem')");
if (null == metas || metas.Count == 0) return PrintInfo("找不到元数据");
string dirPath = GetTerrainPath(args.dircode);
//if (Directory.Exists(dirPath)) Tools.DelPath(dirPath); // 已存在的,删除
if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
string subPath = Path.Combine(dirPath, "subs");
if (!Directory.Exists(subPath)) Directory.CreateDirectory(subPath);
int pubid = PubDBHelper.GetPushlishId(args.dircode, "DEM");
List metsIds = PubDBHelper.GetPublishMetaId(pubid);
List files = new List();
string uploadFolder = Tools.GetSetting("uploadFolder");
foreach (SysMeta meta in metas)
{
if (metsIds.Contains(meta.id))
{
PrintInfo("元数据[" + meta.id + "] 已发布。");
continue;
}
string sourceFile = Path.Combine(uploadFolder, meta.path);
if (!File.Exists(sourceFile))
{
PrintInfo("元数据[" + meta.id + "] 不存在。");
continue;
}
string targetFile = Path.Combine(subPath, meta.path.Split(new string[] { "\\", "//" }, StringSplitOptions.None)[1]);
ConvertRaster(sourceFile, targetFile);
if (File.Exists(targetFile))
{
files.Add(targetFile);
CreateTerrain(args, targetFile, ref err);
}
}
CreateLayerJson(args, files, ref err);
string json = Path.Combine(dirPath, "layer.json");
if (!File.Exists(json)) return PrintInfo("找不到layer.json文件");
Complement(args);
pubid = InsertToDB(metas, args);
return new List { pubid };
}
catch (Exception ex)
{
LogOut.Error(ex.Message + "\r\n" + ex.StackTrace);
err = ex.Message;
return null;
}
}
///
/// 打印信息
///
private static List PrintInfo(string info)
{
LogOut.Info("TerrainUtils:" + info);
return null;
}
///
/// 转换栅格文件
///
private static void ConvertRaster(string sourceFile, string targetFile)
{
if (File.Exists(targetFile)) return;
string epsg = Tools.GetEPSG(sourceFile);
if (epsg == EPSG4326)
{
File.Copy(sourceFile, targetFile);
return;
}
Reproject(sourceFile, targetFile, epsg, EPSG4326);
}
///
/// 创建高程切片
///
private static void CreateTerrain(XYZArgs args, string tifFile, ref string err)
{
string ctbPath = Tools.GetSetting("ctbJL");
string dirPath = GetTerrainPath(args.dircode);
//int maxLevel = GetTerrainMaxLevel(args, tifFile);
string gdal_data = string.Format("set GDAL_DATA={0}\\data", ctbPath);
// -N 顶点法线, -C 强制创建缺失根瓦片, -R 不覆盖现有文件,-f Mesh
string createMesh = string.Format("{0}\\ctb-tile.exe -s {1} -o \"{2}\" \"{3}\"", ctbPath, TERRAIN_MAX_LEVEL, dirPath, tifFile);
List list = new List() { gdal_data, createMesh };
SysTask task = TaskDBHelper.CreateTask(args, "DEM", "高程数据(DEM)");
err = Tools.ExecCmd(task, list);
}
///
/// 创建layer.json
///
private static string CreateLayerJson(XYZArgs args, List files, ref string err)
{
string dirPath = GetTerrainPath(args.dircode);
string vrt = Path.Combine(dirPath, "subs", "dem.vrt");
CreateVrt(files, vrt);
if (!File.Exists(vrt)) return null;
string ctbPath = Tools.GetSetting("ctbJL");
string gdal_data = string.Format("set GDAL_DATA={0}\\data", ctbPath);
string createLayer = string.Format("{0}\\ctb-tile.exe -l -s {1} -o \"{2}\" \"{3}\"", ctbPath, TERRAIN_MAX_LEVEL, dirPath, vrt);
Tools.ExecCmd(new List() { gdal_data, createLayer });
return vrt;
}
///
/// 创建VRT
///
private static void CreateVrt(List files, string vrt)
{
string str = string.Join("\r\n", files);
string filelist = vrt.Replace("dem.vrt", "list.txt");
File.WriteAllText(filelist, str);
string gdalPath = Tools.GetSetting("gdalPath");
string cmd = string.Format("\"{0}\\gdalbuildvrt.exe\" -input_file_list \"{1}\" \"{2}\" -overwrite", gdalPath, filelist, vrt);
Tools.ExecCmd(new List { cmd });
}
///
/// 获取地形最大级别
///
private static int GetTerrainMaxLevel(XYZArgs args, string tifFile)
{
FileInfo fi = new FileInfo(tifFile);
if (fi.Length > DEFAULT_MAX_SIZE) return TERRAIN_MAX_LEVEL;
string ctbPath = Tools.GetSetting("ctbJL");
string dirPath = GetTerrainPath(args.dircode);
string subPath = Path.Combine(dirPath, "subs");
string gdal_data = string.Format("set GDAL_DATA={0}\\data", ctbPath);
string createLayer = string.Format("{0}\\ctb-tile.exe -l -o \"{1}\" \"{2}\"", ctbPath, subPath, tifFile);
Tools.ExecCmd(new List() { gdal_data, createLayer });
string layerJson = Path.Combine(subPath, "layer.json");
if (!File.Exists(layerJson)) return TERRAIN_MAX_LEVEL;
string[] lines = File.ReadAllLines(layerJson, Encoding.UTF8);
int level = -1;
foreach (string line in lines)
{
if (line.IndexOf("startX") > -1) level++;
}
if (File.Exists(layerJson)) File.Delete(layerJson);
return level > TERRAIN_MAX_LEVEL ? TERRAIN_MAX_LEVEL : level;
}
///
/// 补充文件
///
private static void Complement(XYZArgs args)
{
string dirPath = GetTerrainPath(args.dircode);
string p_0_0 = Path.Combine(dirPath, "0", "0");
if (!Directory.Exists(p_0_0)) Directory.CreateDirectory(p_0_0);
string p_0_1 = Path.Combine(dirPath, "0", "1");
if (!Directory.Exists(p_0_1)) Directory.CreateDirectory(p_0_1);
string s_0_0_0 = Path.Combine(SGUtils.LFData, "dem", "0", "0", "0.terrain");
string d_0_0_0 = Path.Combine(dirPath, "0", "0", "0.terrain");
if (!File.Exists(d_0_0_0)) File.Copy(s_0_0_0, d_0_0_0, true);
string s_0_1_0 = Path.Combine(SGUtils.LFData, "dem", "0", "1", "0.terrain");
string d_0_1_0 = Path.Combine(dirPath, "0", "1", "0.terrain");
if (!File.Exists(d_0_1_0)) File.Copy(s_0_1_0, d_0_1_0, true);
string layerJson = Path.Combine(dirPath, "layer.json");
string[] lines = File.ReadAllLines(layerJson, Encoding.UTF8);
//lines[12] = " [ { \"startX\": 0, \"startY\": 0, \"endX\": 1, \"endY\": 0 } ]";
for (int i = 0, c = lines.Length; i < c; i++)
{
if (lines[i].IndexOf("startX") > -1)
{
lines[i] = " [ { \"startX\": 0, \"startY\": 0, \"endX\": 1, \"endY\": 0 } ]";
break;
}
}
File.WriteAllLines(layerJson, lines, Encoding.UTF8);
}
///
/// 插入数据库
///
private static int InsertToDB(List metas, XYZArgs args)
{
//if (PubDBHelper.IsPublish(args.dircode, "DEM")) return 1;
int pubid = PubDBHelper.GetPushlishId(args.dircode, "DEM");
if (pubid > 0) // 更新发布
{
List ids = PubDBHelper.GetPublishMetaId(pubid);
foreach (SysMeta m in metas)
{
if (!ids.Contains(m.id)) PubDBHelper.InsertMetaPub(m.id, pubid, args.userId);
}
string geom = GetPointZ(args);
int rows = PubDBHelper.UpdatePublish(pubid, args.name, args.userId, geom);
return pubid;
}
SysMeta meta = metas[0];
meta.type = "DEM";
meta.name = args.name;
meta.dircode = args.dircode;
SysPublish sys = Tools.NewPublish(meta, args, GetReleaseUrl(args.dircode), "3d\\terrain\\" + args.dircode);
sys.geom = GetPointZ(args);
pubid = PubDBHelper.InsertPublish(sys);
if (pubid > 0)
{
sys.id = pubid;
PubDBHelper.InsertLayer(sys, new SysMeta()
{
name = args.name,
type = meta.type,
dirname = meta.dirname
});
foreach (SysMeta m in metas)
{
PubDBHelper.InsertMetaPub(m.id, pubid, args.userId);
}
}
return pubid;
}
///
/// 获取中心点
///
public static string GetPointZ(XYZArgs args)
{
string dirPath = GetTerrainPath(args.dircode);
string vrt = Path.Combine(dirPath, "subs", "dem.vrt");
if (!File.Exists(vrt)) return null;
string gdalPath = Tools.GetSetting("gdalPath");
string cmd = string.Format("\"{0}\\gdalinfo.exe\" \"{1}\"", gdalPath, vrt);
string rs = null;
Tools.ExecCmd(new List { cmd }, ref rs);
string center = GetCenter(rs);
if (string.IsNullOrEmpty(rs)) return null;
string[] strs = center.Split(new string[] { "," }, StringSplitOptions.None);
double x = double.Parse(strs[0]);
double y = double.Parse(strs[1]);
return string.Format("ST_GeomFromText('POINT Z ({0} {1} {2})')", x, y, 12);
}
///
/// 获取中心坐标
///
private static string GetCenter(string rs)
{
if (string.IsNullOrEmpty(rs)) return null;
string[] strs = rs.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string str in strs)
{
if (str.StartsWith("Center "))
{
int start = str.IndexOf("(");
int end = str.IndexOf(")");
return str.Substring(start + 1, end - start - 1).Replace(" ", "");
}
}
return null;
}
///
/// 重投影
///
public static void Reproject(string sourceFile, string targetFile, string sourceSrs, string targetSrs)
{
string gdalPath = Tools.GetSetting("gdalPath");
string cmd = string.Format("\"{0}\\gdalwarp.exe\" -s_srs {1} -t_srs {2} -r near -of GTiff \"{3}\" \"{4}\"", gdalPath, sourceSrs, targetSrs, sourceFile, targetFile);
Tools.ExecCmd(new List { cmd });
}
///
/// 指定投影 *
///
public static void Project(string sourceFile, string targetSrs)
{
List list = new List();
list.Add("cd \"C:\\Program Files\\QGIS 3.16\\apps\\Python37\"");
//list.Add("set GDAL_DATA=\"C:\\Program Files\\QGIS 3.16\\share\\gdal\"");
//list.Add("set PROJ_LIB=\"C:\\Program Files\\QGIS 3.16\\share\\proj\"");
list.Add("\"C:\\Program Files\\QGIS 3.16\\bin\\qgis_process-qgis-ltr.bat\"");
string cmd = string.Format("python \"C:\\Program Files\\QGIS 3.16\\apps\\Python37\\Scripts\\gdal_edit.py\" -a_srs {0} {1}", targetSrs, sourceFile);
list.Add(cmd);
string rs = "";
string err = Tools.ExecCmd(new List { cmd }, ref rs);
}
}
}