| | |
| | | using Hydro.Core.Model; |
| | | using Hydro.MapView.Common; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Drawing; |
| | |
| | | using static Hydro.Core.ObjectEnum; |
| | | using static Hydro.MapView.RepeaterViewModel; |
| | | using static System.Math; |
| | | |
| | | namespace Hydro.MapView |
| | | { |
| | | partial class MapViewNetWork |
| | | public partial class MapViewNetWork |
| | | { |
| | | |
| | | public bool BuildFromInp(string filePath, bool use_old=false) |
| | | public bool BuildFromInp(string filePath, bool use_old = false) |
| | | { |
| | | this.use_old = use_old; |
| | | if (this.use_old) |
| | |
| | | { |
| | | Nodes = new NodeViewModelList(); |
| | | Links = new LinkViewModelList(); |
| | | |
| | | |
| | | |
| | | string line; |
| | | string section = ""; |
| | |
| | | { |
| | | NodeViewModel j = null; |
| | | if (parts[-2] == "Meter") |
| | | j = new MeterViewModel(); |
| | | { |
| | | var m = new MeterViewModel(); |
| | | m.DlTemplateID = parts.ToString(-4, ""); |
| | | j = m; |
| | | } |
| | | else if (parts[-2] == "Nozzle") |
| | | { |
| | | var n = new NozzleViewModel(); |
| | | j = n; |
| | | n.FlowCoefficient = parts.ToFloat(-4, 0); |
| | | } |
| | | |
| | | else |
| | | j = new JunctionViewModel(); |
| | | |
| | |
| | | j.PatternID = parts.ToString(3, null); |
| | | if (j.PatternID == "NONE") j.PatternID = null; |
| | | j.Level = parts.ToInt(-1, 0); |
| | | |
| | | |
| | | Nodes.Add(j); |
| | | } |
| | | break; |
| | | |
| | | case "RESERVOIRS": |
| | | { |
| | | ReservoirViewModel r = new ReservoirViewModel(); |
| | |
| | | Nodes.Add(r); |
| | | } |
| | | break; |
| | | |
| | | case "TANKS": |
| | | { |
| | | TankViewModel tank = new TankViewModel(); |
| | |
| | | Nodes.Add(tank); |
| | | } |
| | | break; |
| | | |
| | | case "PIPES": |
| | | { |
| | | |
| | | if (parts[-2] == "Repeater") |
| | | { |
| | | RepeaterViewModel repeater = new RepeaterViewModel(); |
| | |
| | | p.MinorLoss = parts.ToFloat(6, 0); |
| | | p.Status = StringToStatus(parts.ToString(7, "OPEN")); |
| | | |
| | | |
| | | |
| | | p.Level = parts.ToInt(-1, 0); |
| | | Links.Add(p); |
| | | } |
| | | |
| | | } |
| | | break; |
| | | |
| | |
| | | Links.Add(valve); |
| | | } |
| | | break; |
| | | |
| | | case "PUMPS": |
| | | { |
| | | PumpViewModel pump = new PumpViewModel(); |
| | |
| | | case "HEAD": |
| | | pump.HeadCurve = parts.ToString(index + 1, "PumpDefault"); |
| | | break; |
| | | |
| | | case "SPEED": |
| | | pump.当前转速 = parts.ToFloat(index + 1, 0); |
| | | break; |
| | |
| | | Links.Add(pump); |
| | | } |
| | | break; |
| | | |
| | | case "CURVES": |
| | | { |
| | | string ID = parts.ToString(0, ""); |
| | |
| | | dict_dataset[ID]._data.Add(new PointF(parts.ToFloat(1, 0), parts.ToFloat(2, 0))); |
| | | } |
| | | break; |
| | | |
| | | case "COORDINATES": |
| | | { |
| | | string id = parts[0]; |
| | |
| | | } |
| | | } |
| | | break; |
| | | |
| | | case "STATUS": |
| | | { |
| | | LinkViewModel link = Links.Find(l => l.ID == parts.ToString(0, null)); |
| | |
| | | } |
| | | break; |
| | | } |
| | | if (o!=null) |
| | | if (o != null) |
| | | { |
| | | o.Tags =new TagList( parts.ToString(-3, null)); |
| | | o.Tags = new TagList(parts.ToString(-3, null)); |
| | | } |
| | | |
| | | } |
| | | } |
| | | sr.Close(); |
| | | |
| | | |
| | | if (!dict_dataset.ContainsKey("GPVDefault")) |
| | | { |
| | | var data = new Dataset("GPVDefault", null); |
| | |
| | | new PointF(100,0), |
| | | }; |
| | | dict_dataset.Add("GPVDefault", data); |
| | | |
| | | } |
| | | if (!dict_dataset.ContainsKey("PumpDefault")) |
| | | { |
| | |
| | | new PointF(750f ,31.44f), |
| | | new PointF(777.7777778f ,30.37f), |
| | | new PointF(805.5555556f ,29.27f), |
| | | |
| | | |
| | | |
| | | }; |
| | | dict_dataset.Add("PumpDefault", data); |
| | | } |
| | |
| | | { |
| | | k2++; |
| | | if (k2 < points.Count) coor = points[k2]; |
| | | |
| | | } |
| | | if (k2 == points.Count) |
| | | { |
| | |
| | | J.Y = coor.Position.Y; |
| | | |
| | | k1++; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | BuildRelation(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | } |
| | | StatusType StringToStatus(string status) |
| | | { |
| | | |
| | | private StatusType StringToStatus(string status) |
| | | { |
| | | switch (status) |
| | | { |
| | | case "CLOESD": |
| | | case "0": |
| | | return StatusType.CLOSED; |
| | | break; |
| | | |
| | | case "OPEN": |
| | | case "1": |
| | | return StatusType.OPEN; |
| | | break; |
| | | |
| | | case "ACTIVE": |
| | | return StatusType.ACTIVE; |
| | | break; |
| | | |
| | | default: |
| | | return StatusType.DEFAULT; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 下拉文本框转换为显示内容 |
| | | /// </summary> |
| | | /// <param name="id"></param> |
| | | /// <returns></returns> |
| | | public string ToDisplyName(string id) |
| | | { |
| | | if (string.IsNullOrEmpty(id)) |
| | | return null; |
| | | var filePath = Path.Combine(Directory.GetCurrentDirectory(), "Data\\WaterEquivalent.Json"); |
| | | List<EquivalentTemplateModel> equivalentTemplateModels = new List<EquivalentTemplateModel>(); |
| | | if (File.Exists(filePath)) |
| | | { |
| | | var json = File.ReadAllText(filePath); |
| | | if (!string.IsNullOrEmpty(json)) |
| | | { |
| | | equivalentTemplateModels = JsonConvert.DeserializeObject<List<EquivalentTemplateModel>>(json); |
| | | } |
| | | } |
| | | return equivalentTemplateModels.Where(x => x.ID == Convert.ToInt64(id)).FirstOrDefault().Name; |
| | | } |
| | | |
| | | public void BuildRelation() |
| | | { |
| | | |
| | | |
| | | //读取坐标 |
| | | int k1 = 0;//表示管线索引 |
| | | int k2 = 0;//表示节点索引 |
| | | Nodes.Sort((a, b) => string.Compare(a.ID, b.ID)); |
| | | |
| | | |
| | | |
| | | //建立点线关系链表StartNode,先将管线以Node1(节点1的ID)排序,再将Nodes按ID排序,建立两个游标k1、k2,正向一次循环,建立链表关系 |
| | | //时间复杂度 O(n) |
| | |
| | | { |
| | | k2++; |
| | | if (k2 < Nodes.Count) J = Nodes[k2]; |
| | | |
| | | } |
| | | if (k2 == Nodes.Count) |
| | | { |
| | |
| | | } |
| | | if (k2 == Nodes.Count) |
| | | { |
| | | |
| | | k2 = k0; |
| | | k1++; |
| | | p.Visible = false; |
| | |
| | | |
| | | //while (valveNodes.Count>0) |
| | | //{ |
| | | |
| | | //} |
| | | |
| | | |
| | | |
| | | foreach (ValveNodeViewModel vn in valveNodes.ToList()) |
| | | { |
| | |
| | | Nodes.Remove(vn); |
| | | } |
| | | |
| | | |
| | | |
| | | foreach (PumpNodeViewModel pn in pumpNodes.ToList()) |
| | | { |
| | | if (pn.Links.Count != 2) continue; |
| | |
| | | LinkViewModel temp0 = pn.Links[0] as LinkViewModel; |
| | | pn.Links.RemoveAt(0); |
| | | pn.Links.Add(temp0); |
| | | |
| | | } |
| | | var junc1 = AddJunction("S__" + pn.ID, pn.Position, pn.Elev); |
| | | if (pn.Links[0].StartNode.ID == pn.ID) |
| | |
| | | if (dict_dataset == null) |
| | | { |
| | | dict_dataset = new Dictionary<string, Dataset>(); |
| | | |
| | | } |
| | | pumps.ForEach(p => |
| | | { |
| | |
| | | pump.Datasets["流量扬程曲线"] = ds; |
| | | } |
| | | ds.pump = pump; |
| | | |
| | | } |
| | | |
| | | if (!pump.Datasets.ContainsKey("流量扬程曲线")) |
| | |
| | | Hash_ID = new HashSet<string>(); |
| | | Nodes.ForEach(o => Hash_ID.Add(o.ID)); |
| | | Links.ForEach(o => Hash_ID.Add(o.ID)); |
| | | |
| | | } |
| | | |
| | | public bool loadInpFile_old(string filePath) |
| | |
| | | //tanks = new List<Tank>(); |
| | | //meters = new List<Meter>(); |
| | | |
| | | Links =new LinkViewModelList(); |
| | | Links = new LinkViewModelList(); |
| | | //valves = new List<Valve>(); |
| | | //repeaters = new List<Repeater>(); |
| | | |
| | | |
| | | string line; |
| | | string section = ""; |
| | |
| | | j.Level = level; |
| | | |
| | | Nodes.Add(j); |
| | | |
| | | } |
| | | break; |
| | | |
| | | case "RESERVOIRS": |
| | | { |
| | | ReservoirViewModel r = new ReservoirViewModel(); |
| | |
| | | Nodes.Add(r); |
| | | } |
| | | break; |
| | | |
| | | case "TANKS": |
| | | { |
| | | TankViewModel tank = new TankViewModel(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8]); |
| | |
| | | Links.Add(valve); |
| | | } |
| | | break; |
| | | |
| | | case "REPEATERS": |
| | | { |
| | | RepeaterViewModel repeater = new RepeaterViewModel(); |
| | |
| | | Links.Add(repeater); |
| | | } |
| | | break; |
| | | |
| | | case "COORDINATES": |
| | | { |
| | | string id = parts[0]; |
| | |
| | | { |
| | | k2++; |
| | | if (k2 < points.Count) coor = points[k2]; |
| | | |
| | | } |
| | | if (k2 == points.Count) |
| | | { |
| | |
| | | J.Y = coor.Position.Y; |
| | | |
| | | k1++; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | //建立点线关系链表StartNode,先将管线以Node1(节点1的ID)排序,再将Nodes按ID排序,建立两个游标k1、k2,正向一次循环,建立链表关系 |
| | | //时间复杂度 O(n) |
| | |
| | | { |
| | | k1++; |
| | | if (k1 < Nodes.Count) J = Nodes[k1]; |
| | | |
| | | } |
| | | if (k1 == Nodes.Count) |
| | | { |
| | |
| | | while (J.ID != p.Node2 && k1 < Nodes.Count) |
| | | { |
| | | k1++; |
| | | if (k1 < Nodes.Count) J =Nodes[k1]; |
| | | if (k1 < Nodes.Count) J = Nodes[k1]; |
| | | } |
| | | if (k1 == Nodes.Count) |
| | | { |
| | |
| | | if (J.MaxDiameter < p.Diameter) J.MaxDiameter = p.Diameter; |
| | | J.Links.Add(p); |
| | | k2++; |
| | | |
| | | } |
| | | |
| | | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | } |
| | | |
| | | public void ClearMinorLoss() |
| | | { |
| | | Links.ForEach(l => l.MinorLoss = 0); |
| | | } |
| | | |
| | | public void CalcLinkMinorLoss() |
| | | { |
| | | Links.ForEach(l => l.MinorLoss = 0); |
| | | Nodes.ForEach(n => |
| | | Nodes.ForEach(n => |
| | | { |
| | | var links_Down= n.ViewLinks.FindAll(l=>l.StartNode==n ?l.EN_FLOW>0:l.EN_FLOW<0); |
| | | var links_Down = n.ViewLinks.FindAll(l => l.StartNode == n ? l.EN_FLOW > 0 : l.EN_FLOW < 0); |
| | | var links_Up = n.ViewLinks.FindAll(l => l.StartNode == n ? l.EN_FLOW < 0 : l.EN_FLOW > 0); |
| | | /*两侧均连接一个管线*/ |
| | | if (links_Down.Count==1 && links_Up.Count==1) |
| | | if (links_Down.Count == 1 && links_Up.Count == 1) |
| | | { |
| | | var link_Down = links_Down[0]; |
| | | var link_Up = links_Up[0]; |
| | |
| | | link_Up.MinorLoss += minorLoss; |
| | | } |
| | | /*上游管线为1根,下游管线为多个*/ |
| | | if (links_Up.Count == 1 && links_Down.Count>1) |
| | | if (links_Up.Count == 1 && links_Down.Count > 1) |
| | | { |
| | | |
| | | var link_Up = links_Up[0]; |
| | | |
| | | |
| | | //计算两个管线的夹角,根据夹角计算损失系数 |
| | | foreach (var link_Down in links_Down) |
| | | { |
| | |
| | | minorLoss += GetChangeDiameterMinorLoss(link_Down, link_Up); |
| | | link_Down.MinorLoss += minorLoss; |
| | | } |
| | | |
| | | } |
| | | |
| | | /*下游管线为1根,上游管线为多个*/ |
| | | if (links_Up.Count > 1 && links_Down.Count == 1) |
| | | { |
| | | var link_Down = links_Down[0]; |
| | | |
| | | |
| | | |
| | | //计算两个管线的夹角,根据夹角计算损失系数 |
| | | foreach (var link_Up in links_Up) |
| | |
| | | minorLoss += GetChangeDiameterMinorLoss(link_Down, link_Up); |
| | | link_Up.MinorLoss += minorLoss; |
| | | } |
| | | |
| | | } |
| | | |
| | | /*下游管线为多个,上游管线为多个*/ |
| | | if (links_Up.Count > 1 && links_Down.Count > 1) |
| | | { |
| | | |
| | | |
| | | var UpCount= links_Up.Count; |
| | | var UpCount = links_Up.Count; |
| | | |
| | | //计算两个管线的夹角,根据夹角计算损失系数 |
| | | foreach (var link_Up in links_Up) |
| | | { |
| | | |
| | | foreach (var link_Down in links_Down) |
| | | { |
| | | var angle = GetAngle(link_Down, link_Up); |
| | |
| | | minorLoss += GetChangeDiameterMinorLoss(link_Down, link_Up); |
| | | link_Up.MinorLoss += minorLoss / UpCount; |
| | | } |
| | | |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | }); |
| | | } |
| | | |
| | | private static float GetChangeDiameterMinorLoss(LinkViewModel link_Down, LinkViewModel link_Up) |
| | | { |
| | | var Diameter_Down = link_Down.Diameter; |
| | | var Diameter_Down = link_Down.Diameter; |
| | | var Diameter_Up = link_Up.Diameter; |
| | | //计算两个管线变径的损失系数 |
| | | var minorLoss = 0f; |
| | | if(Diameter_Down>=Diameter_Up)//突然变粗 |
| | | if (Diameter_Down >= Diameter_Up)//突然变粗 |
| | | { |
| | | minorLoss = (float)Pow(1 - Diameter_Up/ Diameter_Down,2); |
| | | minorLoss = (float)Pow(1 - Diameter_Up / Diameter_Down, 2); |
| | | } |
| | | else//突然变细 |
| | | { |
| | | minorLoss = 0.5f * (1 - Diameter_Down / Diameter_Up); |
| | | } |
| | | |
| | | |
| | | return minorLoss; |
| | | } |
| | | |
| | | private static double GetAngle(LinkViewModel link_Down, LinkViewModel link_Up) |
| | | { |
| | | |
| | | //两个管线link_Down,link_Up的向量 |
| | | Vector3D vector_Down = new Vector3D(link_Down.EndNode.X - link_Down.StartNode.X, link_Down.EndNode.Y - link_Down.StartNode.Y, link_Down.EndNode.Elev- link_Down.StartNode.Elev); |
| | | Vector3D vector_Up=new Vector3D(link_Up.EndNode.X - link_Up.StartNode.X, link_Up.EndNode.Y - link_Up.StartNode.Y, link_Up.EndNode.Elev - link_Up.StartNode.Elev); |
| | | Vector3D vector_Down = new Vector3D(link_Down.EndNode.X - link_Down.StartNode.X, link_Down.EndNode.Y - link_Down.StartNode.Y, link_Down.EndNode.Elev - link_Down.StartNode.Elev); |
| | | Vector3D vector_Up = new Vector3D(link_Up.EndNode.X - link_Up.StartNode.X, link_Up.EndNode.Y - link_Up.StartNode.Y, link_Up.EndNode.Elev - link_Up.StartNode.Elev); |
| | | //获取两个向量vector_Down,vector_Up的空间夹角 |
| | | if (vector_Down.Length == 0 || vector_Up.Length == 0) return 0; |
| | | else |
| | | return Vector3D.CalculateAngle(vector_Down, vector_Up); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | private static float GetMinorLossByAngle(double angle) |
| | | { |
| | | double minorLoss; |
| | | minorLoss=0.946 * Pow(Sin(Abs(angle) / 2),2)+2.05* Pow(Sin(Abs(angle) / 2),4); |
| | | minorLoss = 0.946 * Pow(Sin(Abs(angle) / 2), 2) + 2.05 * Pow(Sin(Abs(angle) / 2), 4); |
| | | |
| | | return (float)minorLoss; |
| | | } |
| | | |
| | | public void BuildToInp(string filePath, string userCoorString = null, string sourcePath = null, bool isReplace = false) |
| | | { |
| | | |
| | | if (sourcePath == null) sourcePath = filePath; |
| | | |
| | | string tempString = ""; |
| | |
| | | { |
| | | tempString = File.ReadAllText(sourcePath); |
| | | } |
| | | |
| | | |
| | | Dictionary<string, string> dictExchange = new Dictionary<string, string>() { |
| | | {"{junctions}","{0}" }, |
| | |
| | | if (o is JunctionViewModel j) |
| | | junctionStringBuilder.AppendLine(j.ToString() + $"{j.Level}\tJunction\t{o.Tags}"); |
| | | else if (o is MeterViewModel m) |
| | | junctionStringBuilder.AppendLine(m.ToString() + $"{o.Level}\tMeter\t{o.Tags}"); |
| | | junctionStringBuilder.AppendLine(m.ToString() + $"{o.Level}\tMeter\t{o.Tags}\t{m.DlTemplateID}"); |
| | | else if (o is NozzleViewModel no) |
| | | junctionStringBuilder.AppendLine(no.ToString() + $"{o.Level}\tNozzle\t{o.Tags}\t{no.FlowCoefficient}"); |
| | | }); |
| | |
| | | }); |
| | | string pumpString = pumpStringBuilder.ToString(); |
| | | |
| | | |
| | | StringBuilder curveStringBuilder = new StringBuilder(); |
| | | |
| | | |
| | | |
| | | //pumps.ForEach(o => |
| | | //{ |
| | |
| | | // curveStringBuilder.AppendLine(o.Datasets["流量扬程曲线"].ToString()); |
| | | //}); |
| | | curveStringBuilder.AppendLine(@";ID X-Value Y-Value |
| | | ;HEADLOSS: |
| | | GPVDefault 0 0 |
| | | ;HEADLOSS: |
| | | GPVDefault 0 0 |
| | | GPVDefault 100 0 "); |
| | | if (dict_dataset != null) |
| | | curveStringBuilder.AppendLine(";PUMP: "); |
| | | foreach (var kp in dict_dataset) |
| | | { |
| | | curveStringBuilder.AppendLine(kp.Value.ToString()); |
| | | } |
| | | foreach (var kp in dict_dataset) |
| | | { |
| | | curveStringBuilder.AppendLine(kp.Value.ToString()); |
| | | } |
| | | string curveString = curveStringBuilder.ToString(); |
| | | |
| | | |
| | | StringBuilder coorStringBuilder = new StringBuilder(); |
| | | if (userCoorString == null) |
| | | { |
| | | |
| | | coorStringBuilder.AppendLine(";Node X-Coord Y-Coord"); |
| | | Nodes.ForEach(o => coorStringBuilder.AppendLine(o.ToCoorString())); |
| | | } |
| | |
| | | coorStringBuilder.Append(userCoorString); |
| | | } |
| | | |
| | | |
| | | |
| | | string coorString = coorStringBuilder.ToString(); |
| | | string output = ""; |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | StringBuilder emitterStringBuilder = new StringBuilder(); |
| | | emitterStringBuilder.AppendLine(";Junction \tCoefficient"); |
| | | Nodes.ForEach(o => emitterStringBuilder.Append((o).ToEmitterString())); |
| | | |
| | | |
| | | |
| | | string emitterString = emitterStringBuilder.ToString(); |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | StringBuilder statusStringBuilder = new StringBuilder(); |
| | | statusStringBuilder.AppendLine(";ID \tStatus/Setting\r\n"); |
| | | Links.ForEach(o => statusStringBuilder.Append(o.ToStatusString())); |
| | | |
| | | |
| | | |
| | | string statusString = statusStringBuilder.ToString(); |
| | | |
| | | |
| | | |
| | | output = tempString; |
| | | |
| | |
| | | output = replaceContent(output, "VALVES", valveString); |
| | | output = replaceContent(output, "PUMPS", pumpString); |
| | | output = replaceContent(output, "CURVES", curveString); |
| | | |
| | | |
| | | output = replaceContent(output, "COORDINATES", coorString); |
| | | output = replaceContent(output, "EMITTERS", emitterString); |
| | |
| | | string backupFileName = $"{Path.GetFileNameWithoutExtension(filePath)}_{DateTime.Now:yyyyMMddHHmmss}{Path.GetExtension(filePath)}"; |
| | | string backupFilePath = Path.Combine(backupFolderPath, backupFileName); |
| | | //if (File.Exists(filePath)) File.Copy(filePath, backupFilePath, true); |
| | | |
| | | |
| | | // 检查文件是否存在 |
| | | try |
| | |
| | | |
| | | private string replaceContent(string text, string content, string replaceString) |
| | | { |
| | | |
| | | |
| | | string str = replaceString; |
| | | |
| | | string replacedText = ReplaceCoordinatesSection(text, content, str); |
| | |
| | | |
| | | return replacedText; |
| | | } |
| | | |
| | | } |
| | | |
| | | public class Vector3D |
| | | { |
| | | public double X { get; set; } |
| | |
| | | Y = y; |
| | | Z = z; |
| | | } |
| | | |
| | | public static double CalculateAngle(Vector3D v1, Vector3D v2) |
| | | { |
| | | // 计算两个向量的点积 |
| | |
| | | |
| | | return angleInRadians; |
| | | } |
| | | |
| | | public double Length |
| | | { |
| | | get |
| | | { |
| | | return Math.Sqrt( X * X + Y * Y + Z * Z); |
| | | return Math.Sqrt(X * X + Y * Y + Z * Z); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |