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 TerraUtils { private static string pyFile; private static int terrainMaxLevel = 0; /// /// 地形最大级别 /// 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; /// /// 获取Python文件 /// public static string PyFile { get { if (string.IsNullOrWhiteSpace(pyFile)) { pyFile = Path.Combine(ExportUtil.SourcesPath, "merge.py"); } return pyFile; } } /// /// QGIS工程 /// public static string Qgz { get { //return Path.Combine(ExportUtil.SourcesPath, "xyz.qgz"); return "xyz.qgz"; } } /// /// bat路径 /// public static string BatPath { get { return @"C:\Program Files\QGIS 3.16\bin\"; } } /// /// 基础bat文件 /// public static string BaseBat { get { // python-qgis-ltr.bat,qgis_process-qgis-ltr.bat return @"C:\Program Files\QGIS 3.16\bin\qgis_process-qgis-ltr.bat"; } } /// /// 获取发布地址 /// public static string GetReleaseUrl(string dircode) { return "{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) { string tifFile = null; try { List metas = XYZUtils.SelectMetas(args.ids, "and type in ('tif', 'tiff')"); if (null == metas || metas.Count == 0) { LogOut.Info("TerraUtils:找不到元数据。"); return null; } string dirPath = GetTerrainPath(args.dircode); //if (Directory.Exists(dirPath)) Tools.DelPath(dirPath); // 已存在的,删除 tifFile = Merge(metas, args, ref err); if (!File.Exists(tifFile)) { LogOut.Info("TerraUtils:找不到tifFile数据。"); return null; } string json = Path.Combine(dirPath, "layer.json"); if (File.Exists(json)) File.Delete(json); //Generate(args, tifFile, ref err); CreateTerrain(args, tifFile, ref err); if (!File.Exists(json)) { LogOut.Info("TerraUtils:找不到layer.json文件。"); return null; } Complement(args); List ids = new List(); int pubid = InsertToDB(metas, args); if (pubid > 0) ids.Add(pubid); return ids; } catch (Exception ex) { LogOut.Error(ex.Message + "\r\n" + ex.StackTrace); err = ex.Message; return null; } /*finally { if (!string.IsNullOrEmpty(tifFile) && File.Exists(tifFile)) File.Delete(tifFile); }*/ } /// /// 合并 /// public static string Merge(List metas, XYZArgs args, ref string err) { string txtFile = null; try { string dirPath = GetTerrainPath(args.dircode); if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath); txtFile = Path.Combine(Tools.TempDir, ExportUtil.DateStr + ".txt"); string tifFile = Path.Combine(dirPath, args.dircode + ".tif"); int pubid = PubDBHelper.GetPushlishId(args.dircode, "DEM"); if (pubid > 0 && File.Exists(tifFile)) { List ids = PubDBHelper.GetPublishMetaId(pubid); List news = new List(); foreach (SysMeta m in metas) { if (!ids.Contains(m.id)) news.Add(m); } if (0 == news.Count) return tifFile; string oldTif = Path.Combine(dirPath, args.dircode + "_old.tif"); if (File.Exists(oldTif)) File.Delete(oldTif); File.Move(tifFile, oldTif); WriteText(txtFile, news, oldTif); } else { //if (File.Exists(tifFile)) File.Delete(tifFile); WriteText(txtFile, metas, null); if (File.Exists(tifFile)) return tifFile; } string cmd = string.Format("python \"{0}\" -qgz {1} -file \"{2}\" -out \"{3}\"", PyFile, Qgz, txtFile, tifFile); SysTask task = TaskDBHelper.CreateTask(args, "DEM", "高程镶嵌(DEM)"); err = Tools.ExecCmd(task, cmd, true); task = TaskDBHelper.SelectById(task.id); if (null == task || task.status != 2) LogOut.Info("TerraUtils:任务为空或状态不为2。"); return tifFile; } catch (Exception ex) { LogOut.Error(ex.Message + "\r\n" + ex.StackTrace); err = ex.Message; return null; } finally { if (!string.IsNullOrEmpty(txtFile) && File.Exists(txtFile)) File.Delete(txtFile); string dirPath = GetTerrainPath(args.dircode); string tifFile = Path.Combine(dirPath, args.dircode + ".tif"); string oldTif = Path.Combine(dirPath, args.dircode + "_old.tif"); if (File.Exists(tifFile) && File.Exists(oldTif)) File.Delete(oldTif); } } /// /// 写文本文件 /// private static void WriteText(string txtFile, List list, string tif) { string uploadFolder = Tools.GetSetting("uploadFolder"); List files = new List(); if (!string.IsNullOrEmpty(tif)) files.Add(tif); foreach (SysMeta meta in list) { string filePath = Path.Combine(uploadFolder, meta.path); if (File.Exists(filePath)) files.Add(filePath); } string str = string.Join("\r\n", files); File.WriteAllText(txtFile, str); } /// /// 获取地形最大级别 /// 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("ctbPath"); string dirPath = GetTerrainPath(args.dircode); string gdal_data = string.Format("set GDAL_DATA={0}\\data", ctbPath); string createLayer = string.Format("{0}\\ctb-tile.exe -l -o \"{1}\" -f Mesh \"{2}\\{3}.tif\"", ctbPath, dirPath, dirPath, args.dircode); Tools.ExecCmd(new List() { gdal_data, createLayer }); string layerJson = Path.Combine(dirPath, "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 CreateTerrain(XYZArgs args, string tifFile, ref string err) { string ctbPath = Tools.GetSetting("ctbPath"); string dirPath = GetTerrainPath(args.dircode); int maxLevel = GetTerrainMaxLevel(args, tifFile); string gdal_data = string.Format("set GDAL_DATA={0}\\data", ctbPath); // -N 顶点法线, -C 强制创建缺失根瓦片, -R 不覆盖现有文件 string createMesh = string.Format("{0}\\ctb-tile.exe -R -C -s {4} -o \"{1}\" -f Mesh \"{2}\\{3}.tif\"", ctbPath, dirPath, dirPath, args.dircode, maxLevel); string createLayer = string.Format("{0}\\ctb-tile.exe -l -s {4} -o \"{1}\" -f Mesh \"{2}\\{3}.tif\"", ctbPath, dirPath, dirPath, args.dircode, maxLevel); List list = new List() { gdal_data, createMesh, createLayer }; SysTask task = TaskDBHelper.CreateTask(args, "DEM", "高程数据(DEM)"); err = Tools.ExecCmd(task, list); } /// /// 补充文件 /// 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; } /// /// 获取中心点 /// private static string GetPointZ(XYZArgs args) { string dirPath = GetTerrainPath(args.dircode); string txtFile = Path.Combine(dirPath, args.dircode + "_cs.txt"); if (!File.Exists(txtFile)) return null; string[] strs = File.ReadAllLines(txtFile, Encoding.UTF8); // File.Delete(txtFile); // 删除坐标文件 if (null == strs || strs.Length == 0) return null; string[] str = strs[0].Split(new string[] { ", " }, StringSplitOptions.None); int i = 18; for (; i > -1; i--) { string path = Path.Combine(dirPath, i.ToString()); if (Directory.Exists(path)) { break; } } return string.Format("ST_GeomFromText('POINT Z ({0} {1} {2})')", str[1], str[0], i); } /*/// /// 生成高程切片 * /// private static void Generate(XYZArgs args, string tifFile, ref string err) { string dirPath = GetTerrainPath(args.dircode).Replace("\\", "/"); string name = "ctb_" + ExportUtil.DateStr; string runDocker = string.Format("docker run -id --name {0} -v \"{1}\":\"/data\" tumgis/ctb-quantized-mesh", name, dirPath); string createMesh = string.Format("docker exec {0} ctb-tile -f Mesh -C -N -s {1} -e {2} -o /data /data/{3}.tif", name, args.max, args.min, args.dircode); // Mesh, Terrain string createLayer = string.Format("docker exec {0} ctb-tile -f Mesh -C -N -s {1} -e {2} -l -o /data /data/{3}.tif", name, args.max, args.min, args.dircode); // Mesh, Terrain string stop = string.Format("docker stop {0}", name); string rm = string.Format("docker rm {0}", name); List list = new List { runDocker, createMesh, createLayer, stop, rm }; err = Tools.ExecCmd(list); }*/ } }