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.name); 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); 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); } } }