using MathNet.Numerics;
|
using MathNet.Numerics.LinearAlgebra.Double;
|
using Newtonsoft.Json;
|
using Newtonsoft.Json.Serialization;
|
using System.ComponentModel;
|
using System.Data;
|
using System.Drawing.Design;
|
using System.IO;
|
using System.Numerics;
|
using System.Reflection;
|
using System.Runtime.Serialization.Formatters.Binary;
|
using System.Text;
|
using System.Text.RegularExpressions;
|
using static Hydro.MapViewEnum;
|
using static Hydro.RepeaterViewModel;
|
using Cursor = System.Windows.Forms.Cursor;
|
namespace Hydro;
|
|
public class TemplateStoreViewModel
|
{
|
public List<Template> templates { get; set; } = new List<Template>();
|
}
|
partial class DMap
|
{
|
|
#region 核心属性
|
public TContainer TC = new TContainer();
|
|
|
/// 地图选项
|
|
public MapDimensions mapOption
|
{
|
get { return TC.mapOption; }
|
set { TC.mapOption = value; }
|
}
|
|
|
/// 临时管网层
|
|
public Template _newTemplate
|
{
|
get { return TC.newTemplate; }
|
set { TC.newTemplate = value; }
|
}
|
|
|
public Template _Template
|
{
|
get { return TC.template; }
|
}
|
|
#endregion
|
|
}
|
public enum DrawingMode
|
{
|
All,
|
Pic,
|
Net,
|
New,
|
Auxiliary
|
|
}
|
public enum DrawingStatus
|
{
|
drawingBase,
|
drawingNet,
|
drawingNetNew,
|
drawingPic,
|
drawingOthers,
|
Ready,
|
}
|
public class MapOption
|
{
|
public float Link_multiply { get; set; } = 0.6667f;
|
public float junction_multiply { get; set; } = 1f;
|
public bool _ShowValve { get; set; } = true;
|
public bool _ShowJunction { get; set; } = true;
|
public bool _ShowStatus { get; set; } = false;
|
public bool _ShowFlowDirection { get; set; } = false;
|
|
}
|
|
partial class MapViewer
|
{
|
void DrawBackGroud(Graphics bufferG, Template template)
|
{
|
if (template == null) return;
|
var _Nodes = template.network.Nodes.ViewNodes;
|
var _Links = template.network.Links.ViewLinks;
|
|
var Cpoints = getCurclePoints(64).ToList();
|
|
var r = 1.73f / zoom;
|
var rt = r;
|
|
|
r = r * Link_multiply;
|
List<PointF> diametersZoom = new List<PointF>() { new PointF(0, 0.08f), new PointF(150, 0.03f), new PointF(300, 0.001f), new PointF(800, 0.0001f) };
|
|
Pen penN = new Pen(Color.FromArgb(0, 0, 255), 1 * r);
|
|
|
//背景图绘制
|
if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath))
|
|
|
{
|
//var gs = bufferG.Save();
|
// 应用矩阵变换以抵消之前的翻转效果
|
//bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
|
List<PointF> p = new List<PointF>();
|
|
if (!this.mapOption.isAutoBackgroundImage)
|
{
|
var Cps = new List<PointF>
|
{
|
template.BackGroundPoint1,
|
new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y),
|
new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y),
|
//template.BackGroundPoint2,
|
|
|
};
|
Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
|
}
|
else
|
{
|
|
// 恢复之前保存的绘图状态
|
|
//var Cps = new List<PointF>
|
//{
|
//template.BackGroundPoint1,
|
//new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y),
|
//new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y),
|
////template.BackGroundPoint2,
|
|
|
//};
|
var p1 = new PointF(template.BackGroundImgX, template.BackGroundImgY);
|
var p2 = new PointF(template.BackGroundImgX + template.BackGroundImgWidth, template.BackGroundImgY + template.BackGroundImgHeight);
|
|
var f = template.BackGroundImgRotaAngle / 180 * Math.PI;
|
var djx = Math.Sqrt((Math.Pow(template.BackGroundImgWidth, 2) + Math.Pow(template.BackGroundImgHeight, 2)));
|
var p3 = new PointF(p1.X + (float)(Math.Cos(f) * template.BackGroundImgWidth), p1.Y + (float)(Math.Sin(f) * template.BackGroundImgWidth));
|
var p4 = new PointF(p1.X - (float)(Math.Sin(f) * template.BackGroundImgHeight), p1.Y + (float)(Math.Cos(f) * template.BackGroundImgHeight));
|
p3.Y = p4.Y;
|
//p4.Y = -p4.Y;
|
var Cps = new List<PointF>
|
{
|
//template.BackGroundPoint1,
|
//new PointF(template.BackGroundImgX,template.BackGroundImgY),
|
p4,
|
p3,p1
|
//template.BackGroundPoint2,
|
|
|
};
|
template.BackGroundPoint1 = p4;
|
template.BackGroundPoint2 = new PointF(p3.X, p1.Y);
|
|
|
|
//List<PointF> p = new List<PointF>();
|
Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
|
}
|
|
//bufferG.DrawImage(System.Drawing.Image.FromFile(@"C:\Users\cloud\Pictures\GenshinImpactCloudGame\QQ截图20230919105637.png"), p[0]);
|
try
|
{
|
var img = System.Drawing.Image.FromFile(template.BackGroundImg_FullPath);
|
if (img != null)
|
{
|
bufferG.FillPolygon(penN.Brush, p.ToArray());
|
bufferG.DrawImage(img, p.ToArray());
|
}
|
}
|
catch
|
{
|
|
}
|
|
//bufferG.Restore(gs);
|
}
|
}
|
|
void Draw(Graphics bufferG, Template template)
|
{
|
if (template == null) return;
|
var _Nodes = template.network.Nodes.ViewNodes;
|
var _Links = template.network.Links.ViewLinks;
|
var _Areas = template.network.Areas;
|
var Cpoints = getCurclePoints(64).ToList();
|
|
var r = 1.73f / zoom;
|
var rt = r;
|
|
float minElve = float.MinValue;
|
float maxElve = float.MaxValue;
|
//if (this.mapOption!=null && this.mapOption.ShowFloor!=int.MinValue )
|
//{
|
//var fl = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor);
|
//var fl_1 = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor+1);
|
//if (fl!=null)
|
//{
|
//minElve = fl.Elev;
|
|
//maxElve = fl_1!=null ? fl_1.Elev : float.MaxValue;
|
//}
|
|
//}
|
r = r * Link_multiply;
|
List<PointF> diametersZoom = new List<PointF>() { new PointF(0, 0.08f), new PointF(150, 0.03f), new PointF(300, 0.001f), new PointF(800, 0.0001f) };
|
|
Pen penN = new Pen(Color.FromArgb(0, 0, 255), 1 * r);
|
|
Pen penChoosed = new Pen(Color.Purple, 5 * r);
|
Pen pen_valveChoosed = new Pen(Color.Red, 5 * r);
|
|
Pen penClosed = new Pen(Color.OrangeRed, 2 * r);
|
Pen penHovered = new Pen(Color.DeepSkyBlue, 5 * r);
|
|
|
//绘制面
|
using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
|
{
|
foreach (var area in _Areas)
|
{
|
|
if (!area.Visible) continue;
|
if (!IsFaceVisibleToCamera(area, GetCameraPosition())) continue;
|
if (area.Elev < minElve || area.Elev >= maxElve) continue;
|
|
var p = new List<PointF>();
|
foreach (var node in area.InnerNodes)
|
{
|
p.Add(CubeWorldPointToMapPoint(node, template.OffSet));
|
}
|
if (p.Count < 3) continue;
|
pen0.Color = penClosed.Color = area.color;
|
Pen pen = pen0;
|
if (area.Hovered) pen = penHovered;
|
bufferG.FillPolygon(pen.Brush, p.ToArray());
|
bufferG.DrawPolygon(pen, p.ToArray());
|
//显示area的名称
|
var c = new PointF(p.Average(p0 => p0.X), p.Average(p0 => p0.Y));
|
var brush = new SolidBrush(Color.White);
|
|
|
|
|
var gs = bufferG.Save();
|
// 应用矩阵变换以抵消之前的翻转效果
|
bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
|
|
Font font = new Font(FontFamily.GenericSansSerif, 10 * 10 * zoom);
|
|
SizeF textSize = bufferG.MeasureString(area.Name, font);
|
var center = new PointF(c.X * Zoom.X, c.Y * Zoom.Y);
|
float textLeft = center.X - textSize.Width / 2;
|
float textTop = center.Y - textSize.Height / 2;
|
PointF pd = new PointF(textLeft, textTop);
|
|
bufferG.DrawString(area.Name, font, brush, pd);
|
// 恢复之前保存的绘图状态
|
bufferG.Restore(gs);
|
}
|
}
|
|
|
// 绘制线
|
|
HashSet<long> dict_flow_direction = new HashSet<long>();
|
using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
|
{
|
|
foreach (var link in _Links)
|
{
|
if (!link.Visible) continue;
|
if (link.Elev < minElve || link.Elev >= maxElve) continue;
|
//if (_isMovingObject && (link.StartNode == _OperaNode || link.EndNode == _OperaNode)) continue;
|
var p1 = WorldPointToMapPoint(link.StartNode, template.OffSet);
|
var p2 = WorldPointToMapPoint(link.EndNode, template.OffSet);
|
if (!isVisible(p1) && !isVisible(p2)) continue;
|
if (LinkColour != null)
|
{
|
pen0.Color = penClosed.Color = GraphHelper.getLinkColor(LinkColour, link);
|
}
|
|
Pen pen = pen0;
|
#if DEBUG
|
#else
|
if (_Template != null && _Template.mapOption._ShowStatus && link.Status == Hydro.Core.StatusType.CLOSED) pen = penClosed;
|
#endif
|
|
if (link.Hovered) pen = penHovered;
|
float zoomAtMin = 0;
|
for (int i = 0; i < diametersZoom.Count; i++)
|
{
|
PointF point = diametersZoom[i];
|
if (link.Diameter >= point.X) continue;
|
zoomAtMin = diametersZoom[i - 1].Y;
|
break;
|
}
|
if (zoomAtMin >= zoom) continue;
|
if (link is ValveViewModel)
|
{
|
if (link.Selected || _ShowValve)
|
{
|
|
var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
|
var valveShapeHeight = link.Selected ? 10 : 5;
|
PointF[] points = new PointF[] {
|
GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
|
|
};
|
|
bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
|
|
}
|
|
|
}
|
else if (link is PumpViewModel)
|
{
|
if (link.Selected || _ShowValve)
|
{
|
|
var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
//bufferG.DrawLine(link.Selected ? pen_valveChoosed : pen, p1, p2);
|
|
bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
|
// 绘制圆形部分(水泵的泵体)
|
float radius = 5 * r;
|
float diameter = radius * 2;
|
#region 圆形拆分
|
//var p = new PointF[]
|
//{
|
//GraphHelper.getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2),
|
//GraphHelper.getRotatePoint(c.X + radius - radius, c.Y - radius, c, p1, p2),
|
//GraphHelper.getRotatePoint(c.X + radius - radius, c.Y + radius, c, p1, p2),
|
//GraphHelper.getRotatePoint(c.X - radius - radius, c.Y + radius, c, p1, p2),
|
//GraphHelper.getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2),
|
//};
|
List<PointF> p = new List<PointF>();
|
Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2)));
|
|
#endregion
|
|
//RectangleF circleRect = new RectangleF(p[0].X, p[0].Y,p[1].X-p[0].X>0? diameter:-diameter,p[1].Y-p[0].Y>0? diameter:-diameter);
|
//bufferG.FillEllipse(link.Selected ? pen_valveChoosed.Brush : pen.Brush, circleRect);
|
|
|
bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
|
|
//// 绘制矩形部分(水泵的出口)
|
//float rectangleWidth = 6*r;
|
//float rectangleHeight = 2*r;
|
//PointF rectTopLeft = new PointF(c.X - rectangleWidth / 2, c.Y + radius);
|
//SizeF rectSize = new SizeF(rectangleWidth, rectangleHeight);
|
//RectangleF rectangleRect = new RectangleF(rectTopLeft, rectSize);
|
//bufferG.DrawRectangles(link.Selected ? pen_valveChoosed : pen,new RectangleF[] { rectangleRect });
|
|
// 绘制连接线
|
|
|
var valveShapeHeight = link.Selected ? radius * 2 : radius;
|
PointF[] points = new PointF[] {
|
GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
|
|
};
|
|
bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
|
}
|
|
|
}
|
else if (link is RepeaterViewModel re)
|
{
|
if (re.Status == RepeaterViewModel.RepeatStatus.收起 || _IsEditMode)
|
{
|
|
bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
|
|
|
var listNode = GraphHelper.Get等分Nodes(p1, p2, Math.Max(re.RepeatTimes, 1));
|
|
for (int i = 0; i < listNode.Count; i++)
|
{
|
//foreach (var c in listNode)
|
//{
|
var c = listNode[i];
|
RectangleF[] rects = new RectangleF[] {
|
new RectangleF(c.X-10*r,c.Y-8*r,20*r,16*r),
|
};
|
bufferG.FillRectangles(new SolidBrush(Color.White), rects);
|
|
//bufferG.FillRectangles(link.Selected ? penChoosed.Brush : pen.Brush, new RectangleF[]
|
//{
|
//new RectangleF(c.X-5*r,c.Y-5*r,3*r,3*r),
|
//new RectangleF(c.X-5*r,c.Y+2*r,3*r,3*r),
|
//new RectangleF(c.X+2*r,c.Y+2*r,3*r,3*r),
|
//new RectangleF(c.X+2*r,c.Y-5*r,3*r,3*r),
|
//});
|
// 保存当前绘图状态
|
var gs = bufferG.Save();
|
// 应用矩阵变换以抵消之前的翻转效果
|
bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
|
int index = re.GetIndex(i);
|
string indexString = index == 0 ? "" : index.ToString();
|
Font font = new Font(FontFamily.GenericSansSerif, 10);
|
string text = $"{indexString}{re.NetworkShowName}";
|
SizeF textSize = bufferG.MeasureString(text, font);
|
var center = new PointF(c.X * Zoom.X, c.Y * Zoom.Y);
|
float textLeft = center.X - textSize.Width / 2;
|
float textTop = center.Y - textSize.Height / 2;
|
PointF p = new PointF(textLeft, textTop);
|
|
bufferG.DrawString(text, font, link.Selected ? penChoosed.Brush : pen.Brush, p);
|
// 恢复之前保存的绘图状态
|
bufferG.Restore(gs);
|
|
if (textSize.Width / Zoom.X > rects[0].Width)
|
{
|
rects[0] = new RectangleF(c.X - textSize.Width / 2 / Zoom.X - 1 * r, c.Y - 8 * r, textSize.Width / Zoom.X + 2 * r, 16 * r);
|
}
|
try
|
{
|
bufferG.DrawRectangles(penN, rects);
|
|
}
|
catch { }
|
|
}
|
//var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
}
|
//else
|
//{
|
//DrawRepeater(bufferG,re);
|
//}
|
}
|
else
|
{
|
|
if (link.StartNode == null || link.EndNode == null) continue;
|
try
|
{
|
bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
|
}
|
catch (Exception)
|
{
|
|
}
|
if (_Template.mapOption._ShowFlowDirection)
|
{
|
var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
|
var ps = MapToScreen(c);
|
//将ps转换为ulong,精度为20,并加入到dict_flow_direction中
|
var ps_20 = GraphHelper.GetUlongByPoint(ps, 5);
|
if (!dict_flow_direction.Contains(ps_20))
|
{
|
dict_flow_direction.Add(ps_20);
|
bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
|
// 绘制圆形部分(水泵的泵体)
|
float radius = 5 * r;
|
float diameter = radius * 2;
|
#region 圆形拆分
|
float activeD = 1;
|
if (link.EN_FLOW < 0) activeD = -1;
|
List<PointF> p = new List<PointF>();
|
Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X - activeD * cp.X * radius + activeD * radius, c.Y + cp.Y * radius, c, p1, p2)));
|
|
#endregion
|
|
|
bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
|
|
var valveShapeHeight = link.Selected ? radius * 2 : radius;
|
PointF[] points = new PointF[] {
|
GraphHelper.getRotatePoint(c.X -activeD* valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X, c.Y ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
|
GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
|
};
|
|
bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
|
}
|
|
|
|
}
|
}
|
|
}
|
}
|
|
|
r = rt;
|
|
|
HashSet<long> dict_point = new HashSet<long>();
|
//绘制点
|
penChoosed = new Pen(Color.Green, 1f * r);
|
Brush brushChoosed = penChoosed.Brush;
|
SolidBrush whiteBrush = new SolidBrush(Color.White);
|
|
using (Pen pen0 = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
|
{
|
|
foreach (NodeViewModel node in _Nodes)
|
{
|
if (!node.Visible) continue;
|
if (node.Elev < minElve || node.Elev >= maxElve) continue;
|
Pen pen = pen0;
|
Brush brush = pen.Brush;
|
float pr = (float)(r * 0.5);
|
pr = pr * junction_multiply;
|
PointF p = WorldPointToMapPoint(node, template.OffSet);
|
if (!isVisible(p)) continue;
|
var ps_20 = GraphHelper.GetUlongByPoint(p, 0.1f);
|
if (dict_point.Contains(ps_20))
|
continue;
|
dict_point.Add(ps_20);
|
//var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f;
|
//var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f;
|
if (NodeColour != null)
|
{
|
pen.Color = penChoosed.Color = GraphHelper.getNodeColor(NodeColour, node);
|
brush = pen.Brush;
|
brushChoosed = penChoosed.Brush;
|
|
|
}
|
if (node.Hovered)
|
{
|
pen = penHovered;
|
brush = pen.Brush;
|
pr = pr * 2;
|
}
|
|
var rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
|
float zoomAtMin = 0;
|
for (int i = 0; i < diametersZoom.Count; i++)
|
{
|
PointF point = diametersZoom[i];
|
if (node.MaxDiameter >= point.X) continue;
|
zoomAtMin = diametersZoom[i - 1].Y;
|
break;
|
}
|
if (zoomAtMin >= zoom) continue;
|
//if(node.ID == _StartPoint)
|
//{
|
//var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
//bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
//whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
|
//bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
//whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
//bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
//}
|
//else
|
if (node == _OperaNode)
|
{
|
//bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle);
|
var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
|
bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
|
whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
//bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle);
|
|
}
|
else if (node.ID == _EndPoint)
|
{
|
|
var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
//whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
|
//bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, whiteRect);
|
|
var p1 = new PointF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr);
|
var p2 = new PointF(p1.X + 6 * pr, p1.Y + 6 * pr);
|
bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2);
|
p1 = new PointF(rectangle.X + 2 * pr, rectangle.Y + 8 * pr);
|
p2 = new PointF(p1.X + 6 * pr, p1.Y - 6 * pr);
|
bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2);
|
|
//bufferG.FillEllipse(junction.Choosed ? brushChoosed : brush, rectangle);
|
//var whiteRect = new RectangleF(rectangle.X + 1 * pr, rectangle.Y + 1 * pr, rectangle.Width - 2 * pr, rectangle.Height - 2 * pr);
|
//bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
//whiteRect = new RectangleF(rectangle.X - 2 * pr, rectangle.Y - 2 * pr, rectangle.Width + 4 * pr, rectangle.Height + 4 * pr);
|
//bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, whiteRect);
|
}
|
else if (node is TankViewModel)
|
{
|
pr *= 2;
|
rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
|
RectangleF r0 = new RectangleF(rectangle.X, rectangle.Y + 5 * pr, 10 * pr, 5 * pr);
|
RectangleF r1 = new RectangleF(rectangle.X + 2 * pr, rectangle.Y, 6 * pr, 5 * pr);
|
bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r0);
|
bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r1);
|
|
}
|
else if (node is ReservoirViewModel)
|
{
|
pr *= 2;
|
rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
|
|
RectangleF r0 = new RectangleF(rectangle.X, rectangle.Y + 2 * pr, rectangle.Width, 6 * pr);
|
RectangleF r1 = new RectangleF(rectangle.X, rectangle.Y + 8 * pr, 1 * pr, 2 * pr);
|
RectangleF r2 = new RectangleF(rectangle.X + 9 * pr, rectangle.Y + 8 * pr, 1 * pr, 2 * pr);
|
bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r0);
|
bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r1);
|
bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r2);
|
}
|
else if (node is MeterViewModel)
|
{
|
|
|
//bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle);
|
bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle);
|
var whiteRect = new RectangleF(rectangle.X + 1 * pr, rectangle.Y + 1 * pr, rectangle.Width - 2 * pr, rectangle.Height - 2 * pr);
|
bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
var p1 = new PointF(rectangle.X + 5 * pr, rectangle.Y);
|
var p2 = new PointF(rectangle.X + 5 * pr, rectangle.Y + 10 * pr);
|
bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2);
|
}
|
else
|
{
|
rectangle = new RectangleF((float)p.X - 3 * pr, (float)p.Y - 3 * pr, 6 * pr, 6 * pr);
|
if (node.Selected || _ShowJunction)
|
bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle);
|
}
|
|
}
|
}
|
|
using (Pen pen = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
|
{
|
Brush brush = pen.Brush;
|
//获取_Nodes中自由水压最小的节点
|
var node = _Nodes.Where(n => n is JunctionViewModel || n is MeterViewModel && n.EN_PRESSURE != float.NaN).OrderBy(n => n.EN_PRESSURE).FirstOrDefault();
|
//判断node.EN_PRESSURE不是float.NaN
|
|
|
|
if (node != null && !float.IsNaN(node.EN_PRESSURE))
|
{
|
|
//if (node.Elev < minElve || node.Elev >= maxElve) continue;
|
float pr = (float)(r * 0.5);
|
pr = pr * junction_multiply;
|
PointF p = WorldPointToMapPoint(node, template.OffSet);
|
|
var ps_20 = GraphHelper.GetUlongByPoint(p, 0.1f);
|
|
dict_point.Add(ps_20);
|
//var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f;
|
//var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f;
|
if (NodeColour != null)
|
{
|
pen.Color = GraphHelper.getNodeColor(NodeColour, node);
|
brush = pen.Brush;
|
brushChoosed = penChoosed.Brush;
|
|
|
}
|
|
|
var rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
|
float zoomAtMin = 0;
|
for (int i = 0; i < diametersZoom.Count; i++)
|
{
|
PointF point = diametersZoom[i];
|
if (node.MaxDiameter >= point.X) continue;
|
zoomAtMin = diametersZoom[i - 1].Y;
|
break;
|
}
|
|
|
//var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
//bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
//whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
|
//bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
|
//whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
//bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
var p1 = new PointF((float)p.X - 4 * pr, (float)p.Y - 2 * pr);
|
var p2 = new PointF((float)p.X + 4 * pr, (float)p.Y - 2 * pr);
|
var p3 = new PointF((float)p.X, (float)p.Y - 4 * pr);
|
bufferG.DrawPolygon(node.Selected ? penChoosed : pen, new PointF[] { p1, p2, p3 });
|
|
var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
bufferG.FillEllipse(whiteBrush, whiteRect);
|
|
whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
|
bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
|
|
}
|
}
|
}
|
//绘制辅助线
|
void DrawH(Graphics bufferG, Template template)
|
{
|
var r = 2f / zoom;
|
if (_isDragging && DragStartPos != new PointF(0, 0) && mousePosition != new PointF(0, 0))
|
{
|
label_center.Text = $"S:{DragStartPos.X}:{DragStartPos.Y} E:{mousePosition.X}:{mousePosition.Y}";
|
var _lastMousePosition = DragStartPos;
|
// 绘制矩形
|
var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y));
|
var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y));
|
if (size.Width == 0) size.Width = 0.01f;
|
if (size.Height == 0) size.Height = 0.01f;
|
var rectangle0 = new RectangleF(start, size);
|
using (var pen = new Pen(Color.Black, 0.5f * r))
|
{
|
bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 });
|
}
|
}
|
if (_isPainting)
|
{
|
if (_mouseState == MapViewEnum.MouseState.新增立管)
|
{
|
var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(0, 0, 1));
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), WorldPointToMapPoint(wPos));
|
}
|
}
|
else
|
{
|
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
if (mapOption.IsOrtho)
|
{
|
var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(1, 1, 0));
|
//getPointAndHeight(e, _select_junction1, out p, out z);
|
var mapPos = WorldPointToMapPoint(wPos);
|
bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), mapPos);
|
}
|
else
|
{
|
bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), _MousePosition);
|
}
|
|
}
|
}
|
}
|
if (_isDrawingPolygon && polygonPoints.Count > 0)
|
{
|
List<PointF> pf = polygonPoints.ToList();
|
pf.Add(new PointF(mousePosition.X, mousePosition.Y));
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
// 绘制多边形虚线边框
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
bufferG.DrawLines(pen, pf.ToArray());
|
}
|
}
|
if (_isSettingBackGroundPictur)
|
{
|
|
var _lastMousePosition = DragStartPos;
|
// 绘制矩形
|
var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y));
|
var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y));
|
var rectangle0 = new RectangleF(start, size);
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 });
|
}
|
}
|
|
if (_isMovingObject)
|
{
|
var newP = _MousePosition;
|
//var p = MapPointToWorldPoint(, _OperaNode.Elev);
|
var oldP3D = (PointF3D)_undoOldValue;
|
var oldP = WorldPointToMapPoint(new PointF(oldP3D.X, oldP3D.Y), oldP3D.Z);
|
List<PointF> pf = new List<PointF> { oldP, newP };
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
// 绘制多边形虚线边框
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
bufferG.DrawLines(pen, pf.ToArray());
|
}
|
}
|
}
|
|
#region 基础坐标转换方法
|
|
/// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
|
|
/// <param name="screenPos"></param>
|
|
private PointF ScreenToVMap(PointF screenPos, float z = 0)
|
{
|
var centerX = this.map.Width / 2;
|
var centerY = this.map.Height / 2;
|
var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X;
|
var worldY = (screenPos.Y - centerY) / Zoom.Y + 0;
|
return new PointF(worldX, worldY);
|
}
|
|
|
|
/// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
|
|
/// <param name="screenPos"></param>
|
|
private PointF ScreenToMap(PointF screenPos, float z = 0)
|
{
|
|
var centerX = this.map.Width / 2;
|
var centerY = this.map.Height / 2;
|
var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X;
|
var worldY = (screenPos.Y - centerY - Z(z).Y) / Zoom.Y + MapCenter.Y;
|
return new PointF(worldX, worldY);
|
}
|
|
|
/// 世界投影坐标转换为屏幕坐标
|
|
private PointF MapToScreen(PointF mapPos, float z = 0)
|
{
|
|
var centerX = this.map.Width / 2;
|
var centerY = this.map.Height / 2;
|
var screenX = (mapPos.X - MapCenter.X) * Zoom.X + centerX + Z(z).X;
|
var screenY = (mapPos.Y - MapCenter.Y) * Zoom.Y + centerY + Z(z).Y;
|
//if (is3Dview) screenY = -(mapPos.Y - center.Y) * (0.5f * zoom) + centerY - 2 * z;
|
return new PointF(screenX, screenY);
|
}
|
|
|
// 根据旋转角度计算旋转后的坐标
|
private PointF Get平面旋转Point(PointF p, PointF MapC)
|
{
|
|
PointF center = MapC;
|
double radian = Rotation * Math.PI / 180;// 角度转弧度
|
float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X);
|
float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y);
|
return new PointF(x, y);
|
}
|
private PointF Get平面还原Point(PointF p, PointF MapC)
|
{
|
PointF center = MapC;
|
double radian = -Rotation * Math.PI / 180;// 角度转弧度
|
float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X);
|
float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y);
|
return new PointF(x, y);
|
}
|
|
private PointF Get俯视角旋转Point(PointF p, float z, PointF MapC)
|
{
|
PointF center = MapC;
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
float x = (float)p.X;
|
float y = (float)(sin * (p.Y - center.Y) + center.Y) + cos * z;
|
return new PointF(x, y);
|
}
|
private PointF Get俯视角还原Point(PointF p, float z, PointF MapC)
|
{
|
PointF center = MapC;
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
float x = (float)p.X;
|
float y = (p.Y - center.Y - cos * z) / sin + center.Y;
|
return new PointF(x, y);
|
}
|
private PointF GetRotateVector(PointF p, PointF p0)
|
{
|
|
double radian = Rotation * Math.PI / 180;// 角度转弧度
|
float x = (float)(Math.Cos(radian) * (p.X - p0.X) - Math.Sin(radian) * (p.Y - p0.Y));
|
float y = (float)(Math.Sin(radian) * (p.X - p0.X) + Math.Cos(radian) * (p.Y - p0.Y));
|
return new PointF(x, y);
|
}
|
|
|
/// 获取世界投影坐标
|
|
private PointF WorldPointToMapPoint(PointF point, float z, PointF3D offset = null)
|
{
|
if (offset == null) offset = new PointF3D(0, 0, 0);
|
point = new PointF(point.X + offset.X, point.Y + offset.Y);
|
|
var pointR = Get平面旋转Point(point, MapCenter);
|
|
var pointT = Get俯视角旋转Point(pointR, z + offset.Z, MapCenter);
|
|
//var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
|
return pointT;
|
}
|
private PointF WorldPointToMapPoint(PointF3D point, PointF3D offset = null)
|
{
|
return WorldPointToMapPoint(new PointF(point.X, point.Y), point.Z, offset);
|
|
}
|
private PointF WorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
|
{
|
PointF p;
|
if (junction == null) return new PointF(0, 0);
|
p = WorldPointToMapPoint(junction.Position, junction.Elev, offset);
|
return p;
|
}
|
private PointF CubeWorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
|
{
|
if (junction == null) return new PointF(0, 0);
|
var point = junction.Position;
|
var z = junction.Elev;
|
if (offset == null) offset = new PointF3D(0, 0, 0);
|
point = new PointF(point.X + offset.X, point.Y + offset.Y);
|
var pointR = Get平面旋转Point(point, new PointF(0, 0));
|
var pointT = Get俯视角旋转Point(pointR, z + offset.Z, new PointF(0, 0));
|
return pointT;
|
}
|
private List<PointF> WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null)
|
{
|
List<PointF> list = new List<PointF>();
|
|
PointF p;
|
p = WorldPointToMapPoint(pipe.StartNode, offset);
|
list.Add(p);
|
p = WorldPointToMapPoint(pipe.EndNode, offset);
|
list.Add(p);
|
return list;
|
|
}
|
|
/// 获取正交投影坐标,返回的是世界坐标
|
|
/// <param name="position3D">世界坐标</param>
|
/// <param name="mousePosition">地图坐标</param>
|
/// <param name="vector3">投影向量</param>
|
|
/// <exception cref="NotImplementedException"></exception>
|
private PointF3D GetZZWorldPoint(PointF3D position3D, PointF mousePosition, Vector3 vector3)
|
{
|
//做一条通过position3D的平行于vector3的直线,
|
if (vector3 == new Vector3(0, 0, 1))
|
{
|
return GetLGWorldPoint(position3D, mousePosition);
|
}
|
else
|
{
|
var p2 = MapPointToWorldPoint(mousePosition, position3D.Z);
|
var vector = new Vector2(p2.X - position3D.X, p2.Y - position3D.Y);
|
//判断二维向量vector在第几象限,距离哪个轴最近
|
var x = vector.X;
|
var y = vector.Y;
|
var x1 = Math.Abs(x);
|
var y1 = Math.Abs(y);
|
if (x1 > y1)
|
{
|
if (x > 0)
|
{
|
//第一象限
|
return new PointF3D(position3D.X + Math.Abs(x), position3D.Y, position3D.Z);
|
}
|
else
|
{
|
//第三象限
|
return new PointF3D(position3D.X - Math.Abs(x), position3D.Y, position3D.Z);
|
}
|
}
|
else
|
{
|
if (y > 0)
|
{
|
//第二象限
|
return new PointF3D(position3D.X, position3D.Y + Math.Abs(y), position3D.Z);
|
}
|
else
|
{
|
//第四象限
|
return new PointF3D(position3D.X, position3D.Y - Math.Abs(y), position3D.Z);
|
}
|
}
|
}
|
}
|
|
|
/// 获取正交投影坐标,返回的是世界坐标
|
|
/// <param name="position3D">世界坐标</param>
|
/// <param name="mousePosition">地图坐标</param>
|
/// <param name="vector3">投影向量</param>
|
|
/// <exception cref="NotImplementedException"></exception>
|
private PointF3D GetLGWorldPoint(PointF3D position3D, PointF p2)
|
{
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
var p1 = WorldPointToMapPoint(position3D);
|
var dy = p2.Y - p1.Y;
|
float dz = dy / cos;
|
return new PointF3D(position3D.X, position3D.Y, position3D.Z + dz);
|
|
}
|
|
private PointF MapPointToWorldPoint(PointF3D point)
|
{
|
return MapPointToWorldPoint(new PointF(point.X, point.Y), point.Z);
|
}
|
|
/// 获取地图投影坐标
|
|
/// <param name="point"></param>
|
/// <param name="z"></param>
|
|
public PointF MapPointToWorldPoint(PointF point, float z = 0)
|
{
|
var pointT = Get俯视角还原Point(point, z, MapCenter);
|
pointT = Get平面还原Point(pointT, MapCenter);
|
|
//var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
|
return pointT;
|
}
|
private PointF GetMapPoint_还原(NodeViewModel junction)
|
{
|
PointF p;
|
|
p = MapPointToWorldPoint(junction.Position, junction.Elev);
|
return p;
|
|
}
|
|
|
|
#endregion
|
#region 计算三维相机
|
public PointF3D GetCameraPosition(float distance = 1)
|
{
|
// 将角度转换为弧度
|
float rotationRadians = (float)Rotation * (float)Math.PI / 180;
|
float rotationFRadians = (float)RotationF * (float)Math.PI / 180;
|
|
// 计算相机的球坐标系位置
|
float x = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Cos(rotationRadians);
|
float y = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Sin(rotationRadians);
|
float z = distance * (float)Math.Cos(rotationFRadians);
|
|
return new PointF3D(x, y, z);
|
}
|
public bool IsFaceVisibleToCamera(AreaViewModel area, PointF3D cameraPosition)
|
{
|
|
//正面是2,右面是1,左面是3,背面是4
|
//Rotation为0时,只显示正面,Rotation为90时,只显示右面,Rotation为180时,只显示背面,Rotation为270时,只显示左面
|
int delta = 5;
|
bool flag = false;
|
switch (area.Name)
|
{
|
case "左":
|
//Rotation为0~180时显示
|
if (RotationF <= 90 - delta && Rotation >= 0 + delta && Rotation <= 180 - delta)
|
flag = true;
|
break;
|
case "前":
|
//Rotation为0~180时显示
|
if (RotationF <= 90 - delta && Rotation >= -90 + delta && Rotation <= 90 - delta)
|
flag = true;
|
break;
|
case "右":
|
//Rotation为0~180时显示
|
if (RotationF <= 90 - delta && Rotation >= -180 + delta && Rotation <= 0 - delta)
|
flag = true;
|
break;
|
case "后":
|
//Rotation为0~180时显示
|
if (RotationF <= 90 - delta && ((Rotation >= 90 + delta && Rotation <= 180) || (Rotation >= -180 && Rotation <= -90 - delta)))
|
flag = true;
|
break;
|
case "上":
|
if (RotationF >= 0 + delta)
|
flag = true;
|
break;
|
case "下":
|
if (RotationF <= 0 - delta)
|
flag = true;
|
break;
|
}
|
return flag;
|
|
|
}
|
|
|
#endregion
|
|
#region 判断可见性
|
private float Get_dist(PointF A, PointF B)
|
{
|
float dx = A.X - B.X;
|
float dy = A.Y - B.Y;
|
float dist = (float)Math.Sqrt(dx * dx + dy * dy);
|
return dist;
|
}
|
//判断A距离线段B和C的距离,如果超出了线段的范围,则返回到最近的端点的距离;距离线段中心点越远,返回的距离越大;
|
private float Get_dist(PointF A, PointF B, PointF C, float MaxOff)
|
{
|
//PointF A, PointF B,PointF C,求点A到B、C构成线段的中心点的距离
|
|
float dist_off = GetDistanceFromPointAToMidpointOfLineSegmentBC(A, B, C);
|
//使用dist_off 跟 线段A、B的长度比较,如果大于1/2,则返回MaxOff,否则按照比例返回
|
float dist_len = Get_dist(B, C);
|
if (dist_len < 5) dist_len = 5;
|
float dist_add = (dist_off / dist_len > 0.5 ? MaxOff : dist_off / dist_len * 2 * MaxOff);
|
|
float dx = C.X - B.X;
|
float dy = C.Y - B.Y;
|
float dist = (float)Math.Sqrt(dx * dx + dy * dy);
|
if (dist == 0) return Get_dist(A, B) + dist_add;
|
float t = ((A.X - B.X) * dx + (A.Y - B.Y) * dy) / (dist * dist);
|
if (t < 0) return Get_dist(A, B) + dist_add;
|
if (t > 1) return Get_dist(A, C) + dist_add;
|
float x = B.X + t * dx;
|
float y = B.Y + t * dy;
|
return Get_dist(A, new PointF(x, y)) + dist_add;
|
|
}
|
private float GetDistanceFromPointAToMidpointOfLineSegmentBC(PointF A, PointF B, PointF C)
|
{
|
// Calculate the midpoint of the line segment BC
|
PointF midpoint = new PointF((B.X + C.X) / 2, (B.Y + C.Y) / 2);
|
|
// Calculate the distance from point A to the midpoint
|
float dx = midpoint.X - A.X;
|
float dy = midpoint.Y - A.Y;
|
float distance = (float)Math.Sqrt(dx * dx + dy * dy);
|
|
return distance;
|
}
|
|
PointF PMin_Show, PMax_Show;
|
|
|
/// 判断是否在屏幕坐标内
|
|
/// <param name="screenPos"></param>
|
|
public bool isVisible(PointF MapPos)
|
{
|
if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y)
|
return false;
|
else
|
return true;
|
}
|
|
|
/// 判断是否在屏幕坐标内
|
|
/// <param name="screenPos"></param>
|
|
public bool isVisible(List<PointF> list_MapPos)
|
{
|
bool visible = false;
|
foreach (var MapPos in list_MapPos)
|
{
|
if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y)
|
{
|
|
}
|
else
|
{
|
visible = true;
|
return true;
|
}
|
|
}
|
|
return visible;
|
}
|
#endregion
|
|
}
|
public partial class MapViewer
|
{
|
|
#region 核心属性
|
TContainer TC = new TContainer();
|
|
|
/// 地图选项
|
|
public MapDimensions mapOption
|
{
|
get { return TC.mapOption; }
|
set { TC.mapOption = value; }
|
}
|
|
/// 地图选项_起始操作时
|
|
private MapDimensions mapOption0 = new MapDimensions();
|
|
/// 临时管网层
|
|
|
public Template _newTemplate
|
{
|
get { return TC.newTemplate; }
|
set { TC.newTemplate = value; }
|
}
|
|
|
|
public Template _Template
|
{
|
get { return TC.template; }
|
set
|
{
|
TC.template = value;
|
|
label_file.Text = TC.template?.filePath;
|
}
|
}
|
|
#endregion
|
#region 交互属性
|
|
/// 悬停对象
|
|
private List<IBaseViewModel> hoveredObjs = new List<IBaseViewModel>();
|
|
/// 选中对象
|
|
public List<IBaseViewModel> selectedObjs = new List<IBaseViewModel>();
|
|
|
private List<NodeViewModel> selectedNodes => selectedObjs.FindAll(o => o is NodeViewModel).Select(o => (NodeViewModel)o).ToList();
|
private List<LinkViewModel> selectedLinks => selectedObjs.FindAll(o => o is LinkViewModel).Select(o => (LinkViewModel)o).ToList();
|
|
MouseState _mouseState = MouseState.无;
|
private NodeViewModel _OperaNode = null;
|
public PointF mouseXY = new PointF(0, 0);
|
|
PointF DragStartPos;
|
PointF _ClickStartPos;
|
PointF RotaStartPos;
|
PointF BackGroudPicLeftPos;
|
bool _isPanning;
|
|
/// 拖拽选择
|
|
bool _isDragging;
|
bool _isRotating;
|
bool _isPainting;
|
|
|
PointF mousePosition;
|
// control+鼠标中间按下缩放
|
bool _isInsertingObject = false;
|
bool _isMovingObject = false;
|
bool _isPastingObject = false;
|
Cursor _lastCursor;
|
object _undoOldValue = null;
|
private List<PointF> polygonPoints = new List<PointF>();
|
|
private bool _isDrawingPolygon;
|
|
#endregion
|
#region 新增管网(辅助)
|
|
MapViewNetWork _NewNet
|
{
|
get
|
{
|
if (_newTemplate == null) _newTemplate = new Template();
|
if (_newTemplate.network == null) _newTemplate.network = new MapViewNetWork();
|
return _newTemplate.network;
|
}
|
}
|
#endregion
|
#region 显示选项(辅助)
|
|
|
private string _StartPoint = null;
|
private string _EndPoint = null;
|
//private bool __isEditMode = true;
|
|
public bool _IsEditMode
|
{
|
get { return this.mapOption?.isEditMode ?? true; }
|
set
|
{
|
toolStripComboBox_浏览模式.Text = value ? "编辑模式" : "浏览模式";
|
|
if (this.mapOption != null) this.mapOption.isEditMode = value;
|
转换为ToolStripMenuItem.Visible = _IsEditMode;
|
toolStripSeparator9.Visible = _IsEditMode;
|
删除ToolStripMenuItem.Visible = _IsEditMode;
|
删除ToolStripMenuItem1.Visible = _IsEditMode;
|
|
复制ToolStripMenuItem.Visible = _IsEditMode;
|
复制ToolStripMenuItem1.Visible = _IsEditMode;
|
粘贴ToolStripMenuItem.Visible = _IsEditMode;
|
粘贴ToolStripMenuItem1.Visible = _IsEditMode;
|
设置长度ToolStripMenuItem.Visible = _IsEditMode;
|
设为关闭ToolStripMenuItem.Visible = _IsEditMode;
|
设为立管点ToolStripMenuItem.Visible = _IsEditMode;
|
对齐ToolStripMenuItem.Visible = _IsEditMode;
|
对齐ToolStripMenuItem1.Visible = _IsEditMode;
|
|
toolStripButton_新建节点.Enabled = _IsEditMode;
|
toolStripButton_新建管线.Enabled = _IsEditMode;
|
toolStripButton_新建立管.Enabled = _IsEditMode;
|
toolStripButton_添加水库.Enabled = _IsEditMode;
|
toolStripButton_添加水池.Enabled = _IsEditMode;
|
toolStripButton_添加水表.Enabled = _IsEditMode;
|
toolStripButton_添加阀门.Enabled = _IsEditMode;
|
toolStripButton_重复器.Enabled = _IsEditMode;
|
|
|
|
}
|
}
|
|
|
|
public float Link_multiply
|
{
|
get
|
{
|
if (_Template == null || _Template.mapOption == null) return 1.0f;
|
return _Template.mapOption.Link_multiply;
|
}
|
set
|
{
|
if (_Template == null || _Template.mapOption == null) return; _Template.mapOption.Link_multiply = value;
|
}
|
}
|
|
public float junction_multiply
|
{
|
get
|
{
|
if (_Template == null || _Template.mapOption == null) return 1.0f;
|
return _Template.mapOption.junction_multiply;
|
}
|
set
|
{
|
if (_Template == null || _Template.mapOption == null) return; _Template.mapOption.junction_multiply = value;
|
}
|
}
|
[DisplayName("显示阀门")]
|
|
public bool _ShowValve
|
{
|
get
|
{
|
if (_Template == null || _Template.mapOption == null) return true;
|
return _Template.mapOption._ShowValve;
|
}
|
set
|
{
|
if (_Template == null || _Template.mapOption == null) return; _Template.mapOption._ShowValve = value;
|
}
|
}
|
[DisplayName("显示节点")]
|
public bool _ShowJunction
|
{
|
get
|
{
|
if (_Template == null || _Template.mapOption == null) return true;
|
return _Template.mapOption._ShowJunction;
|
}
|
set
|
{
|
|
if (_Template == null || _Template.mapOption == null) return; _Template.mapOption._ShowJunction = value;
|
}
|
}
|
string _filePath
|
{
|
get
|
{
|
if (string.IsNullOrEmpty(_Template?.filePath))
|
return null;
|
string path = _Template.filePath.TrimStart('\\');
|
return
|
Path.Combine(Directory.GetCurrentDirectory(), path);
|
}
|
//set
|
//{
|
|
//_Template.路径 = value;
|
//}
|
}
|
private MapViewNetWork _Network
|
{
|
get
|
{
|
return _Template?.network;
|
}
|
}
|
#endregion
|
#region 管网属性(辅助)
|
|
public List<NodeCalcModel> _Nodes
|
{
|
get { return _Network?.Nodes ?? new List<NodeCalcModel>(); }
|
|
}
|
|
public List<LinkCalcModel> _Links
|
{
|
get { return _Network?.Links ?? new List<LinkCalcModel>(); }
|
|
}
|
|
private List<Area> _areas = new List<Area>();
|
|
public List<Area> _Areas
|
{
|
get { return _areas; }
|
|
}
|
#endregion
|
#region 视角设置(辅助)
|
|
|
|
private const float MinZoom = 0.1f;
|
private const float MaxZoom = 1000.0f;
|
|
[DisplayName("缩放系数")]
|
public float zoom
|
{
|
get
|
{
|
return mapOption.zoom;
|
}
|
set
|
{
|
label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}";
|
mapOption.zoom = value;
|
}
|
}
|
[DisplayName("旋转角度")]
|
public double Rotation
|
{
|
get
|
{
|
return mapOption.rotation;
|
}
|
set
|
{
|
toolStripStatusLabel_rotation.Text = $"Rotation:({Rotation.ToString("0")},{RotationF.ToString("0")})";
|
//将旋转角度转换为-180~180
|
value = value % 360;
|
if (value > 180)
|
value -= 360;
|
else if (value < -180)
|
value += 360;
|
mapOption.rotation = value;
|
}
|
}
|
|
private double Rotation0 = 0;
|
|
public PointF MapCenter
|
{
|
get
|
{
|
return mapOption.Center;
|
}
|
set
|
{
|
label_center.Text = $"center:({MapCenter.X.ToString("0.00")} ,{MapCenter.Y.ToString("0.00")})";
|
mapOption.Center = value;
|
}
|
}
|
private PointF MapCenter0;
|
private bool is3Dview = false;
|
double 俯视角度_start = 90;
|
|
|
|
public bool Lock2DView
|
{
|
get
|
{
|
return mapOption.Lock2DView;
|
}
|
set
|
{
|
mapOption.Lock2DView = value;
|
}
|
}
|
|
|
|
/// 俯视线与底面的夹角,投影用sin
|
|
[DisplayName("俯视角度")]
|
public double RotationF
|
{
|
get
|
{
|
return mapOption.rotationF;
|
}
|
set
|
{
|
mapOption.rotationF = value;
|
}
|
}
|
|
public double 俯视弧度
|
{
|
get
|
{
|
return RotationF / 180 * Math.PI;
|
}
|
}
|
|
|
public PointF Zoom
|
{
|
get
|
{
|
return new PointF(zoom, -zoom);
|
}
|
}
|
|
|
private PointF Z(float z)
|
{
|
return new PointF(0, 0);
|
}
|
#endregion
|
#region 颜色分级(辅助)
|
public Colour NodeColour
|
{
|
set
|
{
|
var type = value.Type;
|
value.isChoosed = true;
|
_Template?.Colours?.RemoveAll(cl => cl.Type == type);
|
_Template.Colours.Add(value);
|
mapOption.ColourNode = type;
|
}
|
private get
|
{
|
return _Template?.Colours?.FirstOrDefault(cl => cl.isChoosed && cl.Type == mapOption.ColourNode);
|
}
|
}
|
public Colour LinkColour
|
{
|
set
|
{
|
var type = value.Type;
|
value.isChoosed = true;
|
_Template?.Colours?.RemoveAll(cl => cl.Type == type);
|
_Template.Colours.Add(value);
|
mapOption.ColourLink = type;
|
}
|
private get
|
{
|
return _Template?.Colours?.FirstOrDefault(cl => cl.isChoosed && cl.Type == mapOption.ColourLink);
|
}
|
}
|
|
//private bool __isOrtho = true;
|
|
#endregion
|
#region 正交模式
|
private bool _isOrtho
|
{
|
get
|
{
|
return mapOption.IsOrtho;
|
}
|
set
|
{
|
mapOption.IsOrtho = value;
|
if (mapOption.IsOrtho)
|
{
|
label_ZZ.Text = "正交模式:开";
|
}
|
else
|
{
|
label_ZZ.Text = "正交模式:关";
|
}
|
}
|
}
|
#endregion
|
#region 事件
|
//按帧数判断是否重绘,减少计算量(每帧最多重绘一次)
|
bool _timerDraw = false;
|
//按帧数判断鼠标悬停对象,减少计算量(每帧最多判断一次)
|
bool _mouseHoverCheckFlag = false;
|
#endregion
|
}
|
|
|
/// <summary>
|
/// 几何计算辅助类
|
class GraphHelper
|
{
|
public static Color getNodeColor(Colour colour, NodeViewModel node)
|
{
|
double value = 0;
|
Color color = Color.Gray;
|
|
switch (colour.Type)
|
{
|
case ColourType.节点自由压力:
|
value = node.EN_PRESSURE;
|
break;
|
case ColourType.节点绝对压力:
|
value = node.EN_HEAD;
|
break;
|
case ColourType.节点需水量:
|
value = node.EN_DEMAND;
|
break;
|
}
|
|
for (int i = 0; i < colour.Items.Count; i++)
|
{
|
if (colour.Items[i].DRange.IsInside(value))
|
{
|
color = colour.Items[i].value;
|
break;
|
}
|
}
|
return color;
|
}
|
public static Color getLinkColor(Colour colour, LinkViewModel link)
|
{
|
double value = 0;
|
Color color = Color.Gray;
|
switch (colour.Type)
|
{
|
case ColourType.管线流量:
|
value = link.EN_FLOW;
|
break;
|
case ColourType.管线流速:
|
value = link.EN_VELOCITY;
|
break;
|
}
|
|
for (int i = 0; i < colour.Items.Count; i++)
|
{
|
if (colour.Items[i].DRange.IsInside(value))
|
{
|
color = colour.Items[i].value;
|
break;
|
}
|
}
|
return color;
|
}
|
public static long GetUlongByPoint(PointF ps, float delta = 20, int MaxY = 2000)
|
{
|
return (long)((int)(ps.X / delta) + ((int)Math.Round(ps.Y / delta)) * MaxY / delta);
|
}
|
|
public static List<PointF> Get等分Nodes(PointF p1, PointF p2, int n)
|
{
|
// 计算线段长度
|
float len = (float)Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
|
if (len == 0) len = 0.00001f;
|
// 计算单位向量
|
PointF u = new PointF((p2.X - p1.X) / len, (p2.Y - p1.Y) / len);
|
|
// 计算间距
|
float d = len / (n + 1);
|
|
|
// 计算n等分点
|
List<PointF> nodes = new List<PointF>();
|
for (int i = 1; i < n + 1; i++)
|
{
|
PointF node = new PointF(p1.X + i * d * u.X, p1.Y + i * d * u.Y);
|
if (node.X == float.NaN || node.Y == float.NaN) node = p1;
|
nodes.Add(node);
|
}
|
|
return nodes;
|
}
|
|
public static PointF getRotatePoint(float px, float py, PointF center, PointF x, PointF y)
|
{
|
PointF p = new PointF(px, py);
|
|
return getRotatePoint(p, center, x, y);
|
}
|
|
private static PointF getRotatePoint(PointF p, PointF center, PointF x, PointF y)
|
{
|
float angle = (float)Math.Atan2(y.Y - x.Y, y.X - x.X);
|
float distance = (float)Math.Sqrt(Math.Pow(p.X - center.X, 2) + Math.Pow(p.Y - center.Y, 2));
|
float rotationAngle = (float)(Math.Atan2(p.Y - center.Y, p.X - center.X) + angle);
|
float rotatedX = center.X + distance * (float)Math.Cos(rotationAngle);
|
float rotatedY = center.Y + distance * (float)Math.Sin(rotationAngle);
|
return new PointF(rotatedX, rotatedY);
|
}
|
|
}
|
|
public class Prompt : Form
|
{
|
private static TextBox textBox;
|
private static Button okButton;
|
|
public static string ShowDialog(string text, string caption, string defaultTxt = "")
|
{
|
Form prompt = new Form()
|
{
|
Width = 200,
|
Height = 150,
|
FormBorderStyle = FormBorderStyle.FixedDialog,
|
Text = caption,
|
StartPosition = FormStartPosition.CenterScreen
|
};
|
|
Label textLabel = new Label() { Left = 20, Top = 20, Text = text };
|
textBox = new TextBox() { Left = 20, Top = 50, Width = 150 };
|
textBox.Text = defaultTxt;
|
okButton = new Button() { Text = "确定", Left = 75, Width = 75, Top = 80 };
|
okButton.Click += (sender, e) => { prompt.Close(); };
|
|
prompt.Controls.Add(textBox);
|
prompt.Controls.Add(textLabel);
|
prompt.Controls.Add(okButton);
|
prompt.ShowDialog();
|
|
return textBox.Text;
|
}
|
}
|
|
public class GlobalObject
|
{
|
public static PropertyForm PropertyForm;
|
public static MapViewer map;
|
public static bool LockSelect = false;
|
public static bool ApplyFilter = false;
|
}
|
|
|
partial class empty { }
|
|
//定义一个委托,用来存储void Draw(Graphics bufferG, Template template)
|
public delegate void DrawDelegate(Graphics bufferG, Template template);
|
|
public delegate void MouseDelegate(MouseEventArgs e);
|
|
|
public class TContainer
|
{
|
|
public MapDimensions mapOption = new MapDimensions();
|
|
public Template newTemplate = null;
|
|
public Template template = null;
|
|
}
|
|
public class Area : BaseModel, IBaseViewModel
|
{
|
public List<PointF> Points { get; set; }
|
|
|
public bool Selected { get; set; }
|
|
|
[Description("鼠标悬于上方")]
|
[DisplayName("鼠标悬于上方")]
|
|
public bool Hovered { get; set; }
|
|
|
|
|
|
[DisplayName("位置信息")]
|
|
|
|
|
public PointF Position { get; set; } = new PointF(0, 0);
|
|
|
|
public String regionName { get; set; } = null;
|
|
|
[Description("X坐标")]
|
[DisplayName("X坐标")]
|
[Browsable(true)]
|
public float X
|
{
|
get
|
{
|
return Position.X;
|
}
|
set
|
{
|
Position = new PointF(value, Position.Y);
|
}
|
}
|
|
[Description("Y坐标")]
|
[DisplayName("Y坐标")]
|
[Browsable(true)]
|
public float Y
|
{
|
get
|
{
|
return Position.Y;
|
}
|
set
|
{
|
Position = new PointF(Position.X, value);
|
}
|
}
|
|
|
[Description("标高")]
|
[DisplayName("标高")]
|
[Browsable(true)]
|
public float Elev { get; set; }
|
|
|
[Description("对象的等级")]
|
[DisplayName("级别")]
|
|
|
public int Level { get; set; } = 0;
|
|
[Description("对象的等级")]
|
[DisplayName("是否显示")]
|
public bool Visible { get; set; } = true;
|
|
|
|
|
|
public MapObjectType Type { get { return this.GetTypeString(); } }
|
|
|
|
[Description("ID类型")]
|
[DisplayName("ID类型")]
|
|
public string IDType => Type.ToString() + "\t" + ID;
|
|
|
|
[Description("标签")]
|
[DisplayName("标签")]
|
[Editor(typeof(MyEditor), typeof(UITypeEditor))]
|
public TagList Tags { get; set; } = null;
|
|
|
|
public MapObjectType GetTypeString()
|
{
|
if (this is JunctionViewModel) return MapObjectType.节点;
|
if (this is ReservoirViewModel) return MapObjectType.水库;
|
if (this is TankViewModel) return MapObjectType.水池;
|
if (this is MeterViewModel) return MapObjectType.水表;
|
if (this is NozzleViewModel) return MapObjectType.喷头;
|
if (this is ValveNodeViewModel) return MapObjectType.阀门点;
|
|
|
if (this is PipeViewModel) return MapObjectType.管线;
|
if (this is ValveViewModel) return MapObjectType.阀门;
|
if (this is RepeaterViewModel) return MapObjectType.重复器;
|
if (this is PumpViewModel) return MapObjectType.水泵;
|
if (this is PumpNodeViewModel) return MapObjectType.水泵点;
|
|
return MapObjectType.节点;
|
}
|
|
public bool isNode()
|
{
|
if (this is JunctionViewModel) return true;
|
if (this is ReservoirViewModel) return true;
|
if (this is TankViewModel) return true;
|
if (this is MeterViewModel) return true;
|
if (this is NozzleViewModel) return true;
|
return false;
|
}
|
}
|
|
public interface IBaseViewModel
|
{
|
|
[Description("对象的ID唯一标识")]
|
[DisplayName(" 编号 ")]
|
string ID { get; set; }
|
|
|
|
|
|
|
bool Selected { get; set; }
|
|
bool Hovered { get; set; }
|
|
|
|
|
[DisplayName("位置信息")]
|
|
PointF Position { get; set; }//= new PointF(0, 0);
|
|
|
|
String regionName { get; set; }//= null;
|
|
|
[Description("X坐标")]
|
[DisplayName("X坐标")]
|
[Browsable(true)]
|
float X { get; set; }
|
//{
|
//get
|
//{
|
//return Position.X;
|
//}
|
//set
|
//{
|
//Position = new PointF(value, Position.Y);
|
//}
|
//}
|
|
[Description("Y坐标")]
|
[DisplayName("Y坐标")]
|
[Browsable(true)]
|
float Y { get; set; }
|
//{
|
//get
|
//{
|
//return Position.Y;
|
//}
|
//set
|
//{
|
//Position = new PointF(Position.X, value);
|
//}
|
//}
|
|
|
[Description("标高")]
|
[DisplayName("标高")]
|
[Browsable(true)]
|
float Elev { get; set; }
|
|
|
[Description("对象的等级")]
|
[DisplayName("级别")]
|
//[Editor(typeof(MyPropertyEditor), typeof(UITypeEditor))]
|
|
int Level { get; set; } //= 0;
|
|
[Description("对象的等级")]
|
[DisplayName("是否显示")]
|
bool Visible { get; set; } //= true;
|
|
//
|
//[Description("标签集合")]
|
//[DisplayName("标签")]
|
//public string Tags { get; set; } = null;
|
|
|
|
|
MapObjectType Type { get; }// { get { return this.GetTypeString(); } }
|
|
//
|
|
[Description("ID类型")]
|
[DisplayName("ID类型")]
|
|
string IDType { get; }// => Type.ToString()+"\t"+ ID;
|
MapObjectType GetTypeString();
|
|
TagList Tags { get; set; }
|
|
//string TagsString { get; set; }
|
|
bool isNode();
|
|
|
}
|
|
public class TagList : List<string>
|
{
|
|
|
public override string ToString()
|
{
|
if (Count == 0)
|
return "null";
|
else
|
return string.Join(",", this);
|
}
|
|
//public TagList(string value):base(value.Split(','))
|
//{
|
//if (string.IsNullOrEmpty(value) || value == "null")
|
//{
|
//base.Clear();
|
//return;
|
//}
|
|
//}
|
public TagList()
|
{
|
}
|
public TagList(string value)
|
{
|
if (string.IsNullOrEmpty(value) || value == "null")
|
{
|
base.Clear();
|
return;
|
}
|
string[] tags = value.Split(',');
|
base.AddRange(tags);
|
}
|
}
|
|
public class MyEditor : UITypeEditor
|
{
|
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
|
{
|
return UITypeEditorEditStyle.Modal;
|
}
|
|
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
|
{
|
List<string> tags = value as List<string>;
|
|
// Create and show dialog
|
TagEditorForm form = new TagEditorForm(tags);
|
//form弹出时,位置在鼠标位置
|
form.StartPosition = FormStartPosition.Manual;
|
form.Location = new Point(Cursor.Position.X - form.Width + 10, Cursor.Position.Y - 10);
|
|
//if (form.ShowDialog() == DialogResult.OK)
|
//{
|
|
//}
|
form.ShowDialog();
|
return form.Tags;
|
//return base.EditValue(context, provider, value);
|
}
|
}
|
|
public class TagEditorForm : Form
|
{
|
public List<string> Tags { get; set; }
|
|
private ListBox listBox;
|
private TextBox tb_text;
|
|
public TagEditorForm(List<string> tags)
|
{
|
Tags = tags;
|
|
|
// Initialize ListBox
|
listBox = new ListBox();
|
listBox.DataSource = Tags;
|
listBox.Dock = DockStyle.Fill;
|
this.Controls.Add(listBox);
|
|
// Add buttons for add, remove, update operations
|
tb_text = new TextBox();
|
tb_text.Dock = DockStyle.Top;
|
|
this.Controls.Add(tb_text);
|
Button addButton = new Button();
|
addButton.Dock = DockStyle.Bottom;
|
addButton.Text = "添加";
|
addButton.Click += AddButton_Click;
|
this.Controls.Add(addButton);
|
|
Button removeButton = new Button();
|
removeButton.Dock = DockStyle.Bottom;
|
removeButton.Text = "删除";
|
removeButton.Click += RemoveButton_Click;
|
this.Controls.Add(removeButton);
|
|
Button updateButton = new Button();
|
updateButton.Dock = DockStyle.Bottom;
|
updateButton.Text = "更新";
|
updateButton.Click += UpdateButton_Click;
|
this.Controls.Add(updateButton);
|
|
Panel panel = new Panel();
|
updateButton.Dock = DockStyle.Bottom;
|
this.Controls.Add(panel);
|
|
Button btn_ok = new Button();
|
btn_ok.Dock = DockStyle.Left;
|
btn_ok.Click += (o, e) => { this.DialogResult = DialogResult.OK; };
|
btn_ok.Text = "确定";
|
panel.Controls.Add(btn_ok);
|
|
Button btn_cancel = new Button();
|
btn_cancel.Dock = DockStyle.Right;
|
btn_ok.Click += (o, e) => { this.DialogResult = DialogResult.Cancel; };
|
btn_cancel.Text = "取消";
|
panel.Controls.Add(btn_cancel);
|
|
listBox.SelectedIndexChanged += (o, e) =>
|
{
|
if (listBox.SelectedItem != null)
|
tb_text.Text = listBox.SelectedItem.ToString();
|
};
|
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
}
|
|
private void AddButton_Click(object sender, EventArgs e)
|
{
|
|
// 在listBox中按tb_text的内容,添加新的tag
|
if (tb_text.Text != null && tb_text.Text != "")
|
{
|
if (Tags == null)
|
Tags = new List<string>();
|
Tags.Add(tb_text.Text);
|
listBox.DataSource = null;
|
listBox.DataSource = Tags;
|
}
|
|
}
|
|
private void RemoveButton_Click(object sender, EventArgs e)
|
{
|
//删除listBox中选中的tag
|
if (listBox.SelectedItem != null)
|
{
|
|
Tags.Remove(listBox.SelectedItem.ToString());
|
listBox.DataSource = null;
|
listBox.DataSource = Tags;
|
}
|
// Remove tag
|
}
|
|
private void UpdateButton_Click(object sender, EventArgs e)
|
{
|
// 在listBox中按tb_text的内容,更新tag,但是不改变顺序
|
if (listBox.SelectedItem != null)
|
{
|
|
Tags[listBox.SelectedIndex] = tb_text.Text;
|
listBox.DataSource = null;
|
listBox.DataSource = Tags;
|
}
|
}
|
}
|
|
|
public class LinkViewModel : LinkCalcModel, IBaseViewModel
|
{
|
#region 构造函数
|
|
|
public LinkViewModel()
|
{
|
|
}
|
public LinkViewModel(PointF startPoint, PointF endPoint)
|
{
|
StartNode = new NodeViewModel(startPoint);
|
EndNode = new NodeViewModel(endPoint);
|
}
|
public LinkViewModel(PointF startPoint, PointF endPoint, List<PointF> points)
|
{
|
StartNode = new NodeViewModel(startPoint);
|
EndNode = new NodeViewModel(endPoint);
|
|
}
|
#endregion
|
#region 属性
|
|
|
|
[DisplayName("编号")]
|
[Browsable(true)]
|
public new string ID { get { return base.ID; } set { base.ID = value; } }
|
|
|
[DisplayName("名称")]
|
[Browsable(true)]
|
public new string Name { get { return base.Name; } set { base.Name = value; } }
|
|
|
[DisplayName("起始节点")]
|
[Browsable(true)]
|
public string Node1
|
{
|
get
|
{
|
return base.Node1;
|
}
|
set
|
{
|
|
base.Node1 = value;
|
}
|
}
|
|
|
|
[DisplayName("终止节点")]
|
[Browsable(true)]
|
public string Node2
|
{
|
get
|
{
|
return base.Node2;
|
}
|
set
|
{
|
base.Node2 = value;
|
}
|
}
|
|
|
|
public NodeViewModel StartNode { get { return (NodeViewModel)base.StartNode; } set { base.StartNode = value; } }
|
|
|
public NodeViewModel EndNode { get { return (NodeViewModel)base.EndNode; } set { base.EndNode = value; } }
|
|
private PointF _position { get; set; } = new PointF(0, 0);
|
public PointF Position
|
{
|
get
|
{
|
{
|
if (StartNode == null || EndNode == null) return _position;
|
var x = (StartNode.Position.X + EndNode.Position.X) / 2;
|
var y = (StartNode.Position.Y + EndNode.Position.Y) / 2;
|
_position = new PointF(x, y);
|
|
|
}
|
return _position;
|
}
|
set
|
{
|
}
|
|
}
|
|
|
|
|
public List<PointF> Points { get { return new List<PointF>() { StartNode.Position, EndNode.Position }; } }
|
public PointF[] ToArray(bool is3Dview = false)
|
{
|
if (!is3Dview)
|
return new PointF[] { new PointF((float)(StartNode.X), (float)(StartNode.Y)), new PointF((float)(EndNode.X), (float)(EndNode.Y)) };
|
else
|
return new PointF[] { new PointF((float)(StartNode.X), (float)(StartNode.Y - 2 * StartNode.Elev)), new PointF((float)(EndNode.X), (float)(EndNode.Y - 2 * EndNode.Elev)) };
|
}
|
|
|
|
[DisplayName("标高(m)")]
|
|
public float Elev
|
{
|
get
|
{
|
if (StartNode == null || EndNode == null) return 0;
|
return (StartNode.Elev + EndNode.Elev) / 2;
|
}
|
set
|
{
|
|
}
|
}
|
|
[Category("计算参数")]
|
[DisplayName("初始状态")]
|
[Browsable(true)]
|
public StatusType Status
|
{
|
get { return base.Status; }
|
set { base.Status = value; }
|
}
|
|
|
|
[DisplayName("口径(mm)")]
|
[Browsable(true)]
|
public new float Diameter { get { return base.Diameter; } set { base.Diameter = value; } }
|
|
|
[DisplayName("长度(m)")]
|
[Browsable(true)]
|
|
/// 长度
|
|
public float Length
|
{
|
get
|
{
|
return base.Length;
|
|
}
|
set
|
{
|
base.Length = value;
|
}
|
}
|
|
|
|
public String regionName { get; set; } = null;
|
|
|
[Description("X坐标")]
|
[DisplayName("X坐标")]
|
[Browsable(true)]
|
public float X
|
{
|
get
|
{
|
return Position.X;
|
}
|
set
|
{
|
|
}
|
}
|
|
[Description("Y坐标")]
|
[DisplayName("Y坐标")]
|
[Browsable(true)]
|
public float Y
|
{
|
get
|
{
|
return Position.Y;
|
}
|
set
|
{
|
|
}
|
}
|
|
|
|
[Description("对象的等级")]
|
[DisplayName("级别")]
|
|
|
public int Level { get; set; } = 0;
|
|
[Description("对象的等级")]
|
[DisplayName("是否显示")]
|
public bool Visible { get; set; } = true;
|
|
|
[Description("标签")]
|
[DisplayName("标签")]
|
[Editor(typeof(MyEditor), typeof(UITypeEditor))]
|
public TagList Tags { get; set; } = null;
|
|
|
|
|
|
|
|
public MapObjectType Type { get { return this.GetTypeString(); } }
|
|
|
|
[Description("ID类型")]
|
[DisplayName("ID类型")]
|
|
#endregion
|
#region 方法
|
|
|
public string IDType => Type.ToString() + "\t" + ID;
|
|
public MapObjectType GetTypeString()
|
{
|
if (this is JunctionViewModel) return MapObjectType.节点;
|
if (this is ReservoirViewModel) return MapObjectType.水库;
|
if (this is TankViewModel) return MapObjectType.水池;
|
if (this is MeterViewModel) return MapObjectType.水表;
|
if (this is NozzleViewModel) return MapObjectType.喷头;
|
if (this is ValveNodeViewModel) return MapObjectType.阀门点;
|
|
|
if (this is PipeViewModel) return MapObjectType.管线;
|
if (this is ValveViewModel) return MapObjectType.阀门;
|
if (this is RepeaterViewModel) return MapObjectType.重复器;
|
if (this is PumpViewModel) return MapObjectType.水泵;
|
if (this is PumpNodeViewModel) return MapObjectType.水泵点;
|
|
return MapObjectType.节点;
|
}
|
|
public bool isNode()
|
{
|
if (this is JunctionViewModel) return true;
|
if (this is ReservoirViewModel) return true;
|
if (this is TankViewModel) return true;
|
if (this is MeterViewModel) return true;
|
if (this is NozzleViewModel) return true;
|
return false;
|
}
|
#endregion
|
}
|
|
|
public class NodeViewModel : NodeCalcModel, IBaseViewModel
|
{
|
#region 构造函数
|
public NodeViewModel()
|
{
|
}
|
public NodeViewModel(PointF position)
|
{
|
Position = position;
|
}
|
public NodeViewModel(int X, int Y)
|
{
|
Position = new PointF(X, Y);
|
}
|
#endregion
|
|
#region 属性
|
|
|
|
[DisplayName("编号")]
|
[Browsable(true)]
|
public new string ID { get { return base.ID; } set { base.ID = value; } }
|
|
|
[DisplayName("名称")]
|
[Browsable(true)]
|
public new string Name { get { return base.Name; } set { base.Name = value; } }
|
|
|
public PointF3D Position3D
|
{
|
get
|
{
|
return new PointF3D(X, Y, Elev);
|
}
|
set
|
{
|
Position = new PointF(value.X, value.Y);
|
Elev = value.Z;
|
}
|
|
}
|
|
|
[Description("X坐标")]
|
[DisplayName("X坐标")]
|
[Browsable(true)]
|
public new float X
|
{
|
get
|
{
|
return base.X;
|
}
|
set
|
{
|
base.X = value;
|
}
|
}
|
|
[Description("Y坐标")]
|
[DisplayName("Y坐标")]
|
[Browsable(true)]
|
public new float Y
|
{
|
get
|
{
|
return base.Y;
|
}
|
set
|
{
|
base.Y = value;
|
}
|
}
|
|
|
[Description("标高(m)")]
|
[DisplayName("标高(m)")]
|
[Browsable(true)]
|
public new float Elev { get { return base.Elev; } set { base.Elev = value; } }
|
|
|
|
public MapObjectType Type { get { return this.GetTypeString(); } }
|
|
[Category("计算参数")]
|
[Description("最大口径(mm)")]
|
[DisplayName("最大口径(mm)")]
|
|
public virtual float MaxDiameter { get; set; } = 0;
|
|
|
|
[Category("计算参数")]
|
[Description("需水量(m³/h)")]
|
[DisplayName("需水量(m³/h)")]
|
[Browsable(true)]
|
public virtual float Demand { get; set; }
|
|
|
/// 模式的编号
|
|
[Category("计算参数")]
|
[Description("用水量模式的编号")]
|
[DisplayName("模式编号")]
|
[Browsable(true)]
|
public virtual string PatternID { get; set; }
|
|
|
|
|
[DisplayName("链表清单")]
|
[Browsable(true)]
|
|
public List<LinkCalcModel> Links
|
{
|
get
|
{
|
return base.Links;
|
}
|
set
|
{
|
base.Links = value;
|
}
|
|
}
|
|
public List<LinkViewModel> ViewLinks
|
{
|
get
|
{
|
return base.Links.Select(oo => oo as LinkViewModel).ToList();
|
}
|
|
}
|
|
|
|
|
[DisplayName("位置信息")]
|
|
public PointF Position
|
{
|
get { return new PointF(X, Y); }
|
set { if (value != null) X = value.X; Y = value.Y; }
|
}
|
|
|
[Description("标签")]
|
[DisplayName("标签")]
|
[Editor(typeof(MyEditor), typeof(UITypeEditor))]
|
public TagList Tags { get; set; } = null;
|
|
|
|
|
|
public String regionName { get; set; } = null;
|
|
|
|
|
[Description("对象的等级")]
|
[DisplayName("级别")]
|
|
|
public int Level { get; set; } = 0;
|
|
[Description("对象的等级")]
|
[DisplayName("是否显示")]
|
public bool Visible { get; set; } = true;
|
|
|
|
|
|
|
[Description("ID类型")]
|
[DisplayName("ID类型")]
|
|
public string IDType => Type.ToString() + "\t" + ID;
|
|
#endregion
|
|
#region 方法
|
public void Move(Vector3 vector)
|
{
|
X += vector.X;
|
Y += vector.Y;
|
Elev += vector.Z;
|
}
|
|
|
public MapObjectType GetTypeString()
|
{
|
if (this is JunctionViewModel) return MapObjectType.节点;
|
if (this is ReservoirViewModel) return MapObjectType.水库;
|
if (this is TankViewModel) return MapObjectType.水池;
|
if (this is MeterViewModel) return MapObjectType.水表;
|
if (this is NozzleViewModel) return MapObjectType.喷头;
|
if (this is ValveNodeViewModel) return MapObjectType.阀门点;
|
|
|
if (this is PipeViewModel) return MapObjectType.管线;
|
if (this is ValveViewModel) return MapObjectType.阀门;
|
if (this is RepeaterViewModel) return MapObjectType.重复器;
|
if (this is PumpViewModel) return MapObjectType.水泵;
|
if (this is PumpNodeViewModel) return MapObjectType.水泵点;
|
|
return MapObjectType.节点;
|
}
|
|
public bool isNode()
|
{
|
if (this is JunctionViewModel) return true;
|
if (this is ReservoirViewModel) return true;
|
if (this is TankViewModel) return true;
|
if (this is MeterViewModel) return true;
|
if (this is NozzleViewModel) return true;
|
return false;
|
}
|
public string ToEmitterString()
|
{
|
if (this is NozzleViewModel n)
|
{
|
if (n.FlowCoefficient > 0)
|
return $"{ID}\t{n.FlowCoefficient * Math.Pow(10 / 101.972, 0.5) / 1000 * 60}\r\n";
|
}
|
return null;
|
}
|
|
#endregion
|
|
|
}
|
|
public static class Copy
|
{
|
|
public static T DeepCopy<T>(this T obj)
|
{
|
dynamic retval;
|
using (MemoryStream ms = new MemoryStream())
|
{
|
BinaryFormatter bf = new BinaryFormatter();
|
//序列化成流
|
bf.Serialize(ms, obj);
|
ms.Seek(0, SeekOrigin.Begin);
|
//反序列化成对象
|
retval = bf.Deserialize(ms);
|
ms.Close();
|
}
|
return (T)retval;
|
}
|
}
|
|
|
public class Dataset
|
{
|
//设置Dataset的default值
|
|
|
|
public static List<string> listString = new List<string>() { "流量扬程曲线", "流量功率曲线", "流量效率曲线" };
|
public Dataset(string name, PumpViewModel pump, int Degree = 2)
|
{
|
Name = name;
|
this.pump = pump;
|
this.degree = Degree;
|
}
|
|
public override string ToString()
|
{
|
StringBuilder txt = new StringBuilder();
|
foreach (PointF point in _data)
|
{
|
txt.AppendLine($"{Name}\t{point.X}\t{point.Y}");
|
}
|
return txt.ToString();
|
}
|
//public Dataset()
|
//{
|
|
//}
|
public Color Color
|
{
|
get
|
{
|
switch (Name)
|
{
|
case "流量扬程曲线":
|
return Color.Blue;
|
//break;
|
case "流量功率曲线":
|
return Color.Orange;
|
//break;
|
case "流量效率曲线":
|
return Color.Red;
|
//break;
|
default:
|
return Color.Blue;
|
}
|
|
}
|
|
}
|
public string Name { get; set; }
|
|
|
public List<PointF> _data = new List<PointF>();
|
|
int FitTimes = 2;
|
|
public List<PointF> Data
|
{
|
get
|
{
|
|
if (pump == null || pump.额定转速 == 0) return _data;
|
float eg = (float)pump.当前转速 / (float)pump.额定转速;
|
if (eg >= 1) return _data;
|
else
|
{
|
switch (Name)
|
{
|
case "流量扬程曲线":
|
return _data.Select(p => { p.X *= eg; p.Y *= eg * eg; return p; }).ToList();
|
case "流量功率曲线":
|
return _data.Select(p => { p.X *= eg; p.Y *= eg * eg * eg; return p; }).ToList();
|
case "流量效率曲线":
|
var c1 = pump.Datasets["流量扬程曲线"];
|
var c2 = pump.Datasets["流量功率曲线"];
|
if (c1.IsFitted && c2.IsFitted && c1.Data.Count == c2.Data.Count)
|
{
|
List<PointF> points = new List<PointF>();
|
for (int i = 0; i < c1.Data.Count; i++)
|
{
|
float x = c1.Data[i].X;
|
float y = x * c1.Data[i].Y / c2.Data[i].Y / 3.6f;
|
points.Add(new PointF(x, y));
|
|
//功率=流量* 扬程 / 效率 / 3.6f
|
//效率=流量* 扬程 / 功率 / 3.6f
|
}
|
return points;
|
}
|
else
|
{
|
return _data;
|
}
|
|
default:
|
return _data;
|
}
|
|
|
|
}
|
}
|
set
|
{
|
IsFitted = false;
|
_data = value;
|
}
|
}
|
|
public int degree { get { return FitTimes; } set { if (FitTimes != value) this.IsFitted = false; FitTimes = value; } }
|
|
public List<double> ForumParams = null;
|
|
|
public DenseVector coefficients = null; // 存储多项式系数
|
|
public static double ErrNum { get { return -1; } }
|
|
public static double stepNum { get { return 800; } }
|
|
private double step { get { return (range_X.Max - range_X.Min) / stepNum; } }
|
|
|
[NonSerialized]
|
|
public PumpViewModel pump = null;
|
|
|
|
|
/// 不需要读取
|
|
public string Legend
|
{
|
get
|
{
|
switch (Name)
|
{
|
case "流量扬程曲线":
|
return "Legend1";
|
case "流量功率曲线":
|
return "Legend1";
|
case "流量效率曲线":
|
return "Legend1";
|
|
}
|
return "Legend1";
|
}
|
}
|
|
public void CurveFit()
|
{
|
|
if (!HasData)
|
{
|
IsFitted = false;
|
return;
|
}
|
|
coefficients = Fit.Polynomial(Data.Select(p => (double)p.X).ToArray(), Data.Select(p => (double)p.Y).ToArray(), degree);
|
|
if (range_X == null)
|
{
|
range_X = new DRange(double.MaxValue, double.MinValue);
|
Data.ForEach(p =>
|
{
|
if (range_X.Min > p.X) range_X.Min = p.X;
|
if (range_X.Max < p.X) range_X.Max = p.X;
|
});
|
}
|
IsFitted = true;
|
}
|
public double Evaluate(double x)
|
{
|
if (!IsFitted) return ErrNum;
|
// 计算多项式在点 x 处的取值
|
double y = 0;
|
for (int i = 0; i < coefficients.Count; i++)
|
{
|
y += coefficients[i] * Math.Pow(x, i);
|
}
|
return y;
|
}
|
|
|
double Solve(double y)
|
{
|
List<PointF> points = FittedCurve.ToList();
|
PointF prevPoint = PointF.Empty;
|
PointF nextPoint = PointF.Empty;
|
|
foreach (var point in points)
|
{
|
if (point.Y == y)
|
{
|
return point.X;
|
}
|
else if (point.Y > y)
|
{
|
nextPoint = point;
|
}
|
else
|
{
|
prevPoint = point;
|
break;
|
}
|
}
|
|
if (prevPoint.IsEmpty)
|
{
|
return points[points.Count - 1].X; //throw new Exception("No valid interpolation range found.");
|
}
|
else if (nextPoint.IsEmpty)
|
{
|
return points[0].X;
|
}
|
|
double xDiff = nextPoint.X - prevPoint.X;
|
double yDiff = nextPoint.Y - prevPoint.Y;
|
double slope = yDiff / xDiff;
|
double x = prevPoint.X + (y - prevPoint.Y) / slope;
|
if (double.IsNaN(x)) return ErrNum;
|
else
|
return x;
|
}
|
|
public double Evaluate_Solve(double y)
|
{
|
if (!IsFitted) return ErrNum;
|
if (degree == 2) // 多项式次数
|
{
|
if (!is_Yvalue_validate(y)) return ErrNum;
|
|
|
double a = coefficients[2]; // 二次项系数
|
double b = coefficients[1]; // 一次项系数
|
double c = coefficients[0] - y; // 常数项系数减去给定的 y 值
|
|
|
var roots = MathSolver.Solve(a, b, c);
|
if (roots == null) return ErrNum;
|
else return roots.Max();
|
|
}
|
else if (degree == 3)
|
{
|
double a = coefficients[3]; // 3次项系数
|
double b = coefficients[2]; // 2次项系数
|
double c = coefficients[1]; // 1次项系数
|
double d = coefficients[0] - y;// 常数项系数减去给定的 y 值
|
var roots = MathSolver.Solve(a, b, c, d);
|
if (roots == null) return ErrNum;
|
else return roots.Max();
|
}
|
else
|
{
|
|
return Solve(y);
|
}
|
}
|
|
|
|
public double YMax
|
{
|
get
|
{
|
if (!IsFitted) return ErrNum;
|
double a = coefficients[degree];
|
double b = coefficients[degree - 1];
|
double c = coefficients[0];
|
double delta = b * b - 4 * a * c;
|
double minExtremePoint = -b / (2 * a);// 计算导函数的零点
|
double maxValue = 0;
|
if (a < 0)
|
|
maxValue = -delta / (4 * a) + c;
|
else
|
maxValue = a * minExtremePoint * minExtremePoint + b * minExtremePoint + c;// 计算最小值
|
return maxValue;
|
}
|
}
|
public double YdataMax
|
{
|
get
|
{
|
double max = -99999;
|
foreach (var p in Data)
|
{
|
if (max < p.Y) max = p.Y;
|
}
|
return max;
|
}
|
}
|
public bool is_Yvalue_validate(double y)
|
{
|
if (!IsFitted) return false;
|
double a = coefficients[degree];
|
if (a < 0)
|
|
return y <= YMax;
|
else
|
return y >= YMax;
|
}
|
|
|
/// X显示的范围
|
|
public DRange range_X;
|
|
|
|
/// Y显示的范围
|
|
public DRange range_Y;
|
public bool HasData { get { return Data.Count >= 3; } }
|
public bool IsFitted = false;
|
public List<PointF> FittedCurve
|
{
|
get
|
{
|
if (range_X == null) return null;
|
List<PointF> doubles = new List<PointF>();
|
for (double x = range_X.Min; x <= range_X.Max; x += step)
|
{
|
double y = Evaluate(x);
|
doubles.Add(new PointF((float)x, (float)y));
|
}
|
return doubles;
|
|
}
|
|
}
|
public List<PointF> FittedCurvebyRange(DRange range)
|
{
|
List<PointF> doubles = new List<PointF>();
|
|
if (range == null)
|
{
|
range = new DRange();
|
range.Min = range_X.Min;
|
range.Max = range_X.Max;
|
}
|
var step = (range.Max - range.Min) / stepNum;
|
for (double x = range.Min; x <= range.Max; x += step)
|
{
|
double y = Evaluate(x);
|
doubles.Add(new PointF((float)x, (float)y));
|
}
|
return doubles;
|
}
|
|
|
}
|
public class Default
|
{
|
static string _filePath = Path.Combine(Directory.GetCurrentDirectory(), @"default.ini");
|
public NodeViewModel junction;
|
public ReservoirViewModel reservoir;
|
public TankViewModel tank;
|
public MeterViewModel meter;
|
public NozzleViewModel nozzle;
|
public LinkViewModel pipe;
|
public ValveViewModel valve;
|
public RepeaterViewModel repeater;
|
public PumpViewModel pump;
|
public static Default GetfaultINI()
|
{
|
StreamReader sr = new StreamReader(_filePath);
|
string json = sr.ReadToEnd();
|
sr.Close();
|
return JsonConvert.DeserializeObject<Default>(json);
|
|
}
|
public void SaveFile()
|
{
|
StreamWriter sw = new StreamWriter(_filePath);
|
sw.WriteLine(JsonConvert.SerializeObject(this));
|
sw.Close();
|
}
|
|
public static Dictionary<MapObjectType, string> PreName = new Dictionary<MapObjectType, string>()
|
{
|
{MapObjectType.节点,"J" },
|
{MapObjectType.水库,"R" },
|
{MapObjectType.水池,"T" },
|
{MapObjectType.水表,"M" },
|
{MapObjectType.喷头,"N" },
|
{MapObjectType.管线,"P" },
|
{MapObjectType.阀门,"V" },
|
{MapObjectType.重复器,"Rp" },
|
{MapObjectType.水泵,"Pump" },
|
{MapObjectType.阀门点,"Vn" },
|
};
|
public static string GetPreString(IBaseViewModel obj)
|
{
|
return PreName[obj.Type];
|
}
|
}
|
|
|
public static class Global
|
{
|
|
|
public static List<MapObjectRecord> mapObjectRecords = new List<MapObjectRecord>();
|
public static int RecordIndex = 0;
|
public static List<string> curveStrings = new List<string>() { "流量扬程曲线", "流量功率曲线", "流量效率曲线" };
|
public static void ClearFileReadOnly(string filePath)
|
{
|
if (File.Exists(filePath))
|
{
|
// 获取当前文件属性
|
FileAttributes attributes = File.GetAttributes(filePath);
|
|
// 如果文件被设置为只读,则移除只读属性
|
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
{
|
attributes &= ~FileAttributes.ReadOnly; // 移除只读标志
|
|
// 设置新的文件属性
|
File.SetAttributes(filePath, attributes);
|
|
|
}
|
|
}
|
}
|
}
|
|
|
public static class GlobalExtension
|
{
|
public static Type GetObjType(this MapObjectType type)
|
{
|
switch (type)
|
{
|
case MapObjectType.全部: return null;
|
case MapObjectType.节点: return typeof(JunctionViewModel);
|
case MapObjectType.水表: return typeof(MeterViewModel);
|
case MapObjectType.水库: return typeof(ReservoirViewModel);
|
case MapObjectType.水池: return typeof(TankViewModel);
|
case MapObjectType.喷头: return typeof(NozzleViewModel);
|
case MapObjectType.管线: return typeof(PipeViewModel);
|
case MapObjectType.阀门: return typeof(ValveViewModel);
|
case MapObjectType.重复器: return typeof(RepeaterViewModel);
|
case MapObjectType.水泵: return typeof(PumpViewModel);
|
case MapObjectType.阀门点: return typeof(ValveNodeViewModel);
|
case MapObjectType.水泵点: return typeof(PumpNodeViewModel);
|
default: return null;
|
}
|
|
}
|
|
|
}
|
public class MapObjectRecord
|
{
|
public IBaseViewModel mapObject { get; set; }
|
public string ValueName { get; set; }
|
|
public dynamic Value { get; set; }
|
|
}
|
|
public class MapDimensions
|
{
|
|
|
[Category("视角")]
|
[DisplayName("中心")]
|
[Browsable(true)]
|
public PointF Center { get; set; }
|
|
[Category("视角")]
|
[DisplayName("缩放")]
|
[Browsable(true)]
|
public float zoom { get; set; } = 0.1f;
|
|
[Category("视角")]
|
[DisplayName("旋转角度")]
|
[Browsable(true)]
|
public double rotation { get; set; } = 0;
|
|
|
private double _rotationF;
|
[Category("视角")]
|
[DisplayName("俯视角度")]
|
[Browsable(true)]
|
public double rotationF
|
{
|
get
|
{
|
if (Lock2DView) _rotationF = 90;
|
return _rotationF;
|
}
|
set
|
{
|
_rotationF = value;
|
if (Lock2DView) _rotationF = 90;
|
}
|
}
|
|
[Category("视角")]
|
[DisplayName("显示楼层")]
|
[Browsable(true)]
|
public int ShowFloor { get; set; } = int.MinValue;
|
|
[Category("视角")]
|
[DisplayName("显示背景")]
|
[Browsable(true)]
|
public bool isShowPic { get; set; } = true;
|
|
|
|
public bool isAutoBackgroundImage = false;
|
|
|
[Category("视角")]
|
[DisplayName("显示最不利点")]
|
[Browsable(true)]
|
public bool isShowUnfavor { get; set; } = true;
|
|
//
|
//public int NodeColourIndex { get; set; } = 0;
|
|
//
|
//public int LinkColourIndex { get; set; } = 0;
|
|
[Category("视角")]
|
[DisplayName("锁定平面视角")]
|
[Browsable(true)]
|
public bool Lock2DView { get; set; } = false;
|
|
|
/// 编辑模式true,浏览模式false;默认值:true;浏览模式下,不能编辑模型
|
public bool isEditMode { get; set; } = true;
|
|
|
|
/// 正交模式
|
public bool IsOrtho { get; set; } = true;
|
|
|
/// 显示的颜色分级
|
public ColourType ColourNode { get; set; } = ColourType.无;
|
public ColourType ColourLink { get; set; } = ColourType.无;
|
|
public MapDimensions Copy()
|
{
|
MapDimensions mv = new MapDimensions();
|
mv.Center = Center;
|
mv.zoom = zoom;
|
mv.rotation = rotation;
|
mv.rotationF = rotationF;
|
mv.ShowFloor = ShowFloor;
|
return mv;
|
}
|
|
}
|
|
public class UndoRedoCommand<T>
|
{
|
private readonly Action<T> _undoAction;
|
private readonly Action<T> _redoAction;
|
private readonly T _oldValue;
|
private readonly T _newValue;
|
|
public UndoRedoCommand(T oldValue, T newValue, Action<T> undoAction, Action<T> redoAction)
|
{
|
_oldValue = oldValue;
|
_newValue = newValue;
|
_undoAction = undoAction;
|
_redoAction = redoAction;
|
}
|
|
public void Undo()
|
{
|
_undoAction?.Invoke(_oldValue);
|
}
|
|
public void Redo()
|
{
|
_redoAction?.Invoke(_newValue);
|
}
|
}
|
|
public static class MapObjectExtensions
|
{
|
private static readonly Stack<UndoRedoCommand<object>> _undoStack = new Stack<UndoRedoCommand<object>>();
|
private static readonly Stack<UndoRedoCommand<object>> _redoStack = new Stack<UndoRedoCommand<object>>();
|
|
public static void AddUndoRedoSupport(this List<IBaseViewModel> list, PropertyGrid propertyGrid)
|
{
|
propertyGrid.PropertyValueChanged += (sender, e) =>
|
{
|
if (propertyGrid.SelectedObject is IBaseViewModel obj && obj != null)
|
{
|
var propertyDescriptor = TypeDescriptor.GetProperties(obj)[e.ChangedItem.PropertyDescriptor.Name];
|
var oldValue = e.OldValue;//propertyDescriptor.GetValue(obj);
|
var newValue = e.ChangedItem.Value;
|
|
var undoAction = new Action<object>(v => propertyDescriptor.SetValue(obj, v));
|
var redoAction = new Action<object>(v => propertyDescriptor.SetValue(obj, v));
|
|
|
var command = new UndoRedoCommand<object>(oldValue, newValue, undoAction, redoAction);
|
|
_undoStack.Push(command);
|
_redoStack.Clear();
|
}
|
};
|
}
|
public static void AddCommand(UndoRedoCommand<object> command)
|
{
|
_undoStack.Push(command);
|
_redoStack.Clear();
|
}
|
private static List<IBaseViewModel> getObj(object o)
|
{
|
var list = o as List<IBaseViewModel>;
|
if (list == null)
|
{
|
if (o is List<NodeViewModel> list_nodes) list = new List<IBaseViewModel>(list_nodes);
|
if (o is List<LinkViewModel> list_links) list = new List<IBaseViewModel>(list_links);
|
}
|
return list;
|
}
|
public static void AddCommand(object o, string PropertyDescriptorName, dynamic oldValue, dynamic newValue)
|
{
|
switch (PropertyDescriptorName)
|
{
|
case "Add":
|
{
|
|
var net = o as MapViewNetWork;
|
var undoAction = new Action<object>(v => net.Remove(newValue));
|
var redoAction = new Action<object>(v => net.Add(newValue));
|
var command = new UndoRedoCommand<object>(oldValue, newValue, undoAction, redoAction);
|
AddCommand(command);
|
}
|
return;
|
case "Remove":
|
{
|
var net = o as MapViewNetWork;
|
var undoAction = new Action<object>(v => net.Add(newValue));
|
var redoAction = new Action<object>(v => net.Remove(newValue));
|
var command = new UndoRedoCommand<object>(oldValue, newValue, undoAction, redoAction);
|
AddCommand(command);
|
}
|
return;
|
case "Map":
|
{
|
var mv = o as MapDimensions;
|
var undoAction = new Action<object>(v =>
|
{
|
mv.Center = oldValue.Center;
|
mv.zoom = oldValue.zoom;
|
mv.rotation = oldValue.rotation;
|
mv.rotationF = oldValue.rotationF;
|
|
});
|
var redoAction = new Action<object>(v =>
|
{
|
mv.Center = newValue.Center;
|
mv.zoom = newValue.zoom;
|
mv.rotation = newValue.rotation;
|
mv.rotationF = newValue.rotationF;
|
|
});
|
//object oldValue=propertyDescriptor.GetValue(obj);
|
var command = new UndoRedoCommand<object>(oldValue, newValue, undoAction, redoAction);
|
AddCommand(command);
|
}
|
return;
|
}
|
|
|
if (o is IBaseViewModel obj && obj != null)
|
{
|
var propertyDescriptor = TypeDescriptor.GetProperties(obj)[PropertyDescriptorName];
|
if (propertyDescriptor == null) return;
|
var undoAction = new Action<object>(v => propertyDescriptor.SetValue(obj, v));
|
var redoAction = new Action<object>(v => propertyDescriptor.SetValue(obj, v));
|
var command = new UndoRedoCommand<object>(oldValue, newValue, undoAction, redoAction);
|
AddCommand(command);
|
}
|
else if (o is List<IBaseViewModel> || o is List<NodeViewModel>)
|
{
|
var list = getObj(o);
|
List<UndoRedoCommand<object>> list_command = new List<UndoRedoCommand<object>>();
|
PropertyDescriptor propertyDescriptor = null;
|
for (int i = 0; i < list.Count; i++)
|
{
|
var item = list[i];
|
if (propertyDescriptor == null) propertyDescriptor = TypeDescriptor.GetProperties(item)[PropertyDescriptorName];
|
if (propertyDescriptor == null) continue;
|
IBaseViewModel obj0 = (IBaseViewModel)item;
|
var undoAction0 = new Action<object>(v => propertyDescriptor.SetValue(obj0, v));
|
var redoAction0 = new Action<object>(v => propertyDescriptor.SetValue(obj0, v));
|
|
var command0 = new UndoRedoCommand<object>(oldValue[i], newValue[i], undoAction0, redoAction0);
|
list_command.Add(command0);
|
|
}
|
|
var undoAction = new Action<object>(v =>
|
{
|
for (int i = 0; i < list_command.Count; i++)
|
{
|
list_command[i].Undo();
|
}
|
});
|
|
var redoAction = new Action<object>(v =>
|
{
|
for (int i = 0; i < list_command.Count; i++)
|
{
|
list_command[i].Redo();
|
}
|
});
|
var command = new UndoRedoCommand<object>(null, null, undoAction, redoAction);
|
AddCommand(command);
|
|
}
|
|
}
|
|
public static void Undo()
|
{
|
if (_undoStack.Count > 0)
|
{
|
var command = _undoStack.Pop();
|
command.Undo();
|
_redoStack.Push(command);
|
}
|
|
}
|
|
public static void Redo()
|
{
|
if (_redoStack.Count > 0)
|
{
|
var command = _redoStack.Pop();
|
command.Redo();
|
_undoStack.Push(command);
|
}
|
|
}
|
}
|
|
|
public class Colour
|
{
|
public string Name { get; set; }
|
public ColourType Type { get; set; }
|
public List<ColourItem> Items { get; set; }
|
|
public bool isNode
|
{
|
get
|
{
|
if (Type == ColourType.节点自由压力 || Type == ColourType.节点需水量)
|
{
|
return true;
|
}
|
else
|
{
|
return false;
|
}
|
}
|
}
|
|
public bool isChoosed { get; set; } = false;
|
|
public float minNum = 0;
|
public float maxNum = 50;
|
public int ColourCount = 5;
|
public Color color0 = Color.Red;
|
public Color color1 = Color.Blue;
|
|
|
public Colour(ColourType type = ColourType.节点自由压力, List<ColourItem> value = null, string name = null)
|
{
|
Name = name;
|
Type = type;
|
Items = value;
|
if (Items == null) Items = new List<ColourItem>();
|
if (Name == null) Name = type.ToString();
|
}
|
public override string ToString()
|
{
|
return Name;
|
}
|
|
public static List<ColourItem> GetColourItems(float minValue, float maxValue, int ColourNum, Color color0, Color color1)
|
{
|
var colourItems = new List<ColourItem>();
|
for (int i = 0; i < ColourNum; i++)
|
{
|
DRange currentRange = new DRange(minValue + i * (maxValue - minValue) / ColourNum, minValue + (i + 1) * (maxValue - minValue) / ColourNum);
|
Color c;
|
if (i == 0)
|
{
|
c = color0;
|
}
|
else if (i == ColourNum - 1)
|
{
|
c = color1;
|
}
|
else
|
{
|
c = Color.FromArgb(color0.R + (color1.R - color0.R) / (ColourNum - 1) * i, color0.G + (color1.G - color0.G) / (ColourNum - 1) * i, color0.B + (color1.B - color0.B) / (ColourNum - 1) * i);
|
|
}
|
|
|
ColourItem newFloor = new ColourItem(currentRange, c);
|
colourItems.Add(newFloor);
|
}
|
return colourItems;
|
}
|
|
public static int NodeTypeCount = 3;
|
}
|
|
public class ColourItem
|
{
|
public DRange DRange { get; set; } = new DRange();
|
public Color value;
|
public ColourItem(DRange dRange, Color value)
|
{
|
DRange = dRange;
|
this.value = value;
|
}
|
|
}
|
public enum ColourType
|
{
|
无 = 0,
|
节点自由压力 = 1,
|
节点绝对压力 = 2,
|
节点需水量 = 3,
|
管线流量 = 4,
|
管线流速 = 5
|
}
|
|
|
public class TempForEnum
|
{
|
public string Item1;
|
public dynamic Item2;
|
public TempForEnum(string key, dynamic value)
|
{
|
Item1 = key;
|
Item2 = value;
|
}
|
}
|
|
|
public class EquivalentTemplateModel
|
{
|
public string Name { get; set; }
|
|
public long ID { get; set; }
|
|
public List<WaterEquivalentModel> waterEquivalents { get; set; }
|
|
|
}
|
|
public class WaterEquivalentModel
|
{
|
|
/// 器具名称
|
public string WaterUtensilName { get; set; }
|
|
|
/// 数量
|
public int Count { get; set; }
|
|
|
/// 额定流量
|
public double RatedFlow { get; set; }
|
|
|
/// 最小额定流量
|
public double MinRatedFlow { get; set; }
|
}
|
|
|
public class MapViewEnum
|
{
|
public enum MapObjectType
|
{
|
全部,
|
节点,
|
水库,
|
水池,
|
水表,
|
喷头,
|
管线,
|
阀门,
|
重复器,
|
水泵,
|
阀门点,
|
水泵点,
|
}
|
|
public enum MouseState
|
{
|
无,
|
新增节点,
|
新建水库,
|
新建水池,
|
新建水表,
|
新增喷头,
|
新增管线,
|
新增立管,
|
新建阀门,
|
新建重复器,
|
新建水泵,
|
设置底图范围,
|
|
}
|
|
public enum FactoryType
|
{
|
水厂,
|
泵站
|
}
|
|
public enum TemplateType
|
{
|
全部,
|
小区模板,
|
单元模板,
|
单元分区模板,
|
楼层模板,
|
其他
|
}
|
}
|
|
public class AreaViewModel : NodeViewModel, IBaseViewModel
|
{
|
public List<NodeViewModel> InnerNodes = new List<NodeViewModel>();
|
public Color color { get; set; }
|
}
|
|
public class Factory
|
{
|
public string Name { get; set; }
|
public MapViewEnum.FactoryType Type { get; set; }
|
public List<PumpViewModel> Pumps { get; set; }
|
|
public void CurveFit()
|
{
|
foreach (var p in Pumps)
|
{
|
p.CurveFit();
|
}
|
}
|
}
|
|
|
public class JunctionViewModel : NodeViewModel
|
{
|
public override string ToString()
|
{
|
var pTemp = PatternID;
|
if (string.IsNullOrEmpty(pTemp) || pTemp == ";") pTemp = "";
|
return $"{ID}\t{Elev}\t{Demand}\t{pTemp}\t;\t";
|
}
|
}
|
|
|
public class MeterViewModel : NodeViewModel
|
{
|
public string DlTemplateID { get; set; }
|
public override string ToString()
|
{
|
if (string.IsNullOrEmpty(PatternID)) PatternID = "";
|
return $"{ID}\t{Elev}\t{Demand}\t{PatternID}\t;\t";
|
}
|
|
}
|
|
|
public class NozzleViewModel : NodeViewModel
|
{
|
|
|
[Description("房间")]
|
[DisplayName("房间")]
|
public string Room { get; set; }
|
|
[Category("计算参数")]
|
[Description("流量系数")]
|
[DisplayName("流量系数K")]
|
public float FlowCoefficient { get; set; }
|
public override string ToString()
|
{
|
if (string.IsNullOrEmpty(PatternID)) PatternID = "";
|
return $"{ID}\t{Elev}\t{Demand}\t{PatternID}\t;\t";
|
}
|
}
|
|
|
public class PipeViewModel : LinkViewModel
|
{
|
|
}
|
|
|
public class PointF3D
|
{
|
public float X { get; set; }
|
public float Y { get; set; }
|
public float Z { get; set; }
|
|
public PointF3D(float x, float y, float z)
|
{
|
X = x;
|
Y = y;
|
Z = z;
|
}
|
//定义减法运算符
|
public static PointF3D operator -(PointF3D p1, PointF3D p2)
|
{
|
return new PointF3D(p1.X - p2.X, p1.Y - p2.Y, p1.Z - p2.Z);
|
}
|
//定义加法运算符
|
public static PointF3D operator +(PointF3D p1, PointF3D p2)
|
{
|
return new PointF3D(p1.X + p2.X, p1.Y + p2.Y, p1.Z + p2.Z);
|
}
|
//定义乘法运算符
|
public static PointF3D operator *(PointF3D p1, float f)
|
{
|
return new PointF3D(p1.X * f, p1.Y * f, p1.Z * f);
|
}
|
//定义点乘运算符
|
public static float operator *(PointF3D p1, PointF3D p2)
|
{
|
return p1.X * p2.X + p1.Y * p2.Y + p1.Z * p2.Z;
|
}
|
//定义叉乘运算符
|
public static PointF3D operator ^(PointF3D p1, PointF3D p2)
|
{
|
return new PointF3D(p1.Y * p2.Z - p1.Z * p2.Y, p1.Z * p2.X - p1.X * p2.Z, p1.X * p2.Y - p1.Y * p2.X);
|
}
|
}
|
|
public class Cube
|
{
|
public Dictionary<int, List<PointF3D>> FacesVertices { get; private set; }
|
public List<PointF3D> Vertices { get; private set; }
|
|
public Cube()
|
{
|
InitializeVertices();
|
InitializeFaces();
|
}
|
|
private void InitializeVertices()
|
{
|
Vertices = new List<PointF3D>
|
{
|
new PointF3D(200, 200, 200), // Vertex 0
|
new PointF3D(200, 200, -200), // Vertex 1
|
new PointF3D(200, -200, 200), // Vertex 2
|
new PointF3D(200, -200, -200), // Vertex 3
|
new PointF3D(-200, 200, 200), // Vertex 4
|
new PointF3D(-200, 200, -200), // Vertex 5
|
new PointF3D(-200, -200, 200), // Vertex 6
|
new PointF3D(-200, -200, -200) // Vertex 7
|
};
|
}
|
|
private void InitializeFaces()
|
{
|
FacesVertices = new Dictionary<int, List<PointF3D>>
|
{
|
{ 1, new List<PointF3D> { Vertices[0], Vertices[1], Vertices[3], Vertices[2] } }, // Face 1
|
{ 2, new List<PointF3D> { Vertices[4], Vertices[5], Vertices[7], Vertices[6] } }, // Face 2
|
{ 3, new List<PointF3D> { Vertices[0], Vertices[1], Vertices[5], Vertices[4] } }, // Face 3
|
{ 4, new List<PointF3D> { Vertices[2], Vertices[3], Vertices[7], Vertices[6] } }, // Face 4
|
{ 5, new List<PointF3D> { Vertices[0], Vertices[2], Vertices[6], Vertices[4] } }, // Face 5
|
{ 6, new List<PointF3D> { Vertices[1], Vertices[3], Vertices[7], Vertices[5] } }// Face 6
|
};
|
}
|
}
|
|
|
public class PumpNodeViewModel : NodeViewModel
|
{
|
public PumpNodeViewModel()
|
{
|
Datasets = new Dictionary<string, Dataset>() {
|
{"流量扬程曲线",new Dataset("流量扬程曲线",new PumpViewModel())},
|
{"流量功率曲线",new Dataset("流量功率曲线",new PumpViewModel()) },
|
{"流量效率曲线",new Dataset("流量效率曲线",new PumpViewModel()) }
|
};
|
}
|
public string HeadCurve { get; set; }
|
public List<string> Parameters { get; set; }
|
|
public string Node1 { get; set; }
|
public string Node2 { get; set; }
|
|
public Dictionary<string, Dataset> Datasets { get; set; }
|
|
public double 额定转速 { get; set; } = 1500;
|
public double 额定流量 { get; set; } = 0;
|
public double 额定扬程 { get; set; } = 0;
|
|
public double 额定功率 { get; set; } = 75;
|
|
public double 当前转速 { get; set; } = 1500;
|
|
public double 转速比 { get; set; } = 1;
|
|
public Dataset 流量扬程曲线 { get { return Datasets["流量扬程曲线"]; } }
|
|
public Dataset 流量功率曲线 { get { return Datasets["流量功率曲线"]; } }
|
|
public Dataset 流量效率曲线 { get { return Datasets["流量效率曲线"]; } }
|
|
}
|
|
|
public class PumpViewModel : LinkViewModel
|
{
|
public static List<string> CurveStrings = new List<string> { "流量扬程曲线", "流量功率曲线", "流量效率曲线" };
|
|
public new string Name
|
{
|
get { return base.Name; }
|
set { base.Name = value; }
|
}
|
|
[DisplayName("水泵类型")]
|
public new PumpType Type { get; set; }
|
|
|
public dict<string, Dataset> Datasets { get; set; } = new dict<string, Dataset>();
|
|
|
[Category("计算参数")]
|
public double 额定转速 { get; set; } = 1500;
|
|
[Category("计算参数")]
|
public double 额定流量 { get; set; } = 200;
|
[Category("计算参数")]
|
public double 额定扬程 { get; set; } = 50;
|
[Category("计算参数")]
|
public double 额定功率 { get; set; } = 75;
|
|
public double 转速比 { get; set; } = 1;
|
|
[DisplayName("当前转速")]
|
[Category("计算参数")]
|
public double 当前转速 { get; set; } = 1500;
|
|
public Dataset 流量扬程曲线
|
{
|
get
|
{
|
if (!Datasets.ContainsKey("流量扬程曲线")) Datasets.Add("流量扬程曲线", new Dataset("流量扬程曲线", null));
|
return Datasets["流量扬程曲线"];
|
}
|
}
|
|
public Dataset 流量功率曲线
|
{
|
get
|
{
|
if (!Datasets.ContainsKey("流量功率曲线")) Datasets.Add("流量功率曲线", new Dataset("流量功率曲线", null));
|
return Datasets["流量功率曲线"];
|
}
|
}
|
|
public Dataset 流量效率曲线
|
{
|
get
|
{
|
if (!Datasets.ContainsKey("流量效率曲线")) Datasets.Add("流量效率曲线", new Dataset("流量效率曲线", null));
|
return Datasets["流量效率曲线"];
|
}
|
}
|
|
public string factoryName
|
{
|
set; get;
|
}
|
|
|
|
public Factory factory { get; set; } = null;
|
|
|
public PumpViewModel Copy()
|
{
|
PumpViewModel p = new PumpViewModel();
|
p.Name = Name;
|
p.额定流量 = 额定流量;
|
p.额定扬程 = 额定扬程;
|
p.额定功率 = 额定功率;
|
p.额定转速 = 额定转速;
|
p.当前转速 = 当前转速;
|
p.Type = Type;
|
p.factory = factory;
|
foreach (var str in CurveStrings)
|
{
|
if (!p.Datasets.ContainsKey(str))
|
{
|
p.Datasets.Add(str, new Dataset(str, p));
|
}
|
}
|
|
foreach (var pair in Datasets)
|
{
|
List<PointF> list = new List<PointF>();
|
pair.Value._data.ForEach(m => list.Add(m));
|
p.Datasets[pair.Key].Data = list;
|
DRange rangeDefault = new DRange(double.MaxValue, double.MinValue);
|
p.Datasets[pair.Key].range_X = DRange.Union(rangeDefault, pair.Value.range_X);
|
p.Datasets[pair.Key].range_Y = DRange.Union(rangeDefault, pair.Value.range_Y);
|
}
|
p.CurveFit();
|
return p;
|
}
|
|
public void CurveFit()
|
{
|
|
|
foreach (var data in Datasets)
|
{
|
data.Value.Data.Sort((a, b) => a.X > b.X ? 1 : (a.X == b.X ? 0 : -1));
|
if (data.Value.HasData) data.Value.CurveFit();
|
}
|
string basetype = "流量扬程曲线";
|
string type = "";
|
|
|
type = "流量效率曲线";
|
var type1 = "流量功率曲线";
|
if (!Datasets.ContainsKey(type)) Datasets.Add(type, new Dataset(type, null));
|
if (!Datasets.ContainsKey(type1)) Datasets.Add(type1, new Dataset(type1, null));
|
if (Datasets[type].IsFitted && !Datasets[type1].IsFitted)
|
{
|
List<PointF> points = new List<PointF>();
|
List<PointF> points1 = new List<PointF>();
|
|
foreach (var yc in Datasets[basetype].Data)
|
{
|
float x = yc.X;
|
float y_扬程 = yc.Y;
|
|
float y_效率 = (float)Datasets[type].Evaluate(x);
|
float y_功率 = (float)x * y_扬程 / y_效率 / 3.6f;
|
points.Add(new PointF(x, y_效率));
|
points1.Add(new PointF(x, y_功率));
|
}
|
Datasets[type].Data = points;
|
Datasets[type1].Data = points1;
|
Datasets[type].CurveFit();
|
Datasets[type1].CurveFit();
|
}
|
|
|
|
if (!Datasets[type].IsFitted && Datasets[type1].IsFitted)
|
{
|
List<PointF> points = new List<PointF>();
|
List<PointF> points1 = new List<PointF>();
|
|
foreach (var yc in Datasets[basetype].Data)
|
{
|
float x = yc.X;
|
float y_扬程 = yc.Y;
|
float y_功率 = (float)Datasets[type1].Evaluate(x);
|
float y_效率 = (float)x * y_扬程 / y_功率 / 3.6f;
|
|
points.Add(new PointF(x, y_效率));
|
points1.Add(new PointF(x, y_功率));
|
|
|
}
|
Datasets[type].Data = points;
|
Datasets[type1].Data = points1;
|
Datasets[type].CurveFit();
|
Datasets[type1].CurveFit();
|
}
|
|
}
|
|
public void ShowInGrid(DataGridView dataGridView)
|
{
|
dataGridView.Rows.Clear();
|
// if ()
|
for (int i = 0; i < 流量扬程曲线.Data.Count; i++)
|
{
|
PointF p = 流量扬程曲线.Data[i];
|
PointF p_temp;
|
double y1 = 0, y2 = 0;
|
if (流量功率曲线.IsFitted)
|
{
|
if ((p_temp = 流量功率曲线.Data.Find(p0 => p0.X == p.X)) == default(PointF))
|
y1 = 流量功率曲线.Evaluate(p.X);
|
else
|
y1 = p_temp.Y;
|
}
|
|
if (流量效率曲线.IsFitted)
|
{
|
if ((p_temp = 流量效率曲线.Data.Find(p0 => p0.X == p.X)) == default(PointF))
|
y2 = 流量效率曲线.Evaluate(p.X);
|
else
|
y2 = p_temp.Y;
|
}
|
dataGridView.Rows.Add(Math.Round(p.X, 1), Math.Round(p.Y, 2), Math.Round(y1, 2), Math.Round(y2, 2));
|
}
|
}
|
|
|
[Category("计算参数")]
|
[DisplayName("流量扬程曲线")]
|
public List<PointF> HeadCurvePoints
|
{
|
get
|
{
|
this.Datasets.TryGetValue("流量扬程曲线", out Dataset dataset);
|
if (dataset != null)
|
{
|
return dataset._data;
|
}
|
return null;
|
}
|
set
|
{
|
this.Datasets.TryGetValue("流量扬程曲线", out Dataset dataset);
|
if (dataset == null)
|
{
|
dataset = new Dataset("流量扬程曲线", this);
|
}
|
dataset._data = value;
|
|
}
|
}
|
[Category("计算参数")]
|
[DisplayName("流量效率曲线")]
|
public List<PointF> EfficCurvePoints
|
{
|
get
|
{
|
this.Datasets.TryGetValue("流量效率曲线", out Dataset dataset);
|
if (dataset != null)
|
{
|
return dataset._data;
|
}
|
return null;
|
}
|
set
|
{
|
this.Datasets.TryGetValue("流量效率曲线", out Dataset dataset);
|
if (dataset == null)
|
{
|
dataset = new Dataset("流量效率曲线", this);
|
}
|
dataset._data = value;
|
|
}
|
}
|
|
public string HeadCurve { get; set; } = "PumpDefault";
|
|
public List<string> Parameters { get; set; }
|
|
//实际需水量
|
|
[DisplayName("扬程")]
|
[Browsable(true)]
|
public new float EN_HEADLOSS { get { return -base.EN_HEADLOSS; } }
|
|
|
public new float EN_VELOCITY { get { return base.EN_VELOCITY; } }
|
|
|
public override string ToString()
|
{
|
string para = Parameters == null ? null : string.Join("\t", Parameters);
|
return $"{ID}\t{Node1}\t{Node2}\tHead\t{HeadCurve}\tSPEED\t{转速比}\t{para}\t;\t";
|
}
|
}
|
|
public class RepeaterViewModel : LinkViewModel
|
{
|
|
[DisplayName("对象前缀名称")]
|
[Browsable(true)]
|
|
/// 模板ID
|
public string NetworkPreName { get; set; }
|
|
|
[DisplayName("显示名称")]
|
[Browsable(true)]
|
|
/// 模板ID
|
public string NetworkShowName { get; set; }
|
|
|
[DisplayName("前缀最小序号")]
|
[Browsable(true)]
|
|
/// 模板ID
|
|
public int NetworkPreStartNum { get; set; } = 1;
|
|
|
[DisplayName("前缀正序")]
|
[Browsable(true)]
|
|
/// 模板ID
|
|
public bool NetworkIsAscNum { get; set; } = true;
|
|
[Category("计算参数")]
|
[DisplayName("模板ID")]
|
|
|
/// 模板ID
|
|
public string TemplateID { get; set; }
|
|
|
[Category("计算参数")]
|
[DisplayName("模板名称")]
|
[Browsable(true)]
|
public string TempName => TemplateList.GetTemplate(TemplateID)?.Name;
|
|
public Template template = null;
|
|
[NonSerialized]
|
public MapViewNetWork netList = null;
|
|
|
|
public NodeViewModel StartNode_inner;
|
|
public NodeViewModel EndNode_inner;
|
|
|
public bool isLoadded = false;
|
|
|
[Category("计算参数")]
|
[DisplayName("重复次数")]
|
[Browsable(true)]
|
|
/// 重复次数
|
|
public int RepeatTimes { get; set; }
|
|
|
|
|
[Category("计算参数")]
|
[DisplayName("海森威廉系数")]
|
|
public new float Roughness { get; set; }
|
[Category("计算参数")]
|
[DisplayName("局部阻力系数")]
|
|
public override float MinorLoss { get; set; }
|
|
[DisplayName("长度(m)")]
|
[Browsable(true)]
|
public new float Length { get; set; }
|
|
|
[DisplayName("口径(mm)")]
|
|
public new float Diameter { get; set; }
|
|
|
[Category("计算参数")]
|
[DisplayName("显示状态")]
|
[Browsable(true)]
|
public new RepeatStatus Status { get; set; }
|
|
public bool Load(int MaxLevel, dict<string, dynamic> param, Dictionary<TemplateType, bool> viewModel, bool viewMode = true)
|
{
|
|
if (template == null)
|
{
|
template = TemplateList.GetTemplate(TemplateID);
|
if (template == null)
|
{
|
return false;
|
}
|
template.loadInpFile();
|
template.network.MapObjects.ForEach(o =>
|
{
|
if (o.Level > MaxLevel)
|
o.Visible = false;
|
else
|
o.Visible = true;
|
});
|
MapViewNetWork net = template.network;
|
net.StartPoint = net.GetNode(template.Node1)[0];
|
net.EndPoint = net.GetNode(template.Node2)[0];
|
|
}
|
|
|
if (!viewMode)
|
{
|
Status = RepeatStatus.收起;
|
}
|
else if (viewModel != null)
|
{
|
if (viewModel[template.Type])
|
Status = RepeatStatus.显示;
|
else
|
Status = RepeatStatus.收起;
|
}
|
else
|
{
|
Status = RepeatStatus.显示;
|
}
|
|
|
if (param.Contains("层数") && param["层数"] > 0 && template.Type == TemplateType.楼层模板)
|
{
|
RepeatTimes = (int)param["层数"];
|
}
|
|
if (Status == RepeatStatus.收起)
|
{
|
return false;
|
}
|
PointF3D basepoint = StartNode.Position3D;
|
netList = new MapViewNetWork();
|
for (int i = 0; i < RepeatTimes; i++)
|
{
|
MapViewNetWork net = template.network.CreateNew(basepoint);
|
int index = GetIndex(i);
|
|
net.Name = NetworkPreName + (index == 0 ? "" : index.ToString("00"));
|
net.StartPoint = net.GetNode(template.Node1)[0];
|
net.EndPoint = net.GetNode(template.Node2)[0];
|
if (template.Type == TemplateType.楼层模板)
|
ChangeNetbyParam(net, param);
|
if (i == 0) StartNode_inner = net.StartPoint;
|
EndNode_inner = net.EndPoint;
|
net.LoadRepeaters(MaxLevel, param, viewModel);
|
net.Rename();
|
netList.AddJoinNet(net);
|
basepoint = netList.EndPoint.Position3D;
|
}
|
return true;
|
}
|
void ChangeNetbyParam(MapViewNetWork net, dict<string, dynamic> param)
|
{
|
if (param.Contains("层高") && param["层高"] > 0 && net.StartPoint != null && net.EndPoint != null)
|
{
|
var currentHeight = Math.Abs(net.StartPoint.Elev - net.EndPoint.Elev);
|
var k = (float)param["层高"] / currentHeight;
|
net.Nodes.ForEach(n => n.Elev = (n.Elev - net.StartPoint.Elev) * k + net.StartPoint.Elev);
|
}
|
|
if (param.Contains("系统最大流量") && param["系统最大流量"] > 0 && net.StartPoint != null && net.EndPoint != null)
|
{
|
Dictionary<NodeViewModel, float> Distance = new Dictionary<NodeViewModel, float>();
|
CalcDistance(net, net.StartPoint, Distance);
|
float sumDistance = 0;
|
net.meters.ForEach(m => sumDistance += Distance[m]);
|
float avgDistance = sumDistance / net.meters.Count;
|
var k = (float)param["系统最大流量"] / avgDistance;
|
net.Nodes.ForEach(n =>
|
{
|
n.X = (n.X - net.StartPoint.X) * k + net.StartPoint.X;
|
n.Y = (n.Y - net.StartPoint.Y) * k + net.StartPoint.Y;
|
});
|
}
|
if (param.Contains("户数") && template.Type == TemplateType.楼层模板)
|
{
|
var MaxLevel = (int)param["户数"];
|
net.MapObjects.ForEach(o =>
|
{
|
if (o.Level > MaxLevel)
|
o.Visible = false;
|
else
|
o.Visible = true;
|
});
|
}
|
}
|
|
|
|
public static void CalcDistance(MapViewNetWork net, NodeViewModel startNode, Dictionary<NodeViewModel, float> Distance)
|
{
|
// 定义 visited 字典记录已访问过的节点和待访问的节点队列
|
Queue<NodeViewModel> queue = new Queue<NodeViewModel>();
|
|
// 标记起始节点为已访问,并加入队列
|
Distance[startNode] = 0;
|
queue.Enqueue(startNode);
|
|
// 不断从队列中取出节点进行访问,直到队列为空
|
while (queue.Count > 0)
|
{
|
// 取出队首节点并输出
|
NodeViewModel node = queue.Dequeue();
|
//Console.WriteLine(node.Name);
|
|
// 遍历当前节点的所有未访问邻居节点,并标记为已访问
|
foreach (LinkViewModel link in net.Links)
|
{
|
if (link.StartNode == node)
|
{
|
var node1 = link.EndNode;
|
var dis = Distance[node] + (float)Math.Sqrt(Math.Pow(node.X - node1.X, 2) + Math.Pow(node.Y - node1.Y, 2));
|
if (!Distance.ContainsKey(node1) || Distance[node1] > dis)
|
Distance[link.EndNode] = dis;
|
queue.Enqueue(link.EndNode);
|
}
|
else if (link.EndNode == node && !Distance.ContainsKey(link.StartNode))
|
{
|
var node1 = link.StartNode;
|
var dis = Distance[node] + (float)Math.Sqrt(Math.Pow(node.X - node1.X, 2) + Math.Pow(node.Y - node1.Y, 2));
|
if (!Distance.ContainsKey(node1) || Distance[node1] > dis)
|
Distance[link.StartNode] = dis;
|
queue.Enqueue(link.StartNode);
|
}
|
}
|
}
|
}
|
|
public int GetIndex(int i)
|
{
|
int index = 0;
|
if (NetworkIsAscNum)
|
{
|
index = NetworkPreStartNum + i;
|
}
|
else
|
{
|
index = RepeatTimes - 1 - i + NetworkPreStartNum;
|
}
|
|
return index;
|
}
|
|
|
|
public enum RepeatStatus
|
{
|
收起,
|
显示
|
}
|
}
|
|
|
public class ReservoirViewModel : NodeViewModel
|
{
|
[Category("计算参数")]
|
[Description("需水量")]
|
[DisplayName("需水量(m³/h)")]
|
|
public new float Demand { get; set; }
|
[Category("计算参数")]
|
[Description("总水头")]
|
[DisplayName("绝对水压(m)")]
|
public float Head { get; set; }
|
//public string Pattern { get; set; }
|
public override string ToString()
|
{
|
return $"{ID}\t{Head}\t{PatternID}\t;\t";
|
}
|
}
|
|
|
public class TankViewModel : NodeViewModel
|
{
|
[Category("计算参数")]
|
[DisplayName("初始水位(m)")]
|
public float InitLevel { get; set; } = 5;
|
[Category("计算参数")]
|
[DisplayName("最低水位(m)")]
|
public float MinLevel { get; set; } = 0;
|
[Category("计算参数")]
|
[DisplayName("最高水位(m)")]
|
public float MaxLevel { get; set; } = 10;
|
[Category("计算参数")]
|
[DisplayName("直径(mm)")]
|
|
public float Diameter { get; set; } = 10;
|
|
[Category("计算参数")]
|
[DisplayName("池底面积")]
|
public double Area
|
{
|
get
|
{
|
return Math.PI * Math.Pow(Diameter, 2) / 4;
|
}
|
set
|
{
|
Diameter = (float)Math.Pow(value / Math.PI, 0.5) * 2;
|
}
|
}
|
[Category("计算参数")]
|
[DisplayName("最小容积")]
|
public float MinVol { get; set; } = 0;
|
|
[Category("计算参数")]
|
[DisplayName("容积曲线")]
|
public string VolCurve { get; set; } = "";
|
[Category("计算参数")]
|
[DisplayName("是否允许溢流")]
|
public string Overflow { get; set; } = "";
|
|
public TankViewModel()
|
{
|
|
}
|
public TankViewModel(string id, string elevation, string initlevel, string minlevel, string maxlevel, string diameter, string minvol, string volcurve, string overflow)
|
{
|
ID = id;
|
Elev = float.Parse(elevation);
|
float d = 0;
|
float.TryParse(initlevel, out d);
|
InitLevel = d;
|
float.TryParse(minlevel, out d);
|
MinLevel = d;
|
float.TryParse(maxlevel, out d);
|
MaxLevel = d;
|
float.TryParse(diameter, out d);
|
Diameter = d;
|
float.TryParse(minvol, out d);
|
MinVol = d;
|
VolCurve = "";
|
//float.TryParse(overflow, out d );
|
Overflow = "";
|
}
|
public override string ToString()
|
{
|
VolCurve = "";
|
Overflow = "";
|
return $"{ID}\t{Elev}\t{InitLevel}\t{MinLevel}\t{MaxLevel}\t{Diameter}\t{MinVol}\t{VolCurve}\t{Overflow}\t;\t";
|
}
|
}
|
|
|
public class ValveNodeViewModel : NodeViewModel
|
{
|
public string Node1 { get; set; }
|
public string Node2 { get; set; }
|
|
|
|
[DisplayName("长度(m)")]
|
[Browsable(true)]
|
public float Length { get; set; }
|
|
|
[DisplayName("口径(mm)")]
|
[Browsable(true)]
|
public float Diameter { get; set; }
|
|
[Category("计算参数")]
|
[DisplayName("海森威廉系数")]
|
[Browsable(true)]
|
public float Roughness { get; set; } = 110;
|
[Category("计算参数")]
|
[DisplayName("局部阻力系数")]
|
[Browsable(true)]
|
public float MinorLoss { get; set; } = 0;
|
[Category("计算参数")]
|
[DisplayName("初始状态")]
|
[Browsable(true)]
|
public new StatusType Status { get; set; }
|
|
|
[Browsable(true)]
|
public new string Type { get; set; } = "GPV";
|
|
[DisplayName("曲线")]
|
[Browsable(true)]
|
public string Setting { get; set; } = "GPVDefault";
|
}
|
|
|
public class ValveViewModel : LinkViewModel
|
{
|
|
[DisplayName("长度(m)")]
|
[Browsable(true)]
|
public new float Length { get; set; }
|
|
|
[DisplayName("口径(mm)")]
|
[Browsable(true)]
|
public new float Diameter { get; set; }
|
|
[Category("计算参数")]
|
[DisplayName("海森威廉系数")]
|
[Browsable(true)]
|
public new float Roughness { get; set; } = 110;
|
[Category("计算参数")]
|
[DisplayName("局部阻力系数")]
|
[Browsable(true)]
|
public new float MinorLoss { get; set; } = 0;
|
//[Category("计算参数")]
|
//[DisplayName("初始状态")]
|
//[Browsable(true)]
|
//public string Status { get; set; } = "";
|
|
|
[Browsable(true)]
|
public new string Type { get; set; } = "GPV";
|
|
[DisplayName("曲线")]
|
[Browsable(true)]
|
public string Setting { get; set; } = "GPVDefault";
|
|
// 重写ToString()方法以便将阀门属性转换为字符串
|
public override string ToString()
|
{
|
|
return $"{ID}\t{Node1}\t{Node2}\t{Diameter:F4}\t{Type}\t{Setting}\t{MinorLoss:F4}\t;\t";
|
}
|
|
}
|
|
|
public class TRegion
|
{
|
public string Name { get; set; } = "新分区";
|
public List<Floor> Floors { get; set; } = new List<Floor>();
|
public bool isDirectionUp { get; set; } = true;
|
public string JoinNode { get; set; } = null;
|
|
public override string ToString()
|
{
|
return Name;
|
}
|
|
}
|
|
|
public class Floor
|
{
|
public int FloorIndex = 1;
|
public string BackgroundImg = null;
|
public float Elev = 0;
|
public MapDimensions MapView { get; set; } = null;
|
|
public string Name => $"{FloorIndex}楼";
|
public Floor()
|
{
|
|
}
|
|
|
public Floor(Floor other)
|
{
|
// 进行属性的深拷贝赋值
|
this.FloorIndex = other.FloorIndex;
|
this.BackgroundImg = other.BackgroundImg;
|
this.Elev = other.Elev;
|
this.MapView = (other.MapView != null) ? other.MapView.DeepCopyByBin<MapDimensions>() : null;
|
}
|
public Floor(int floorIndex, string tempID, float floorElevation, MapDimensions otherInfo)
|
{
|
FloorIndex = floorIndex;
|
TemplateID = tempID;
|
Elev = floorElevation;
|
MapView = otherInfo;
|
}
|
public string TemplateID { get; set; } = null;
|
|
|
public Template template { get { return TemplateList.GetTemplate(TemplateID); } }
|
|
|
|
|
}
|
|
|
public class Template
|
{
|
private string _ID;
|
|
[Description("对象的ID唯一标识")]
|
[DisplayName("模板ID")]
|
[Browsable(true)]
|
public string ID { get { if (_ID == null || _ID == "") _ID = Guid.NewGuid().ToString(); return _ID; } set { _ID = value; } }
|
|
[DisplayName("名称")]
|
public string Name { get; set; }
|
|
public MapOption mapOption { get; set; } = new MapOption();
|
|
private string _filePath = null;
|
|
[Category("计算参数")]
|
[DisplayName("路径INP")]
|
public string filePath
|
{
|
get
|
{
|
return _filePath;
|
}
|
set
|
{
|
var filePath = value;
|
var CurDir = Directory.GetCurrentDirectory();
|
if (filePath != null && filePath.IndexOf(CurDir) >= 0)
|
{
|
|
filePath = filePath.Replace(CurDir, "");
|
if (filePath[0] == '\\')
|
filePath = filePath.Substring(1);
|
}
|
|
|
_filePath = filePath;
|
}
|
}
|
|
|
public PointF3D OffSet { get; set; } = new PointF3D(0, 0, 0);
|
|
private string _BackGroundImg_FullPath;
|
|
public string BackGroundImg_FullPath
|
{
|
get
|
{
|
if (string.IsNullOrEmpty(_BackGroundImg_FullPath))
|
{
|
FileInfo fi = new FileInfo(FullPath);
|
return fi.FullName.Substring(0, fi.FullName.Length - fi.Extension.Length) + ".png";
|
}
|
else return _BackGroundImg_FullPath;
|
}
|
set
|
{
|
_BackGroundImg_FullPath = value;
|
}
|
}
|
|
public float BackGroundElev = 0;
|
|
|
/// 底图X
|
|
public float BackGroundImgX = 0;
|
|
|
/// 底图Y
|
|
public float BackGroundImgY = 0;
|
|
/// 底图高度
|
|
public float BackGroundImgHeight = 0;
|
|
/// 底图宽度
|
|
public float BackGroundImgWidth = 0;
|
|
/// 底图旋转角度
|
|
public float BackGroundImgRotaAngle = 0;
|
public PointF BackGroundPoint1 = new PointF();
|
|
public PointF BackGroundPoint2 = new PointF();
|
|
public string FullPath
|
{
|
get
|
{
|
if (filePath != null) filePath = filePath.TrimStart('\\');
|
return
|
Path.Combine(Directory.GetCurrentDirectory(), (filePath == null ? "" : filePath));
|
|
}
|
}
|
|
|
public string ImportExcelPath { get; set; }
|
|
|
public int ImportExcelIndex { get; set; }
|
|
|
|
[Category("计算参数")]
|
[DisplayName("最高级数")]
|
public int MaxLevel { get; set; } = 99;
|
|
|
|
[Browsable(true)]
|
public TemplateType Type { get; set; }
|
|
|
public Template()
|
{
|
|
ID = new Guid().ToString();
|
Name = "临时";
|
filePath = null;
|
|
}
|
public Template(string ID, string name, string address, TemplateType type)
|
{
|
if (ID == null)
|
this.ID = new Guid().ToString();
|
Name = name;
|
filePath = address;
|
Type = type;
|
}
|
|
|
|
[Description("对象的ID唯一标识")]
|
|
[NonSerialized]
|
public MapViewNetWork network = null;
|
|
|
|
[Category("楼层")]
|
[DisplayName("楼层")]
|
|
public List<TRegion> Regions { get; set; } = null;
|
|
|
[DisplayName("标高")]
|
|
public float Elev { get { return 0; } }
|
|
public float Diameter { get { return 0; } }
|
|
|
public float Level { get { return 0; } }
|
|
|
|
|
[DisplayName("开始节点")]
|
public string Node1 { get; set; }
|
|
|
|
[DisplayName("结束节点")]
|
public string Node2 { get; set; }
|
|
|
public string X { get; set; }
|
|
public string Y { get; set; }
|
|
|
public string Visible { get; set; }
|
|
[Category("默认视角")]
|
[DisplayName("视角")]
|
|
public MapDimensions view { get; set; } = new MapDimensions();
|
|
|
[Category("默认视角")]
|
[DisplayName("中心X")]
|
[Browsable(true)]
|
public float CenterX
|
{
|
get
|
{
|
if (view != null) return view.Center.X;
|
else return 0;
|
}
|
set
|
{
|
if (view == null) view = new MapDimensions();
|
view.Center = new PointF(value, view.Center.Y);
|
}
|
}
|
[Category("默认视角")]
|
[DisplayName("中心Y")]
|
[Browsable(true)]
|
public float CenterY
|
{
|
get
|
{
|
if (view != null) return view.Center.Y;
|
else return 0;
|
}
|
set
|
{
|
if (view == null) view = new MapDimensions();
|
view.Center = new PointF(view.Center.X, value);
|
}
|
}
|
|
[Category("默认视角")]
|
[DisplayName("缩放")]
|
[Browsable(true)]
|
public float zoom
|
{
|
get
|
{
|
if (view != null)
|
return view.zoom;
|
else return 1f;
|
}
|
set
|
{
|
if (view == null) view = new MapDimensions();
|
view.zoom = value;
|
}
|
}
|
|
[Category("默认视角")]
|
[DisplayName("旋转角度")]
|
[Browsable(true)]
|
public double rotation
|
{
|
get { if (view != null) return view.rotation; else return 0; }
|
set
|
{
|
if (view == null) view = new MapDimensions();
|
view.rotation = value;
|
}
|
}
|
|
[Category("默认视角")]
|
[DisplayName("俯视角度")]
|
[Browsable(true)]
|
public double rotationF
|
{
|
get { if (view != null) return view.rotationF; else return 90; }
|
set
|
{
|
if (view == null) view = new MapDimensions();
|
view.rotationF = value;
|
}
|
}
|
|
|
|
|
public bool loadInpFile()
|
{
|
network = new MapViewNetWork();
|
var result = network.BuildFromInp(FullPath);
|
if (result)
|
{
|
network.MapObjects.ForEach(o =>
|
{
|
if (o.Level > MaxLevel)
|
o.Visible = false;
|
else
|
o.Visible = true;
|
});
|
|
|
return true;
|
}
|
else
|
return false;
|
}
|
[DisplayName("颜色分级方案")]
|
public List<Colour> Colours { get; set; } = new List<Colour>();
|
|
|
public void Export(string path)
|
{
|
network.BuildToInp(path);
|
}
|
}
|
|
|
public class TemplateList
|
{
|
public List<Template> templates = new List<Template>();
|
public static TemplateList instance;
|
public static string _tempListPath = null;
|
public static bool Inited = false;
|
|
public static Template AddTemp(Template temp)
|
{
|
instance.templates.Add(temp);
|
return temp;
|
}
|
public static Template GetTemplate(string ID)
|
{
|
return instance.templates.Find(t => t.ID == ID);
|
}
|
|
public static void Init(string filePath = null)
|
{
|
if (filePath == null)
|
_tempListPath = Path.Combine(Directory.GetCurrentDirectory(), "templates.json");
|
else
|
_tempListPath = filePath;
|
if (File.Exists(_tempListPath))
|
{
|
string jsonString = File.ReadAllText(_tempListPath);
|
|
if (jsonString != null && jsonString != "")
|
{
|
try
|
{
|
instance = JsonConvert.DeserializeObject<TemplateList>(jsonString);
|
}
|
catch
|
{
|
|
}
|
|
}
|
|
|
}
|
if (instance == null)
|
{
|
instance = new TemplateList();
|
// 添加测试数据
|
AddTemp(new Template(null, "小区模板", @"template\小区模板\", TemplateType.小区模板));
|
AddTemp(new Template(null, "分区模板", @"template\单元分区模板\", TemplateType.单元分区模板));
|
AddTemp(new Template(null, "单元模板", @"template\单元模板\", TemplateType.单元模板));
|
AddTemp(new Template(null, "楼层1", @"template\楼层模板\楼层1.inp", TemplateType.楼层模板));
|
}
|
Inited = true;
|
}
|
|
// 保存模板数据到文件中
|
public static void SaveToFile(string filePath = null)
|
{
|
if (filePath == null) filePath = _tempListPath;
|
// 备份历史保存文件
|
if (File.Exists(filePath))
|
{
|
string backupPath = filePath + ".bak";
|
if (File.Exists(backupPath))
|
{
|
File.Delete(backupPath);
|
}
|
|
FileCopy.Copy(filePath, backupPath);
|
}
|
|
JsonSerializerSettings settings = new JsonSerializerSettings
|
{
|
Formatting = Formatting.Indented,
|
ContractResolver = new ShouldSerializeContractResolver(),
|
};
|
string json = JsonConvert.SerializeObject(instance, Formatting.Indented, settings);
|
File.WriteAllText(_tempListPath, json);
|
|
//MessageCompressHelper.SaveCompressedBase64ToFile<TemplateList>(instance, filePath);
|
}
|
|
public static List<Template> GetTemplates()
|
{
|
if (instance != null)
|
{
|
return instance.templates;
|
}
|
else
|
return new List<Template>();
|
}
|
}
|
public class ShouldSerializeContractResolver : DefaultContractResolver
|
{
|
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
{
|
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
|
if (property.DeclaringType == typeof(Template) && member.Name == "network")
|
{
|
property.ShouldSerialize = instance => false;
|
}
|
|
return property;
|
}
|
}
|
|
|
public class WaterEquivalent
|
{
|
public WaterEquivalent() { }
|
public WaterEquivalent(WaterEquivalent rhs)
|
{
|
this.ID = rhs.ID;
|
this.BelongID = rhs.BelongID;
|
this.BelongType = rhs.BelongType;
|
this.WaterUtensilID = rhs.WaterUtensilID;
|
this.Count = rhs.Count;
|
this.MinRatedFlow = rhs.MinRatedFlow;
|
this.RatedFlow = rhs.RatedFlow;
|
this.Flags = rhs.Flags;
|
this.TagName = rhs.TagName;
|
this.UseStatus = rhs.UseStatus;
|
this.SortCode = rhs.SortCode;
|
this.Description = rhs.Description;
|
}
|
|
public long ID { get; set; }
|
|
|
/// 所属对象标识
|
public long BelongID { get; set; }
|
|
|
/// 所属对象类型
|
public string BelongType { get; set; }
|
|
|
/// 用水器具标识
|
public long WaterUtensilID { get; set; }
|
|
|
/// 数量
|
public int Count { get; set; }
|
|
|
/// 额定流量
|
public double RatedFlow { get; set; }
|
|
|
/// 最小额定流量
|
public double MinRatedFlow { get; set; }
|
|
|
/// 标签列表
|
public string Flags { get; set; }
|
|
|
/// 标签名称
|
public string TagName { get; set; }
|
|
/// 使用状态
|
public int UseStatus { get; set; }
|
|
|
/// 排序码
|
public int SortCode { get; set; }
|
|
|
/// 说明
|
public string Description { get; set; }
|
|
|
}
|
|
|
public class WaterEquivalentCollection : List<WaterEquivalent>
|
{
|
public WaterEquivalentCollection() { }
|
public WaterEquivalentCollection(WaterEquivalentCollection rhs)
|
{
|
foreach (var item in rhs)
|
{
|
this.Add(new WaterEquivalent(item));
|
}
|
}
|
}
|
|
public class WaterEquivalentTemplate
|
{
|
public WaterEquivalentTemplate() { }
|
public WaterEquivalentTemplate(WaterEquivalentTemplate rhs)
|
{
|
this.ID = rhs.ID;
|
this.Name = rhs.Name;
|
this.Description = rhs.Description;
|
this.WaterEquivalentCollection = new WaterEquivalentCollection(rhs.WaterEquivalentCollection);
|
}
|
public string ID { get; set; }
|
public string Name { get; set; }
|
public string Description { get; set; }
|
|
public WaterEquivalentCollection WaterEquivalentCollection { get; set; }
|
}
|
|
public class WaterEquivalentSettings
|
{
|
|
/// 当量模板
|
|
public WaterEquivalentTemplate waterEquivalents = new WaterEquivalentTemplate();
|
|
/// 用户水表的集合
|
|
public List<string> Meters = new List<string>();
|
}
|
|
|
public class NetWork //: INetWork
|
{
|
public NetWork()
|
{
|
}
|
|
public List<JunctionModel> Junctions
|
{
|
get
|
{
|
var js = Nodes.Where(d => d is JunctionModel);
|
return js?.Select(d => d as JunctionModel).ToList();
|
}
|
|
}
|
public List<TankModel> Tanks
|
{
|
get
|
{
|
var js = Nodes.Where(d => d is TankModel);
|
return js?.Select(d => d as TankModel).ToList();
|
}
|
}
|
|
public List<PipeModel> Pipes
|
{
|
get
|
{
|
var js = Links.Where(d => d is PipeModel);
|
return js?.Select(d => d as PipeModel).ToList();
|
}
|
}
|
|
public List<PumpModel> Pumps
|
{
|
get
|
{
|
var js = Links.Where(d => d is PumpModel);
|
return js?.Select(d => d as PumpModel).ToList();
|
}
|
}
|
|
public List<ValveModel> Valves
|
{
|
get
|
{
|
var js = Links.Where(d => d is ValveModel);
|
return js?.Select(d => d as ValveModel).ToList();
|
}
|
}
|
|
public List<ReservoisModel> Reservos
|
{
|
get
|
{
|
var js = Nodes.Where(d => d is ReservoisModel);
|
return js?.Select(d => d as ReservoisModel).ToList();
|
}
|
}
|
|
public List<MeterModel> Meters
|
{
|
get
|
{
|
var js = Nodes.Where(d => d is MeterModel);
|
return js?.Select(d => d as MeterModel).ToList();
|
}
|
}
|
|
public List<NozzleModel> Nozzles
|
{
|
get
|
{
|
var js = Nodes.Where(d => d is NozzleModel);
|
return js?.Select(d => d as NozzleModel).ToList();
|
}
|
}
|
|
public virtual void AddJunction(JunctionModel junction)
|
{
|
CheckNodesExist(junction);
|
Nodes.Add(junction);
|
}
|
|
public virtual void AddJunctions(List<JunctionModel> junctions)
|
{
|
junctions.ForEach(junction => { AddJunction(junction); });
|
}
|
|
public virtual void AddTank(TankModel tank)
|
{
|
CheckNodesExist(tank);
|
Nodes.Add(tank);
|
}
|
|
public virtual void AddTanks(List<TankModel> tanks)
|
{
|
tanks.ForEach(tank => { AddTank(tank); });
|
}
|
|
public virtual void AddPipe(PipeModel pipe)
|
{
|
CheckLinksExist(pipe);
|
Links.Add(pipe);
|
}
|
|
public virtual void AddPipes(List<PipeModel> pipes)
|
{
|
pipes.ForEach(pipe => { AddPipe(pipe); });
|
}
|
public virtual void AddPump(PumpModel pump)
|
{
|
CheckLinksExist(pump);
|
Links.Add(pump);
|
}
|
|
public virtual void AddPumps(List<PumpModel> pumps)
|
{
|
pumps.ForEach(pump => { AddPump(pump); });
|
}
|
public virtual void AddValve(ValveModel valve)
|
{
|
CheckLinksExist(valve);
|
Links.Add(valve);
|
}
|
|
public virtual void AddValves(List<ValveModel> valves)
|
{
|
valves.ForEach(valve => { AddValve(valve); });
|
}
|
public virtual void AddReservos(ReservoisModel reservois)
|
{
|
CheckNodesExist(reservois);
|
Nodes.Add(reservois);
|
}
|
public virtual void AddReservoss(List<ReservoisModel> reservoiss)
|
{
|
reservoiss.ForEach(reservois => { AddReservos(reservois); });
|
}
|
public virtual void AddMeter(MeterModel meter)
|
{
|
CheckNodesExist(meter);
|
Nodes.Add(meter);
|
}
|
public virtual void AddMeters(List<MeterModel> meters)
|
{
|
meters.ForEach(meter => { AddMeter(meter); });
|
}
|
public virtual void AddNozzle(NozzleModel nozzle)
|
{
|
CheckNodesExist(nozzle);
|
Nodes.Add(nozzle);
|
}
|
public virtual void AddNozzles(List<NozzleModel> nozzles)
|
{
|
nozzles.ForEach(nozzle => { AddNozzle(nozzle); });
|
}
|
|
private void CheckNodesExist(NodeCalcModel node)
|
{
|
if (Nodes.Any(d => d.ID == node.ID))
|
throw new Exception("已存在重复的对象");
|
}
|
|
private void CheckLinksExist(LinkCalcModel link)
|
{
|
if (Links.Any(d => d.ID == link.ID))
|
throw new Exception("已存在重复的对象");
|
}
|
|
public List<NodeCalcModel> Nodes { get; set; } = new List<NodeCalcModel>();
|
public List<LinkCalcModel> Links { get; set; } = new List<LinkCalcModel>();
|
|
|
/// 根据INP文件生成
|
public virtual bool BuildFromInp(string InpPath)
|
{
|
if (InpPath == null || !File.Exists(InpPath)) return false;
|
List<Coor> points = new List<Coor>();
|
StreamReader sr = new StreamReader(InpPath);
|
|
{
|
string line;
|
string section = "";
|
while ((line = sr.ReadLine()) != null)
|
{
|
if (line.Trim().StartsWith("["))
|
{
|
section = line.TrimStart('[').TrimEnd(']');
|
}
|
else
|
{
|
string s = line.Trim('\t').Trim(' ');
|
if (s.Length == 0 || s[0] == ';') continue;
|
line = line.Replace("\t\t", "\t_\t").Replace("\t \t", "\t_\t");
|
Parts parts = new Parts(line.Split(new char[] { '\t', ' ', ';' }, StringSplitOptions.RemoveEmptyEntries));
|
switch (section)
|
{
|
case "JUNCTIONS":
|
{
|
var ID = parts[0];
|
float elev;
|
float.TryParse(parts[1], out elev);
|
var Elev = elev;
|
float demand;
|
float.TryParse(parts[2], out demand);
|
var Demand = demand;
|
var PatternID = parts[3];
|
int level;
|
int.TryParse(parts[6], out level);
|
var Level = level;
|
|
if (parts[5] == "Meter")
|
{
|
AddMeter(new MeterModel()
|
{
|
ID = ID,
|
Elev = Elev,
|
Demand = Demand,
|
PatternID = PatternID,
|
});
|
}
|
else if (parts[5] == "Nozzle")
|
{
|
AddNozzle(new NozzleModel()
|
{
|
ID = ID,
|
Elev = Elev,
|
Demand = Demand,
|
PatternID = PatternID,
|
});
|
}
|
else
|
{
|
AddJunction(new JunctionModel()
|
{
|
ID = ID,
|
Elev = Elev,
|
Demand = Demand,
|
PatternID = PatternID,
|
});
|
}
|
|
}
|
break;
|
case "RESERVOIRS":
|
{
|
ReservoisModel r = new ReservoisModel();
|
r.ID = parts[0];
|
float head;
|
if (float.TryParse(parts[1], out head))
|
r.Head = head;
|
r.PatternID = parts.Length > 2 ? parts[2] : "";
|
int level;
|
|
AddReservos(r);
|
}
|
break;
|
case "TANKS":
|
{
|
float initLevel = 0;
|
float.TryParse(parts[2], out initLevel);
|
|
float minLevel = 0;
|
float.TryParse(parts[3], out minLevel);
|
|
float maxLevel = 0;
|
float.TryParse(parts[4], out maxLevel);
|
|
float diamter = 0;
|
float.TryParse(parts[5], out diamter);
|
|
float minVol = 0;
|
float.TryParse(parts[6], out minVol);
|
var tank = new TankModel()
|
{
|
ID = parts[0],
|
Elev = float.Parse(parts[1]),
|
InitLevel = initLevel,
|
MinLevel = minLevel,
|
MaxLevel = maxLevel,
|
Diameter = diamter,
|
MinVol = minVol,
|
VolCurve = "",
|
IsOverFlow = true
|
};
|
AddTank(tank);
|
}
|
break;
|
case "PIPES":
|
{
|
PipeModel p = new PipeModel();
|
p.ID = parts[0];
|
p.Node1 = parts[1];
|
p.Node2 = parts[2];
|
float length;
|
if (float.TryParse(parts[3], out length))
|
p.Length = length;
|
float diameter;
|
if (float.TryParse(parts[4], out diameter))
|
p.Diameter = diameter;
|
float roughness;
|
if (float.TryParse(parts[5], out roughness))
|
p.Roughness = roughness;
|
float minorLoss;
|
if (float.TryParse(parts[6], out minorLoss))
|
p.MinorLoss = minorLoss;
|
p.Status = parts.Length > 7 ? StatusType.CLOSED : StatusType.DEFAULT;
|
AddPipe(p);
|
}
|
break;
|
case "VALVES":
|
{
|
ValveModel valve = new ValveModel();
|
valve.ID = parts[0];
|
|
valve.Node1 = parts[1];
|
valve.Node2 = parts[2];
|
|
float diameter;
|
if (float.TryParse(parts[3], out diameter))
|
valve.Diameter = diameter;
|
valve.Type = parts[4];
|
valve.CurvSetting = parts[5];
|
float minorLoss;
|
if (float.TryParse(parts[6], out minorLoss))
|
valve.MinorLoss = minorLoss;
|
AddValve(valve);
|
}
|
break;
|
case "REPEATERS":
|
{
|
|
}
|
break;
|
case "COORDINATES":
|
{
|
string id = parts[0];
|
float x;
|
float y;
|
if (float.TryParse(parts[1], out x) && float.TryParse(parts[2], out y))
|
{
|
points.Add(new Coor(id, new PointF(x, y)));
|
}
|
}
|
break;
|
}
|
}
|
}
|
sr.Close();
|
|
#region 坐标匹配方法
|
#endregion
|
|
|
|
#region 优化方案
|
int k1 = 0;
|
int k2 = 0;
|
|
|
Nodes.Sort((a, b) => string.Compare(a.ID, b.ID));
|
points.Sort((a, b) => string.Compare(a.ID, b.ID));
|
k1 = 0;
|
k2 = 0;
|
while (k1 < Nodes.Count)
|
{
|
var J = Nodes[k1];
|
var coor = points[k2];
|
|
while (J.ID != coor.ID && k2 < points.Count)
|
{
|
k2++;
|
if (k2 < points.Count) coor = points[k2];
|
|
}
|
if (k2 == points.Count)
|
{
|
throw new Exception($"未找到Node[{J.ID}]的坐标");
|
}
|
J.X = coor.Position.X;
|
J.Y = coor.Position.Y;
|
|
k1++;
|
}
|
#endregion
|
|
|
|
|
|
Links.Sort((a, b) => string.Compare(a.Node1, b.Node1));
|
k1 = 0;
|
k2 = 0;
|
while (k2 < Links.Count)
|
{
|
var p = Links[k2];
|
var J = Nodes[k1];
|
while (J.ID != p.Node1 && k1 < Nodes.Count)
|
{
|
k1++;
|
if (k1 < Nodes.Count) J = Nodes[k1];
|
|
}
|
if (k1 == Nodes.Count)
|
{
|
throw new Exception($"未找到Link[{p.ID}]的起始节点[{p.Node1}]");
|
}
|
k2++;
|
}
|
|
|
|
Links.Sort((a, b) => string.Compare(a.Node2, b.Node2));
|
k1 = 0;
|
k2 = 0;
|
while (k2 < Links.Count)
|
{
|
var p = Links[k2];
|
var J = Nodes[k1];
|
while (J.ID != p.Node2 && k1 < Nodes.Count)
|
{
|
k1++;
|
if (k1 < Nodes.Count) J = Nodes[k1];
|
}
|
if (k1 == Nodes.Count)
|
{
|
throw new Exception($"未找到Link[{p.ID}]的终止节点[{p.Node2}]");
|
}
|
k2++;
|
}
|
return true;
|
}
|
}
|
|
|
|
public static string ReplaceCoordinatesSection(string text, string content, string str)
|
{
|
string pattern = $@"(\[{content}\]).*?(\[|$)";
|
|
string replacedText = Regex.Replace(text, pattern, match =>
|
{
|
string section = match.Groups[2].Value.Trim();
|
|
if (!string.IsNullOrEmpty(section))
|
{
|
return $"{match.Groups[1].Value}\n{str}\n[";
|
}
|
else
|
{
|
return $"{match.Groups[1].Value}\n{str}\n[";
|
}
|
}, RegexOptions.Singleline);
|
|
return replacedText;
|
}
|
|
}
|
|
|
|
public partial class MapViewNetWork : NetWork
|
{
|
bool use_old = false;
|
public string Name;
|
private LinkViewModelList _links = new LinkViewModelList();
|
public LinkViewModelList Links { get { return _links; } set { base.Links = _links = value; } }
|
|
private NodeViewModelList _nodes = new NodeViewModelList();
|
public NodeViewModelList Nodes { get { return _nodes; } set { base.Nodes = _nodes = value; } }
|
|
private List<AreaViewModel> _areas = new List<AreaViewModel>();
|
public List<AreaViewModel> Areas { get { return _areas; } set { _areas = value; } }
|
|
public NodeViewModel StartPoint { get; set; }
|
|
public NodeViewModel EndPoint { get; set; }
|
|
public double[] getMinMax(ColourType colourType)
|
{
|
//根据当前选中的ColourType,判断是否有对应的网络数据
|
|
double max = 0;
|
double min = 0;
|
|
switch (colourType)
|
{
|
case ColourType.节点自由压力:
|
max = Nodes.Where(node => !(node is ReservoirViewModel || node is TankViewModel)).Max(node => node.EN_PRESSURE);
|
min = Nodes.Where(node => !(node is ReservoirViewModel || node is TankViewModel)).Min(node => node.EN_PRESSURE);
|
break;
|
case ColourType.节点绝对压力:
|
max = Nodes.Where(node => !(node is ReservoirViewModel || node is TankViewModel)).Max(node => node.EN_PRESSURE);
|
min = Nodes.Where(node => !(node is ReservoirViewModel || node is TankViewModel)).Min(node => node.EN_PRESSURE);
|
break;
|
case ColourType.节点需水量:
|
max = Nodes.Where(node => !(node is ReservoirViewModel || node is TankViewModel)).Max(node => node.EN_DEMAND);
|
min = Nodes.Where(node => !(node is ReservoirViewModel || node is TankViewModel)).Min(node => node.EN_DEMAND);
|
break;
|
case ColourType.管线流量:
|
max = Links.Max(link => link.EN_FLOW);
|
min = Links.Min(link => link.EN_FLOW);
|
break;
|
case ColourType.管线流速:
|
max = Links.Max(link => link.EN_VELOCITY);
|
min = Links.Min(link => link.EN_VELOCITY);
|
break;
|
default:
|
break;
|
|
}
|
return new double[] { min, max };
|
}
|
|
|
|
public Dictionary<string, Dataset> dict_dataset = new Dictionary<string, Dataset>();
|
|
public HashSet<string> Hash_ID;
|
|
|
public List<JunctionViewModel> junctions
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is JunctionViewModel).Select(n => n as JunctionViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is JunctionViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
|
|
public List<ReservoirViewModel> reservoirs
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is ReservoirViewModel).Select(n => n as ReservoirViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is ReservoirViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
|
public List<TankViewModel> tanks
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is TankViewModel).Select(n => n as TankViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is TankViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
|
public List<MeterViewModel> meters
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is MeterViewModel).Select(n => n as MeterViewModel).ToList();
|
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is MeterViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
|
public List<NozzleViewModel> nozzles
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is NozzleViewModel).Select(n => n as NozzleViewModel).ToList();
|
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is NozzleViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
|
|
public List<PipeViewModel> pipes
|
{
|
get
|
{
|
return Links.FindAll(n => n is PipeViewModel).Select(n => n as PipeViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Links.RemoveAll(n => n is PipeViewModel);
|
Links.AddRange(value);
|
}
|
}
|
|
public List<ValveViewModel> valves
|
{
|
get
|
{
|
return Links.FindAll(n => n is ValveViewModel).Select(n => n as ValveViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Links.RemoveAll(n => n is ValveViewModel);
|
Links.AddRange(value);
|
}
|
}
|
|
public List<ValveNodeViewModel> valveNodes
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is ValveNodeViewModel).Select(n => n as ValveNodeViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is ValveNodeViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
|
|
public List<RepeaterViewModel> repeaters
|
{
|
get
|
{
|
return Links.FindAll(n => n is RepeaterViewModel).Select(n => n as RepeaterViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Links.RemoveAll(n => n is RepeaterViewModel);
|
Links.AddRange(value);
|
}
|
}
|
|
public List<PumpViewModel> pumps
|
{
|
get
|
{
|
return Links.FindAll(n => n is PumpViewModel).Select(n => n as PumpViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Links.RemoveAll(n => n is PumpViewModel);
|
Links.AddRange(value);
|
}
|
}
|
|
public List<PumpNodeViewModel> pumpNodes
|
{
|
get
|
{
|
return Nodes.FindAll(n => n is PumpNodeViewModel).Select(n => n as PumpNodeViewModel).ToList();
|
}
|
set
|
{
|
if (value == null) return;
|
Nodes.RemoveAll(n => n is PumpNodeViewModel);
|
Nodes.AddRange(value);
|
}
|
}
|
public List<JunctionViewModel> Deserialized_junctions { get; set; }
|
public List<TankViewModel> Deserialized_tanks { get; set; }
|
public List<ReservoirViewModel> Deserialized_reservoirs { get; set; }
|
public List<MeterViewModel> Deserialized_meters { get; set; }
|
public List<NozzleViewModel> Deserialized_nozzles { get; set; }
|
public List<PipeViewModel> Deserialized_pipes { get; set; }
|
public List<ValveViewModel> Deserialized_valves { get; set; }
|
public List<ValveNodeViewModel> Deserialized_valveNodes { get; set; }
|
public List<RepeaterViewModel> Deserialized_repeaters { get; set; }
|
public List<PumpViewModel> Deserialized_pumps { get; set; }
|
public List<PumpNodeViewModel> Deserialized_pumpNodes { get; set; }
|
|
public List<AreaViewModel> areas = new List<AreaViewModel>();
|
|
public bool ReadFromJson(string json)
|
{
|
try
|
{
|
var net = JsonConvert.DeserializeObject<MapViewNetWork>(json);
|
junctions = net.Deserialized_junctions;
|
tanks = net.Deserialized_tanks;
|
reservoirs = net.Deserialized_reservoirs;
|
meters = net.Deserialized_meters;
|
nozzles = net.Deserialized_nozzles;
|
pipes = net.Deserialized_pipes;
|
valves = net.Deserialized_valves;
|
valveNodes = net.Deserialized_valveNodes;
|
repeaters = net.Deserialized_repeaters;
|
pumps = net.Deserialized_pumps;
|
pumpNodes = net.Deserialized_pumpNodes;
|
StartPoint = net.StartPoint;
|
EndPoint = net.EndPoint;
|
return true;
|
}
|
catch
|
{
|
return false;
|
}
|
|
|
|
}
|
public string WriteToJson()
|
{
|
var net = new MapViewNetWork();
|
net.Deserialized_junctions = junctions;
|
net.Deserialized_tanks = tanks;
|
net.Deserialized_reservoirs = reservoirs;
|
net.Deserialized_meters = meters;
|
net.Deserialized_nozzles = nozzles;
|
net.Deserialized_pipes = pipes;
|
net.Deserialized_valves = valves;
|
net.Deserialized_repeaters = repeaters;
|
net.Deserialized_pumps = pumps;
|
net.StartPoint = StartPoint;
|
net.EndPoint = EndPoint;
|
string json = JsonConvert.SerializeObject(net);
|
return json;
|
}
|
|
|
public JunctionViewModel AddJunction(string ID, PointF position, float z = 0)
|
{
|
JunctionViewModel j = new JunctionViewModel();
|
|
j.ID = ID;
|
j.Demand = 0;
|
j.PatternID = "";
|
j.Elev = z;
|
j.X = position.X;
|
j.Y = position.Y;
|
Nodes.Add(j);
|
return j;
|
}
|
public JunctionViewModel AddJunction(PointF position, float z = 0)
|
{
|
JunctionViewModel j = new JunctionViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(j)}{i}";
|
while (Nodes.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(j)}{i}";
|
}
|
j.ID = ID;
|
j.Elev = 0;
|
j.Demand = 0;
|
j.PatternID = "";
|
j.Elev = z;
|
j.X = position.X;
|
j.Y = position.Y;
|
Nodes.Add(j);
|
return j;
|
}
|
public MeterViewModel AddMeter(PointF position)
|
{
|
MeterViewModel j = new MeterViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(j)}{i}";
|
while (Nodes.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(j)}{i}";
|
}
|
j.ID = ID;
|
j.Elev = 0;
|
j.Demand = 0;
|
j.PatternID = "";
|
|
j.X = position.X;
|
j.Y = position.Y;
|
Nodes.Add(j);
|
|
return j;
|
}
|
public ReservoirViewModel AddReservoir(PointF position)
|
{
|
ReservoirViewModel j = new ReservoirViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(j)}{i}";
|
while (Nodes.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(j)}{i}";
|
}
|
j.ID = ID;
|
j.Elev = 0;
|
j.Demand = 0;
|
j.PatternID = "";
|
j.Head = 100;
|
j.X = position.X;
|
j.Y = position.Y;
|
Nodes.Add(j);
|
|
return j;
|
}
|
public TankViewModel AddTank(PointF position)
|
{
|
TankViewModel j = new TankViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(j)}{i}";
|
while (Nodes.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(j)}{i}";
|
}
|
j.ID = ID;
|
j.Elev = 0;
|
j.Demand = 0;
|
j.PatternID = "";
|
|
j.X = position.X;
|
j.Y = position.Y;
|
Nodes.Add(j);
|
|
return j;
|
}
|
public PipeViewModel AddPipe(NodeViewModel node1, NodeViewModel node2)
|
{
|
PipeViewModel pipe = new PipeViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(pipe)}{i}";
|
while (Links.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(pipe)}{i}";
|
}
|
pipe.ID = ID;
|
pipe.Diameter = 100;
|
pipe.MinorLoss = 0;
|
pipe.Roughness = 100;
|
pipe.Status = StatusType.DEFAULT;
|
pipe.StartNode = node1;
|
pipe.EndNode = node2;
|
pipe.Length = -1;
|
|
|
|
Links.Add(pipe);
|
return pipe;
|
}
|
public ValveViewModel AddValve(NodeViewModel node1, NodeViewModel node2)
|
{
|
ValveViewModel valve = new ValveViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(valve)}{i}";
|
while (Links.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(valve)}{i}";
|
}
|
valve.ID = ID;
|
|
valve.Diameter = 100;
|
valve.Status = StatusType.DEFAULT;
|
valve.StartNode = node1;
|
valve.EndNode = node2;
|
|
Links.Add(valve);
|
|
return valve;
|
}
|
public RepeaterViewModel AddRepeater(NodeViewModel node1, NodeViewModel node2)
|
{
|
RepeaterViewModel repeater = new RepeaterViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(repeater)}{i}";
|
while (Links.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(repeater)}{i}";
|
}
|
repeater.ID = ID;
|
|
|
repeater.StartNode = node1;
|
repeater.EndNode = node2;
|
|
Links.Add(repeater);
|
|
return repeater;
|
}
|
public PumpViewModel AddPump(NodeViewModel node1, NodeViewModel node2)
|
{
|
PumpViewModel pump = new PumpViewModel();
|
int i = 0;
|
string ID = $"{Default.GetPreString(pump)}{i}";
|
while (Links.Find(p0 => p0.ID == ID) != null)
|
{
|
i++;
|
ID = $"{Default.GetPreString(pump)}{i}";
|
}
|
pump.ID = ID;
|
|
|
pump.StartNode = node1;
|
pump.EndNode = node2;
|
|
Links.Add(pump);
|
|
return pump;
|
}
|
|
public List<IBaseViewModel> Remove(List<IBaseViewModel> list)
|
{
|
|
List<IBaseViewModel> objs = new List<IBaseViewModel>();
|
list.ForEach(o =>
|
{
|
if (o == null) return;
|
o.Selected = false;
|
if (o is NodeViewModel n)
|
{
|
n.Links.ForEach(l =>
|
{
|
if (this.Links.Remove(l)) objs.Add((LinkViewModel)l);
|
});
|
if (this.Nodes.Remove(n)) objs.Add(n);
|
|
}
|
else if (o is LinkViewModel l)
|
{
|
if (this.Links.Remove(l)) objs.Add(l);
|
|
}
|
});
|
return objs;
|
|
}
|
|
public void ChangePoint(NodeViewModel source, NodeViewModel newPoint)
|
{
|
Links.ForEach(l =>
|
{
|
if (l.StartNode == source)
|
{
|
l.StartNode = newPoint;
|
}
|
else if (l.EndNode == source)
|
{
|
l.EndNode = newPoint;
|
}
|
|
});
|
source.Visible = false;
|
}
|
public void ChangeNodeID(NodeViewModel node, string ID)
|
{
|
node.ID = ID;
|
node.Links.ForEach(l =>
|
{
|
if (l.StartNode == node)
|
{
|
l.Node1 = node.ID;
|
}
|
else
|
{
|
l.Node2 = node.ID;
|
}
|
});
|
}
|
public string GetValidID(IBaseViewModel obj)
|
{
|
string DefaultString = Default.GetPreString(obj);
|
int i = 0;
|
string ID = obj.ID;
|
ID = $"{DefaultString}{i}";
|
while (Hash_ID.Contains(ID))
|
{
|
ID = $"{DefaultString}{i}";
|
i++;
|
}
|
return ID;
|
}
|
|
public MapViewNetWork CreateNew(PointF3D basepoint)
|
{
|
MapViewNetWork net = this.DeepCopy<MapViewNetWork>();
|
var BasePos = StartPoint.Position3D;
|
|
net.Nodes.ForEach(n =>
|
{
|
n.X += basepoint.X - BasePos.X;
|
n.Y += basepoint.Y - BasePos.Y;
|
n.Elev += basepoint.Z - BasePos.Z;
|
});
|
|
return net;
|
}
|
|
public void AddJoinNet(MapViewNetWork network)
|
{
|
|
if (Nodes.Count == 0)
|
{
|
Nodes.AddRange(network.Nodes);
|
Links.AddRange(network.Links);
|
StartPoint = network.StartPoint;
|
EndPoint = network.EndPoint;
|
}
|
else
|
{
|
|
ChangePoint(EndPoint, network.StartPoint);
|
Nodes.AddRange(network.Nodes);
|
Links.AddRange(network.Links);
|
EndPoint = network.EndPoint;
|
}
|
}
|
public List<IBaseViewModel> Add(MapViewNetWork net0, PointF3D offset = null, bool isCopy = false, NodeViewModel ConnectNode = null)
|
{
|
if (offset == null)
|
{
|
offset = new PointF3D(0, 0, 0);
|
}
|
List<IBaseViewModel> list = new List<IBaseViewModel>();
|
if (Hash_ID == null) Hash_ID = new HashSet<string>();
|
|
MapViewNetWork net = isCopy ? net0.DeepCopy() : net0;
|
net.Nodes.ForEach(n0 =>
|
{
|
NodeViewModel n = (NodeViewModel)n0;
|
if (Hash_ID.Contains(n.ID))
|
{
|
string ID = GetValidID(n);
|
net.ChangeNodeID(n, ID);
|
}
|
n.X += offset.X;
|
n.Y += offset.Y;
|
n.Elev += offset.Z;
|
Nodes.Add(n);
|
Hash_ID.Add(n.ID);
|
list.Add(n);
|
if (n0 == net.EndPoint && list[0] != n)
|
{
|
int index = list.IndexOf(n);
|
var o = list[0];
|
list[0] = n;
|
list[index] = o;
|
}
|
});
|
net.Links.ForEach(l0 =>
|
{
|
LinkViewModel l = (LinkViewModel)l0;
|
if (Hash_ID.Contains(l.ID))
|
{
|
string ID = GetValidID(l);
|
l.ID = ID;
|
}
|
Links.Add(l);
|
Hash_ID.Add(l.ID);
|
list.Add(l);
|
});
|
if (ConnectNode != null)
|
{
|
var l = AddPipe(ConnectNode, net.StartPoint);
|
list.Add(l);
|
Hash_ID.Add(l.ID);
|
}
|
return list;
|
}
|
|
|
public void Add(List<IBaseViewModel> objects)
|
{
|
Nodes.AddRange(objects.FindAll(o => o is NodeViewModel).Select(o => (NodeViewModel)o));
|
Links.AddRange(objects.FindAll(o => o is LinkViewModel).Select(o => (LinkViewModel)o));
|
}
|
|
public void Clear()
|
{
|
Nodes.Clear();
|
Links.Clear();
|
}
|
|
|
public List<IBaseViewModel> MapObjects
|
{
|
get
|
{
|
List<BaseModel> objects = new List<BaseModel>();
|
objects.AddRange(Nodes);
|
objects.AddRange(Links);
|
return objects.Select(o => (IBaseViewModel)o).ToList();
|
}
|
}
|
public void Rename()
|
{
|
MapObjects.ForEach(o => o.ID = $"{Name}_{o.ID}");
|
}
|
public void Add(RepeaterViewModel repeater)
|
{
|
ChangePoint(repeater.StartNode, repeater.StartNode_inner);
|
MoveDownNetwork(repeater);
|
ChangePoint(repeater.EndNode, repeater.EndNode_inner);
|
|
Nodes.AddRange(repeater.netList.Nodes);
|
Links.AddRange(repeater.netList.Links);
|
}
|
public void LoadRepeaters(int MaxLevel, dict<string, dynamic> param, Dictionary<TemplateType, bool> viewModel, bool ViewMode = true)
|
{
|
|
|
repeaters.ForEach(r =>
|
{
|
|
if (!r.Load(MaxLevel, param, viewModel, ViewMode))
|
{
|
r.Status = RepeaterViewModel.RepeatStatus.收起;
|
r.Visible = true;
|
}
|
|
else
|
{
|
Add(r);
|
r.Visible = false;
|
}
|
|
|
});
|
}
|
|
public void MoveDownNetwork(RepeaterViewModel repeater)
|
{
|
visited = new Dictionary<NodeViewModel, bool>();
|
visited.Add(repeater.StartNode, true);
|
var p1 = repeater.EndNode_inner;
|
var p2 = repeater.EndNode;
|
PointF3D p = new PointF3D(p1.X - p2.X, p1.Y - p2.Y, p1.Elev - p2.Elev);
|
BFS(this, repeater.EndNode, new Vector3(p.X, p.Y, p.Z));
|
|
}
|
|
|
// 定义 visited 字典记录已访问过的节点和待访问的节点队列
|
Dictionary<NodeViewModel, bool> visited;
|
private bool _isCalculated = false;
|
|
public void BFS(MapViewNetWork net, NodeViewModel startNode, Vector3 vector)
|
{
|
|
Queue<NodeViewModel> queue = new Queue<NodeViewModel>();
|
|
// 标记起始节点为已访问,并加入队列
|
visited[startNode] = true;
|
queue.Enqueue(startNode);
|
|
// 不断从队列中取出节点进行访问,直到队列为空
|
while (queue.Count > 0)
|
{
|
// 取出队首节点并输出
|
NodeViewModel node = queue.Dequeue();
|
node.Move(vector);
|
|
|
// 遍历当前节点的所有未访问邻居节点,并标记为已访问
|
foreach (LinkViewModel link in net.Links)
|
{
|
if (link.StartNode == node && !visited.ContainsKey(link.EndNode))
|
{
|
visited[link.EndNode] = true;
|
queue.Enqueue(link.EndNode);
|
|
}
|
else if (link.EndNode == node && !visited.ContainsKey(link.StartNode))
|
{
|
visited[link.StartNode] = true;
|
queue.Enqueue(link.StartNode);
|
}
|
}
|
}
|
}
|
|
public List<NodeViewModel> GetNode(string node)
|
{
|
return Nodes.FindAll(n => n.ID == node).Select(n => (NodeViewModel)n).ToList();
|
}
|
|
|
public Dictionary<string, List<string>> CheckValidate()
|
{
|
BuildRelation();
|
string result = null;
|
Dictionary<string, List<string>> result_dict = new Dictionary<string, List<string>>();
|
StringBuilder result_sb = new StringBuilder();
|
//to-do
|
var objs = Links.Select(o => o as LinkViewModel).ToList();//new List<LinkViewModel>() { Links[0] }; //Links.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel).ToList();
|
//objs去掉重复的元素
|
objs = objs.Distinct().ToList();
|
var visitedNodes = new HashSet<NodeViewModel>();
|
FindObjs = new HashSet<IBaseViewModel>();
|
objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes));
|
List<string> list_孤立点 = new List<string>();
|
for (int i = 0; i < Nodes.Count; i++)
|
{
|
if (!FindObjs.Contains(Nodes[i]))
|
{
|
result_sb.AppendLine($"节点{Nodes[i].ID}是孤立点");
|
list_孤立点.Add(Nodes[i].ID);
|
}
|
|
}
|
if (list_孤立点.Count > 0) result_dict.Add("孤立点", list_孤立点);
|
//属性判断
|
var list_管道连接关系异常 = new List<string>();
|
var list_管道长度小于等于0 = new List<string>();
|
var list_粗糙系数设置错误 = new List<string>();
|
var list_管径设置错误 = new List<string>();
|
|
pipes.ForEach(p =>
|
{
|
if (p.StartNode == null || p.EndNode == null)
|
{
|
result_sb.AppendLine($"{p.ID}管道连接关系异常");
|
list_管道连接关系异常.Add(p.ID);
|
}
|
if (p.Length <= 0)
|
{
|
result_sb.AppendLine($"{p.ID}管道长度小于等于0");
|
list_管道长度小于等于0.Add(p.ID);
|
}
|
if (p.Roughness <= 0.1 || p.Roughness > 10000)
|
{
|
result_sb.AppendLine($"{p.ID}粗糙系数设置错误");
|
list_粗糙系数设置错误.Add(p.ID);
|
}
|
if (p.Diameter <= 0.1 || p.Diameter > 10000)
|
{
|
result_sb.AppendLine($"{p.ID}管径设置错误");
|
list_管径设置错误.Add(p.ID);
|
}
|
|
});
|
if (list_管道连接关系异常.Count > 0) result_dict.Add("管道连接关系异常", list_管道连接关系异常);
|
if (list_管道长度小于等于0.Count > 0) result_dict.Add("管道长度小于等于0", list_管道长度小于等于0);
|
if (list_粗糙系数设置错误.Count > 0) result_dict.Add("粗糙系数设置错误", list_粗糙系数设置错误);
|
if (list_管径设置错误.Count > 0) result_dict.Add("管径设置错误", list_管径设置错误);
|
return result_dict;
|
|
|
|
}
|
HashSet<IBaseViewModel> FindObjs;
|
private void TraversePipeNetworkALL(LinkViewModel startLink, HashSet<NodeViewModel> visitedNodes = null, int direction = 0)
|
{
|
|
Queue<LinkViewModel> queue = new Queue<LinkViewModel>();
|
|
|
|
queue.Enqueue(startLink);
|
if (visitedNodes == null)
|
visitedNodes = new HashSet<NodeViewModel>();
|
|
while (queue.Count > 0)
|
{
|
LinkViewModel currentLink = queue.Dequeue();
|
|
foreach (var node in new NodeViewModel[] { currentLink.StartNode, currentLink.EndNode })
|
{
|
if (direction == 1 && currentLink.EN_FLOW >= 0 && node == currentLink.StartNode) continue;
|
if (direction == -1 && currentLink.EN_FLOW <= 0 && node == currentLink.EndNode) continue;
|
if (node != null && !visitedNodes.Contains(node))
|
{
|
visitedNodes.Add(node);
|
if (!FindObjs.Contains(node)) FindObjs.Add(node);
|
|
foreach (var link in node.ViewLinks)
|
{
|
if (!visitedNodes.Contains(link.StartNode) || !visitedNodes.Contains(link.EndNode))
|
{
|
|
if (!FindObjs.Contains(link)) FindObjs.Add(link);
|
queue.Enqueue(link);
|
|
|
|
|
}
|
}
|
}
|
}
|
|
}
|
|
|
|
}
|
|
|
public void SetNodeDemand()
|
{
|
Nodes.ForEach(n =>
|
{
|
if (n is NodeViewModel node && node.Demand == 0)
|
{
|
node.Demand = 0.01f;
|
}
|
else if (n is MeterViewModel meter && meter.Demand == 0)
|
{
|
meter.Demand = 0.01f;
|
}
|
else if (n is NozzleViewModel nozzle && nozzle.Demand == 0)
|
{
|
nozzle.Demand = 0.01f;
|
}
|
});
|
}
|
}
|
|
|
//构造一个List<LinkViewModel>类,能够实现List的所有功能
|
|
public class LinkViewModelList : List<LinkCalcModel>
|
{
|
//List<LinkCalcModel> base;
|
Dictionary<string, LinkViewModel> dict;//
|
public LinkViewModelList() : base()
|
{
|
this.dict = new Dictionary<string, LinkViewModel>();
|
}
|
|
public List<LinkViewModel> ViewLinks
|
{
|
get
|
{
|
var list = new List<LinkViewModel>();
|
base.ForEach(l =>
|
{
|
//if (l is LinkViewModel)
|
list.Add((LinkViewModel)l);
|
});
|
return list;
|
//return base.Select(l => (LinkViewModel)l).ToList();
|
}
|
}
|
|
|
/// 实现Add方法,同时更新字典
|
public void Add(LinkViewModel linkCalcModel)
|
{
|
base.Add(linkCalcModel);
|
if (!dict.ContainsKey(linkCalcModel.ID))
|
dict.Add(linkCalcModel.ID, linkCalcModel);
|
}
|
|
/// 实现AddRange方法,同时更新字典
|
|
/// <param name="linkCalcModels"></param>
|
public void AddRange(List<LinkViewModel> linkCalcModels)
|
{
|
base.AddRange(linkCalcModels);
|
linkCalcModels.ForEach(link =>
|
{
|
if (!dict.ContainsKey(link.ID))
|
dict.Add(link.ID, link);
|
});
|
}
|
|
|
public LinkViewModel this[string ID]
|
{
|
get
|
{
|
if (dict.ContainsKey(ID))
|
return dict[ID];
|
else
|
return (LinkViewModel)base.Find(l => l.ID == ID);
|
}
|
}
|
public LinkViewModel this[int index]
|
{
|
get
|
{
|
return (LinkViewModel)base[index];
|
}
|
}
|
|
public void Sort()
|
{
|
base.Sort();
|
}
|
public void Sort(Comparison<LinkCalcModel> comparison)
|
{
|
base.Sort(comparison);
|
}
|
|
public void Select(Action<LinkViewModel> action)
|
{
|
ViewLinks.ForEach(action);
|
}
|
//实现Find方法
|
public LinkViewModel Find(Predicate<LinkViewModel> match)
|
{
|
//base.Find(match);
|
return ViewLinks.Find(match);
|
}
|
//实现FindAll方法
|
public List<LinkViewModel> FindAll(Predicate<LinkViewModel> match)
|
{
|
return ViewLinks.FindAll(match);
|
}
|
//实现ForEach方法
|
public void ForEach(Action<LinkViewModel> action)
|
{
|
ViewLinks.ForEach(action);
|
}
|
//实现RemoveAll方法
|
public int RemoveAll(Predicate<LinkCalcModel> match)
|
{
|
return base.RemoveAll(match);
|
}
|
|
/// 实现Remove方法,同时更新字典
|
|
public bool Remove(LinkViewModel linkCalcModel)
|
{
|
if (base.Remove(linkCalcModel))
|
{
|
if (dict.ContainsKey(linkCalcModel.ID))
|
dict.Remove(linkCalcModel.ID);
|
return true;
|
}
|
else
|
return false;
|
}
|
|
|
}
|
|
public class NodeViewModelList : List<NodeCalcModel>
|
{
|
Dictionary<string, NodeCalcModel> dict;
|
public NodeViewModelList() : base()
|
{
|
this.dict = new Dictionary<string, NodeCalcModel>();
|
}
|
|
|
public void ChangeID(string oldID, string newID)
|
{
|
if (dict.ContainsKey(oldID))
|
{
|
dict[oldID].ID = newID;
|
dict.Add(newID, dict[oldID]);
|
dict.Remove(oldID);
|
}
|
}
|
|
/// 实现Add方法,同时更新字典
|
public void Add(NodeViewModel nodeCalcModel)
|
{
|
base.Add(nodeCalcModel);
|
if (!dict.ContainsKey(nodeCalcModel.ID))
|
dict.Add(nodeCalcModel.ID, nodeCalcModel);
|
}
|
|
/// 实现AddRange方法,同时更新字典
|
/// <param name="nodeCalcModels"></param>
|
public void AddRange(List<NodeViewModel> nodeCalcModels)
|
{
|
base.AddRange(nodeCalcModels);
|
nodeCalcModels.ForEach(node =>
|
{
|
if (!dict.ContainsKey(node.ID))
|
dict.Add(node.ID, node);
|
});
|
}
|
|
/// 实现Remove方法,同时更新字典
|
public bool Remove(NodeViewModel nodeCalcModel)
|
{
|
if (base.Remove(nodeCalcModel))
|
{
|
if (dict.ContainsKey(nodeCalcModel.ID))
|
dict.Remove(nodeCalcModel.ID);
|
return true;
|
}
|
else
|
return false;
|
}
|
|
|
/// 统计数量
|
public int Count { get { return base.Count; } }
|
public NodeViewModel this[string ID]
|
{
|
get
|
{
|
if (dict.ContainsKey(ID))
|
return (NodeViewModel)dict[ID];
|
else
|
return (NodeViewModel)base.Find(l => l.ID == ID);
|
}
|
}
|
public NodeViewModel this[int index]
|
{
|
get
|
{
|
return (NodeViewModel)base[index];
|
}
|
}
|
|
public List<NodeViewModel> ViewNodes
|
{
|
get
|
{
|
List<NodeViewModel> list = new List<NodeViewModel>();
|
foreach (var item in this)
|
{
|
list.Add((NodeViewModel)item);
|
}
|
return list;
|
}
|
|
}
|
|
|
|
public NodeViewModel Find(Predicate<NodeViewModel> match)
|
{
|
return ViewNodes.Find(match);
|
}
|
//实现FindAll方法
|
public List<NodeViewModel> FindAll(Predicate<NodeViewModel> match)
|
{
|
return ViewNodes.FindAll(match);
|
}
|
//实现ForEach方法
|
public void ForEach(Action<NodeViewModel> action)
|
{
|
ViewNodes.ForEach(action);
|
}
|
|
|
}
|
|
|
public partial class MapViewNetWork
|
{
|
public bool BuildFromInp(string filePath, bool use_old = false)
|
{
|
this.use_old = use_old;
|
if (this.use_old)
|
{
|
return loadInpFile_old(filePath);
|
}
|
if (filePath == null || !File.Exists(filePath)) return false;
|
List<Coor> points = new List<Coor>();
|
dict_dataset = new Dictionary<string, Dataset>();
|
StreamReader sr = new StreamReader(filePath);
|
|
{
|
Nodes = new NodeViewModelList();
|
Links = new LinkViewModelList();
|
|
string line;
|
string section = "";
|
while ((line = sr.ReadLine()) != null)
|
{
|
if (line.Trim().StartsWith("["))
|
{
|
section = line.TrimStart('[').TrimEnd(']');
|
}
|
else
|
{
|
string s = line.Trim('\t').Trim(' ');
|
if (s.Length == 0 || s[0] == ';') continue;
|
Parts parts = new Parts(line);
|
section = section.ToUpper();
|
IBaseViewModel o = null;
|
switch (section)
|
{
|
case "JUNCTIONS":
|
{
|
NodeViewModel j = null;
|
if (parts[-2] == "Meter")
|
{
|
var m = new MeterViewModel();
|
j = m;
|
}
|
else if (parts[-2] == "Nozzle")
|
{
|
var n = new NozzleViewModel();
|
j = n;
|
n.FlowCoefficient = parts.ToFloat(-4, 0);
|
}
|
else
|
j = new JunctionViewModel();
|
|
o = j;
|
j.ID = parts.ToString(0, null);
|
j.Elev = parts.ToFloat(1, 0);
|
j.Demand = parts.ToFloat(2, 0);
|
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();
|
o = r;
|
r.ID = parts.ToString(0, null);
|
r.Head = parts.ToFloat(1, 0);
|
r.PatternID = parts.ToString(2, null);
|
r.Level = parts.ToInt(-1, 0);
|
r.Elev = parts.ToFloat(-2, 0);
|
Nodes.Add(r);
|
}
|
break;
|
|
case "TANKS":
|
{
|
TankViewModel tank = new TankViewModel();
|
o = tank;
|
tank.ID = parts.ToString(0, null);
|
tank.Elev = parts.ToFloat(1, 0);
|
tank.InitLevel = parts.ToFloat(2, 0);
|
tank.MinLevel = parts.ToFloat(3, 0);
|
tank.MaxLevel = parts.ToFloat(4, 0);
|
tank.Diameter = parts.ToFloat(5, 0);
|
tank.MinVol = parts.ToFloat(6, 0);
|
tank.VolCurve = parts.ToString(7, null);
|
tank.Overflow = "";
|
tank.Level = parts.ToInt(-1, 0);
|
Nodes.Add(tank);
|
}
|
break;
|
|
case "PIPES":
|
{
|
if (parts[-2] == "Repeater")
|
{
|
RepeaterViewModel repeater = new RepeaterViewModel();
|
o = repeater;
|
repeater.ID = parts.ToString(0, null);
|
repeater.Node1 = parts.ToString(1, null);
|
repeater.Node2 = parts.ToString(2, null);
|
repeater.Length = parts.ToFloat(3, 0.1f);
|
repeater.Diameter = parts.ToFloat(4, 150f);
|
repeater.Roughness = parts.ToFloat(5, 100f);
|
repeater.MinorLoss = parts.ToFloat(6, 0);
|
repeater.Level = parts.ToInt(-1, 0);
|
repeater.TemplateID = parts.ToString(-3, null);
|
repeater.RepeatTimes = parts.ToInt(-4, 1);
|
RepeatStatus status;
|
if (Enum.TryParse(parts[-5], out status))
|
repeater.Status = status;
|
repeater.NetworkPreName = parts.ToString(-6, null);
|
repeater.NetworkPreStartNum = parts.ToInt(-7, 0);
|
repeater.NetworkIsAscNum = parts.ToBool(-8, false);
|
repeater.NetworkShowName = parts.ToString(-9, null);
|
|
Links.Add(repeater);
|
}
|
else
|
{
|
PipeViewModel p = new PipeViewModel();
|
o = p;
|
p.ID = parts.ToString(0, null);
|
p.Node1 = parts.ToString(1, null);
|
p.Node2 = parts.ToString(2, null);
|
p.Length = parts.ToFloat(3, 0.1f);
|
p.Diameter = parts.ToFloat(4, 150f);
|
p.Roughness = parts.ToFloat(5, 100f);
|
p.MinorLoss = parts.ToFloat(6, 0);
|
p.Status = StringToStatus(parts.ToString(7, "OPEN"));
|
|
p.Level = parts.ToInt(-1, 0);
|
Links.Add(p);
|
}
|
}
|
break;
|
|
case "VALVES":
|
{
|
ValveViewModel valve = new ValveViewModel();
|
o = valve;
|
valve.ID = parts.ToString(0, null);
|
|
valve.Node1 = parts.ToString(1, null);
|
valve.Node2 = parts.ToString(2, null);
|
valve.Diameter = parts.ToFloat(3, 0);
|
valve.Type = parts.ToString(4, null);
|
valve.Setting = parts.ToString(5, null);
|
valve.MinorLoss = parts.ToFloat(6, 0);
|
valve.Level = parts.ToInt(-1, 0);
|
Links.Add(valve);
|
}
|
break;
|
|
case "PUMPS":
|
{
|
PumpViewModel pump = new PumpViewModel();
|
o = pump;
|
pump.ID = parts.ToString(0, null);
|
|
pump.Node1 = parts.ToString(1, null);
|
pump.Node2 = parts.ToString(2, null);
|
int index = 3;
|
string label = null;
|
while ((label = parts.ToString(index, null)) != null)
|
{
|
label = label.ToUpper();
|
switch (label)
|
{
|
case "HEAD":
|
pump.HeadCurve = parts.ToString(index + 1, "PumpDefault");
|
break;
|
|
case "SPEED":
|
pump.当前转速 = parts.ToFloat(index + 1, 0);
|
break;
|
}
|
index += 2;
|
}
|
|
pump.Level = parts.ToInt(-1, 0);
|
Links.Add(pump);
|
}
|
break;
|
|
case "CURVES":
|
{
|
string ID = parts.ToString(0, "");
|
if (!dict_dataset.ContainsKey(ID))
|
{
|
var ds = new Dataset(ID, null);
|
dict_dataset.Add(ID, ds);
|
}
|
dict_dataset[ID]._data.Add(new PointF(parts.ToFloat(1, 0), parts.ToFloat(2, 0)));
|
}
|
break;
|
|
case "COORDINATES":
|
{
|
string id = parts[0];
|
float x;
|
float y;
|
if (float.TryParse(parts[1], out x) && float.TryParse(parts[2], out y))
|
{
|
points.Add(new Coor(id, new PointF(x, y)));
|
}
|
}
|
break;
|
|
case "STATUS":
|
{
|
LinkViewModel link = Links.Find(l => l.ID == parts.ToString(0, null));
|
if (link != null)
|
link.Status = StringToStatus(parts.ToString(1, "OPEN"));
|
}
|
break;
|
}
|
if (o != null)
|
{
|
o.Tags = new TagList(parts.ToString(-3, null));
|
}
|
}
|
}
|
sr.Close();
|
|
if (!dict_dataset.ContainsKey("GPVDefault"))
|
{
|
var data = new Dataset("GPVDefault", null);
|
data.Data = new List<PointF>()
|
{
|
new PointF(0,0),
|
new PointF(100,0),
|
};
|
dict_dataset.Add("GPVDefault", data);
|
}
|
if (!dict_dataset.ContainsKey("PumpDefault"))
|
{
|
var data = new Dataset("PumpDefault", null);
|
data.Data = new List<PointF>()
|
{
|
new PointF(0f, 45.38f),
|
new PointF(83.33333333f ,45.25f),
|
new PointF(111.1111111f ,45.12f),
|
new PointF(138.8888889f ,44.96f),
|
new PointF(166.6666667f ,44.76f),
|
new PointF(194.4444444f ,44.52f),
|
new PointF(222.2222222f ,44.24f),
|
new PointF(250f ,43.92f),
|
new PointF(277.7777778f ,43.56f),
|
new PointF(305.5555556f ,43.17f),
|
new PointF(333.3333333f ,42.73f),
|
new PointF(361.1111111f ,42.25f),
|
new PointF(388.8888889f ,41.74f),
|
new PointF(416.6666667f ,41.18f),
|
new PointF(444.4444444f ,40.58f),
|
new PointF(472.2222222f ,39.95f),
|
new PointF(500f ,39.28f),
|
new PointF(527.7777778f ,38.56f),
|
new PointF(555.5555556f ,37.81f),
|
new PointF(583.3333333f ,37.02f),
|
new PointF(611.1111111f ,36.19f),
|
new PointF(638.8888889f ,35.32f),
|
new PointF(666.6666667f ,34.41f),
|
new PointF(694.4444444f ,33.46f),
|
new PointF(722.2222222f ,32.47f),
|
new PointF(750f ,31.44f),
|
new PointF(777.7777778f ,30.37f),
|
new PointF(805.5555556f ,29.27f),
|
};
|
dict_dataset.Add("PumpDefault", data);
|
}
|
|
//读取坐标
|
int k1 = 0;
|
int k2 = 0;
|
Nodes.Sort((a, b) => string.Compare(a.ID, b.ID));
|
points.Sort((a, b) => string.Compare(a.ID, b.ID));
|
k1 = 0;
|
k2 = 0;
|
while (k1 < Nodes.Count)
|
{
|
var J = Nodes[k1];
|
var coor = points[k2];
|
|
while (J.ID != coor.ID && k2 < points.Count)
|
{
|
k2++;
|
if (k2 < points.Count) coor = points[k2];
|
}
|
if (k2 == points.Count)
|
{
|
throw new Exception($"未找到Node[{J.ID}]的坐标");
|
}
|
J.X = coor.Position.X;
|
J.Y = coor.Position.Y;
|
|
k1++;
|
}
|
|
BuildRelation();
|
|
return true;
|
}
|
}
|
|
private StatusType StringToStatus(string status)
|
{
|
switch (status)
|
{
|
case "CLOESD":
|
case "0":
|
return StatusType.CLOSED;
|
|
case "OPEN":
|
case "1":
|
return StatusType.OPEN;
|
|
case "ACTIVE":
|
return StatusType.ACTIVE;
|
|
default:
|
return StatusType.DEFAULT;
|
}
|
}
|
|
public void BuildRelation()
|
{
|
//读取坐标
|
int k1 = 0;//表示管线索引
|
int k2 = 0;//表示节点索引
|
Nodes.Sort((a, b) => string.Compare(a.ID, b.ID));
|
|
|
|
Links.Sort((a, b) => string.Compare(a.Node1, b.Node1));
|
k2 = 0;
|
k1 = 0;
|
while (k1 < Links.Count)
|
{
|
var p = Links[k1];
|
var J = Nodes[k2];
|
var k0 = k2;
|
while (J.ID != p.Node1 && k2 < Nodes.Count)
|
{
|
k2++;
|
if (k2 < Nodes.Count) J = Nodes[k2];
|
}
|
if (k2 == Nodes.Count)
|
{
|
k2 = k0;
|
k1++;
|
p.Visible = false;
|
continue;
|
//throw new Exception($"未找到Link[{p.ID}]的起始节点[{p.Node1}]");
|
}
|
p.StartNode = J;
|
p.Node1 = J.ID;
|
if (J.MaxDiameter < p.Diameter) J.MaxDiameter = p.Diameter;
|
J.Links.Add(p);
|
k1++;
|
}
|
|
|
|
Links.Sort((a, b) => string.Compare(a.Node2, b.Node2));
|
k2 = 0;
|
k1 = 0;
|
while (k1 < Links.Count)
|
{
|
var p = Links[k1];
|
var J = Nodes[k2];
|
var k0 = k2;
|
while (J.ID != p.Node2 && k2 < Nodes.Count)
|
{
|
k2++;
|
if (k2 < Nodes.Count) J = Nodes[k2];
|
}
|
if (k2 == Nodes.Count)
|
{
|
k2 = k0;
|
k1++;
|
p.Visible = false;
|
|
continue;
|
}
|
p.EndNode = J;
|
p.Node2 = J.ID;
|
if (J.MaxDiameter < p.Diameter) J.MaxDiameter = p.Diameter;
|
J.Links.Add(p);
|
k1++;
|
}
|
|
foreach (ValveNodeViewModel vn in valveNodes.ToList())
|
{
|
if (vn.Links.Count != 2) continue;
|
|
var junc1 = AddJunction("S__" + vn.ID, vn.Position, vn.Elev);
|
if (vn.Links[0].StartNode.ID == vn.ID)
|
{
|
vn.Links[0].StartNode = junc1;
|
}
|
else
|
{
|
vn.Links[0].EndNode = junc1;
|
}
|
junc1.Links.Add(vn.Links[0]);
|
|
var junc2 = AddJunction("E__" + vn.ID, vn.Position, vn.Elev);
|
if (vn.Links[1].StartNode.ID == vn.ID)
|
{
|
vn.Links[1].StartNode = junc2;
|
}
|
else
|
{
|
vn.Links[1].EndNode = junc2;
|
}
|
junc2.Links.Add(vn.Links[1]);
|
ValveViewModel valve = AddValve(junc1, junc2);
|
|
valve.ID = vn.ID;
|
valve.Status = vn.Status;
|
junc1.Links.Add(valve);
|
junc2.Links.Add(valve);
|
Nodes.Remove(vn);
|
}
|
|
foreach (PumpNodeViewModel pn in pumpNodes.ToList())
|
{
|
if (pn.Links.Count != 2) continue;
|
if (pn.Links[0].ID != pn.Node1)
|
{
|
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)
|
{
|
pn.Links[0].StartNode = junc1;
|
}
|
else
|
{
|
pn.Links[0].EndNode = junc1;
|
}
|
junc1.Links.Add(pn.Links[0]);
|
|
var junc2 = AddJunction("E__" + pn.ID, pn.Position, pn.Elev);
|
if (pn.Links[1].StartNode.ID == pn.ID)
|
{
|
pn.Links[1].StartNode = junc2;
|
}
|
else
|
{
|
pn.Links[1].EndNode = junc2;
|
}
|
junc2.Links.Add(pn.Links[1]);
|
PumpViewModel pump = AddPump(junc1, junc2);
|
pump.Status = pn.Status;
|
pump.ID = pn.ID;
|
pump.额定功率 = pn.额定功率;
|
pump.额定扬程 = pn.额定扬程;
|
pump.额定流量 = pn.额定流量;
|
pump.HeadCurve = pn.HeadCurve;
|
pump.额定转速 = pn.额定转速;
|
pump.转速比 = pn.转速比;
|
junc1.Links.Add(pump);
|
junc2.Links.Add(pump);
|
Nodes.Remove(pn);
|
}
|
if (dict_dataset == null)
|
{
|
dict_dataset = new Dictionary<string, Dataset>();
|
}
|
pumps.ForEach(p =>
|
{
|
foreach (var kp in p.Datasets)
|
{
|
if (!dict_dataset.ContainsKey(kp.Value.Name))
|
{
|
dict_dataset.Add(kp.Value.Name, kp.Value);
|
}
|
}
|
});
|
pumps.ForEach((pump) =>
|
{
|
if (dict_dataset.ContainsKey(pump.HeadCurve))
|
{
|
Dataset ds = dict_dataset[pump.HeadCurve];
|
|
if (!pump.Datasets.ContainsKey("流量扬程曲线"))
|
{
|
pump.Datasets.Add("流量扬程曲线", ds);
|
}
|
else
|
{
|
pump.Datasets["流量扬程曲线"] = ds;
|
}
|
ds.pump = pump;
|
}
|
|
if (!pump.Datasets.ContainsKey("流量扬程曲线"))
|
{
|
pump.Datasets.Add("流量扬程曲线", new Dataset(pump.ID + "_Head", pump));
|
}
|
if (pump.Datasets["流量扬程曲线"].Data.Count <= 0)
|
{
|
pump.Datasets["流量扬程曲线"].Data.Add(new PointF((float)pump.额定流量, (float)pump.额定扬程));
|
}
|
pump.HeadCurve = pump.Datasets["流量扬程曲线"].Name;
|
});
|
|
|
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)
|
{
|
if (filePath == null || !File.Exists(filePath)) return false;
|
List<Coor> points = new List<Coor>();
|
StreamReader sr = new StreamReader(filePath);
|
|
{
|
Nodes = new NodeViewModelList();
|
|
|
Links = new LinkViewModelList();
|
|
string line;
|
string section = "";
|
while ((line = sr.ReadLine()) != null)
|
{
|
if (line.Trim().StartsWith("["))
|
{
|
section = line.TrimStart('[').TrimEnd(']');
|
}
|
else
|
{
|
string s = line.Trim('\t').Trim(' ');
|
if (s.Length == 0 || s[0] == ';') continue;
|
line = line.Replace("\t\t", "\t_\t").Replace("\t \t", "\t_\t");
|
Parts parts = new Parts(line.Split(new char[] {
|
'\t', ' ', ';'
|
}, StringSplitOptions.RemoveEmptyEntries));
|
switch (section)
|
{
|
case "JUNCTIONS":
|
{
|
NodeViewModel j = null;
|
if (parts[4] == "Meter")
|
{
|
j = new MeterViewModel();
|
meters.Add((MeterViewModel)j);
|
}
|
else if (parts[4] == "Nozzle")
|
j = new NozzleViewModel();
|
else
|
j = new JunctionViewModel();
|
|
j.ID = parts[0];
|
float elev;
|
if (float.TryParse(parts[1], out elev))
|
j.Elev = elev;
|
float demand;
|
if (float.TryParse(parts[2], out demand))
|
j.Demand = demand;
|
j.PatternID = parts[3];
|
int level;
|
if (int.TryParse(parts[5], out level))
|
j.Level = level;
|
|
Nodes.Add(j);
|
}
|
break;
|
|
case "RESERVOIRS":
|
{
|
ReservoirViewModel r = new ReservoirViewModel();
|
r.ID = parts[0];
|
float head;
|
if (float.TryParse(parts[1], out head))
|
r.Head = head;
|
r.PatternID = parts.Length > 2 ? parts[2] : "";
|
int level;
|
if (int.TryParse(parts[3], out level))
|
r.Level = level;
|
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]);
|
int level;
|
if (int.TryParse(parts[9], out level))
|
tank.Level = level;
|
Nodes.Add(tank);
|
}
|
break;
|
|
case "PIPES":
|
{
|
PipeViewModel p = new PipeViewModel();
|
p.ID = parts[0];
|
p.Node1 = parts[1];
|
p.Node2 = parts[2];
|
float length;
|
if (float.TryParse(parts[3], out length))
|
p.Length = length;
|
float diameter;
|
if (float.TryParse(parts[4], out diameter))
|
p.Diameter = diameter;
|
float roughness;
|
if (float.TryParse(parts[5], out roughness))
|
p.Roughness = roughness;
|
float minorLoss;
|
if (float.TryParse(parts[6], out minorLoss))
|
p.MinorLoss = minorLoss;
|
p.Status = parts.Length > 7 ? StringToStatus(parts[7]) : StatusType.DEFAULT;
|
int level;
|
if (int.TryParse(parts[8], out level))
|
p.Level = level;
|
Links.Add(p);
|
}
|
break;
|
|
case "VALVES":
|
{
|
ValveViewModel valve = new ValveViewModel();
|
valve.ID = parts[0];
|
|
valve.Node1 = parts[1];
|
valve.Node2 = parts[2];
|
|
float diameter;
|
if (float.TryParse(parts[3], out diameter))
|
valve.Diameter = diameter;
|
valve.Type = parts[4];
|
valve.Setting = parts[5];
|
float minorLoss;
|
if (float.TryParse(parts[6], out minorLoss))
|
valve.MinorLoss = minorLoss;
|
int level;
|
if (int.TryParse(parts[7], out level))
|
valve.Level = level;
|
Links.Add(valve);
|
}
|
break;
|
|
case "REPEATERS":
|
{
|
RepeaterViewModel repeater = new RepeaterViewModel();
|
repeater.ID = parts[0];
|
repeater.Node1 = parts[1];
|
repeater.Node2 = parts[2];
|
repeater.TemplateID = parts[3];
|
int repeatTimes;
|
if (int.TryParse(parts[4], out repeatTimes))
|
repeater.RepeatTimes = repeatTimes;
|
RepeatStatus status;
|
if (Enum.TryParse(parts[5], out status))
|
repeater.Status = status;
|
repeater.NetworkPreName = parts[6];
|
int networkPreStartNum;
|
if (int.TryParse(parts[7], out networkPreStartNum))
|
repeater.NetworkPreStartNum = networkPreStartNum;
|
bool networkIsAscNum;
|
if (bool.TryParse(parts[8], out networkIsAscNum))
|
repeater.NetworkIsAscNum = networkIsAscNum;
|
repeater.NetworkShowName = parts[9];
|
int level;
|
if (int.TryParse(parts[10], out level))
|
repeater.Level = level;
|
Links.Add(repeater);
|
}
|
break;
|
|
case "COORDINATES":
|
{
|
string id = parts[0];
|
float x;
|
float y;
|
if (float.TryParse(parts[1], out x) && float.TryParse(parts[2], out y))
|
{
|
points.Add(new Coor(id, new PointF(x, y)));
|
}
|
}
|
break;
|
}
|
}
|
}
|
sr.Close();
|
|
//读取坐标
|
int k1 = 0;
|
int k2 = 0;
|
Nodes.Sort((a, b) => string.Compare(a.ID, b.ID));
|
points.Sort((a, b) => string.Compare(a.ID, b.ID));
|
k1 = 0;
|
k2 = 0;
|
while (k1 < Nodes.Count)
|
{
|
var J = Nodes[k1];
|
var coor = points[k2];
|
|
while (J.ID != coor.ID && k2 < points.Count)
|
{
|
k2++;
|
if (k2 < points.Count) coor = points[k2];
|
}
|
if (k2 == points.Count)
|
{
|
throw new Exception($"未找到Node[{J.ID}]的坐标");
|
}
|
J.X = coor.Position.X;
|
J.Y = coor.Position.Y;
|
|
k1++;
|
}
|
|
|
|
Links.Sort((a, b) => string.Compare(a.Node1, b.Node1));
|
k1 = 0;
|
k2 = 0;
|
while (k2 < Links.Count)
|
{
|
var p = Links[k2];
|
var J = Nodes[k1];
|
while (J.ID != p.Node1 && k1 < Nodes.Count)
|
{
|
k1++;
|
if (k1 < Nodes.Count) J = Nodes[k1];
|
}
|
if (k1 == Nodes.Count)
|
{
|
throw new Exception($"未找到Link[{p.ID}]的起始节点[{p.Node1}]");
|
}
|
p.StartNode = J;
|
if (J.MaxDiameter < p.Diameter) J.MaxDiameter = p.Diameter;
|
J.Links.Add(p);
|
k2++;
|
}
|
|
|
|
Links.Sort((a, b) => string.Compare(a.Node2, b.Node2));
|
k1 = 0;
|
k2 = 0;
|
while (k2 < Links.Count)
|
{
|
var p = Links[k2];
|
var J = Nodes[k1];
|
while (J.ID != p.Node2 && k1 < Nodes.Count)
|
{
|
k1++;
|
if (k1 < Nodes.Count) J = Nodes[k1];
|
}
|
if (k1 == Nodes.Count)
|
{
|
throw new Exception($"未找到Link[{p.ID}]的终止节点[{p.Node2}]");
|
}
|
p.EndNode = J;
|
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 =>
|
{
|
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)
|
{
|
var link_Down = links_Down[0];
|
var link_Up = links_Up[0];
|
double angle = GetAngle(link_Down, link_Up);
|
var minorLoss = 0f;
|
minorLoss += GetMinorLossByAngle(angle);
|
minorLoss += GetChangeDiameterMinorLoss(link_Down, link_Up);
|
link_Up.MinorLoss += minorLoss;
|
}
|
/*上游管线为1根,下游管线为多个*/
|
if (links_Up.Count == 1 && links_Down.Count > 1)
|
{
|
var link_Up = links_Up[0];
|
|
//计算两个管线的夹角,根据夹角计算损失系数
|
foreach (var link_Down in links_Down)
|
{
|
var angle = GetAngle(link_Down, link_Up);
|
var minorLoss = 0f;
|
minorLoss += GetMinorLossByAngle(angle);
|
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)
|
{
|
var angle = GetAngle(link_Down, link_Up);
|
var minorLoss = 0f;
|
minorLoss += GetMinorLossByAngle(angle);
|
minorLoss += GetChangeDiameterMinorLoss(link_Down, link_Up);
|
link_Up.MinorLoss += minorLoss;
|
}
|
}
|
|
/*下游管线为多个,上游管线为多个*/
|
if (links_Up.Count > 1 && links_Down.Count > 1)
|
{
|
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);
|
var minorLoss = 0f;
|
minorLoss += GetMinorLossByAngle(angle);
|
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_Up = link_Up.Diameter;
|
//计算两个管线变径的损失系数
|
var minorLoss = 0f;
|
if (Diameter_Down >= Diameter_Up)//突然变粗
|
{
|
minorLoss = (float)Math.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);
|
//获取两个向量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 * Math.Pow(Math.Sin(Math.Abs(angle) / 2), 2) + 2.05 * Math.Pow(Math.Sin(Math.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 = "";
|
if (!isReplace)
|
{
|
var tempPath = Path.Combine(Directory.GetCurrentDirectory(), @"template\inp\导出模板.inp");
|
if (!File.Exists(tempPath))
|
{
|
//MessageBox.Show($"模板文件不存在[{tempPath}]");
|
return;
|
}
|
tempString = File.ReadAllText(tempPath);
|
}
|
else
|
{
|
tempString = File.ReadAllText(sourcePath);
|
}
|
|
Dictionary<string, string> dictExchange = new Dictionary<string, string>() {
|
{"{junctions}","{0}" },
|
{"{reservoirs}","{1}" },
|
{"{tanks}","{2}" },
|
{"{pipes}","{3}" },
|
{"{valves}","{4}" },
|
{"{pumps}","{5}" },
|
{"{coor}","{6}" },
|
{"{curve}","{7}" },
|
};
|
dictExchange.ToList().ForEach(m => tempString = tempString.Replace(m.Key, m.Value));
|
|
StringBuilder junctionStringBuilder = new StringBuilder();
|
|
junctionStringBuilder.AppendLine(";ID Elev Demand Pattern Type");
|
|
Nodes.ForEach(o0 =>
|
{
|
var o = o0;
|
if (!o.Visible) return;
|
|
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}\t{m.DlTemplateID}");
|
else if (o is NozzleViewModel no)
|
junctionStringBuilder.AppendLine(no.ToString() + $"{o.Level}\tNozzle\t{o.Tags}\t{no.FlowCoefficient}");
|
});
|
string junctionString = junctionStringBuilder.ToString();
|
|
StringBuilder reservoirStringBuilder = new StringBuilder();
|
|
reservoirStringBuilder.AppendLine(";ID Head Pattern ");
|
|
reservoirs.ForEach(o =>
|
{
|
if (!o.Visible) return;
|
reservoirStringBuilder.AppendLine(o.ToString() + $"{o.Level}\t{o.Elev}\t{o.Tags}");
|
});
|
string reserverString = reservoirStringBuilder.ToString();
|
|
StringBuilder tankStringBuilder = new StringBuilder();
|
|
tankStringBuilder.AppendLine(";ID Elevation InitLevel MinLevel MaxLevel Diameter MinVol VolCurve Overflow");
|
|
tanks.ForEach(o =>
|
{
|
if (!o.Visible) return;
|
tankStringBuilder.AppendLine(o.ToString() + $"{o.Level}\tTank\t{o.Tags}");
|
});
|
string tankString = tankStringBuilder.ToString();
|
|
StringBuilder pipeStringBuilder = new StringBuilder();
|
|
pipeStringBuilder.AppendLine(";ID Node1 Node2 Length Diameter Roughness MinorLoss Status");
|
|
Links.ForEach(o0 =>
|
{
|
var o = (LinkViewModel)o0;
|
if (!o.Visible) return;
|
if (o is PipeViewModel p)
|
pipeStringBuilder.AppendLine(p.ToString() + $"{p.Level}\tPipe\t{p.Tags}");
|
else if (o is RepeaterViewModel r)
|
pipeStringBuilder.AppendLine(r.ToString());
|
});
|
string pipeString = pipeStringBuilder.ToString();
|
|
StringBuilder valveStringBuilder = new StringBuilder();
|
|
valveStringBuilder.AppendLine(";ID Node1 Node2 Diameter Type Setting MinorLoss ");
|
|
valves.ForEach(o =>
|
{
|
if (!o.Visible) return;
|
valveStringBuilder.AppendLine(o.ToString() + $"{o.Level}\tValve\t{o.Tags}");
|
});
|
string valveString = valveStringBuilder.ToString();
|
|
StringBuilder pumpStringBuilder = new StringBuilder();
|
|
pumpStringBuilder.AppendLine(";ID Node1 Node2 Diameter Type Setting MinorLoss ");
|
|
pumps.ForEach(o =>
|
{
|
if (!o.Visible) return;
|
pumpStringBuilder.AppendLine(o.ToString() + $"{o.Level}\tPump\t{o.Tags}");
|
});
|
string pumpString = pumpStringBuilder.ToString();
|
|
StringBuilder curveStringBuilder = new StringBuilder();
|
|
curveStringBuilder.AppendLine(@";ID X-Value Y-Value
|
;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());
|
}
|
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()));
|
}
|
else
|
{
|
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, "JUNCTIONS", junctionString);
|
output = replaceContent(output, "RESERVOIRS", reserverString);
|
output = replaceContent(output, "TANKS", tankString);
|
output = replaceContent(output, "PIPES", pipeString);
|
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);
|
output = replaceContent(output, "STATUS", statusString);
|
string backupFolderPath = Path.Combine(Path.GetDirectoryName(filePath), "bk");
|
if (!Directory.Exists(backupFolderPath))
|
{
|
Directory.CreateDirectory(backupFolderPath);
|
}
|
|
string backupFileName = $"{Path.GetFileNameWithoutExtension(filePath)}_{DateTime.Now:yyyyMMddHHmmss}{Path.GetExtension(filePath)}";
|
string backupFilePath = Path.Combine(backupFolderPath, backupFileName);
|
FileCopy.Copy(filePath, backupFilePath, true);
|
|
|
// 检查文件是否存在
|
try
|
{
|
Global.ClearFileReadOnly(filePath);
|
|
File.WriteAllText(filePath, output);
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show(ex.Message);
|
}
|
|
//MessageBox.Show($"保存成功!");
|
}
|
|
private string replaceContent(string text, string content, string replaceString)
|
{
|
string str = replaceString;
|
|
string replacedText = ReplaceCoordinatesSection(text, content, str);
|
|
return replacedText;
|
//Console.WriteLine(replacedText);
|
}
|
}
|
|
public class Vector3D
|
{
|
public double X { get; set; }
|
public double Y { get; set; }
|
public double Z { get; set; }
|
|
public Vector3D(double x, double y, double z)
|
{
|
X = x;
|
Y = y;
|
Z = z;
|
}
|
|
public static double CalculateAngle(Vector3D v1, Vector3D v2)
|
{
|
// 计算两个向量的点积
|
double dotProduct = v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;
|
|
// 计算两个向量的模长
|
double v1Magnitude = Math.Sqrt(v1.X * v1.X + v1.Y * v1.Y + v1.Z * v1.Z);
|
double v2Magnitude = Math.Sqrt(v2.X * v2.X + v2.Y * v2.Y + v2.Z * v2.Z);
|
|
// 计算夹角(弧度)
|
double angleInRadians = Math.Acos(dotProduct / (v1Magnitude * v2Magnitude));
|
|
// 将弧度转换为度数
|
//double angleInDegrees = angleInRadians * (180 / Math.PI);
|
|
return angleInRadians;
|
}
|
|
public double Length
|
{
|
get
|
{
|
return Math.Sqrt(X * X + Y * Y + Z * Z);
|
}
|
}
|
}
|
|
public abstract class BaseModel
|
{
|
public BaseModel() { }
|
|
public BaseModel(BaseModel model)
|
{
|
this.ID = model.ID;
|
this.Name = model.Name;
|
this.Status = model.Status;
|
}
|
public virtual string ID { get; set; }
|
public virtual string Name { get; set; }
|
|
public virtual StatusType Status { get; set; } = StatusType.OPEN;
|
|
|
[Description("楼层")]
|
[DisplayName("楼层")]
|
public virtual string Floor { get; set; }
|
|
|
|
}
|
|
|
public class LinkModel : BaseModel
|
{
|
public LinkModel() { }
|
|
public LinkModel(LinkModel model) : base(model)
|
{
|
this.Node1 = model.Node1;
|
this.Node2 = model.Node2;
|
this.Diameter = model.Diameter;
|
this.Length = model.Length;
|
this.Roughness = model.Roughness;
|
this.MinorLoss = model.MinorLoss;
|
|
}
|
|
/// Node1
|
|
public virtual string Node1 { get; set; }
|
|
/// Node2
|
|
public virtual string Node2 { get; set; }
|
|
/// 口径
|
|
public virtual float Diameter { get; set; }
|
|
|
/// 长度
|
|
public virtual float Length { get; set; }
|
|
|
/// 海森威廉系数
|
|
public virtual float Roughness { get; set; }
|
|
|
/// 局部阻力系数
|
|
public virtual float MinorLoss { get; set; }
|
public virtual string ToStatusString()
|
{
|
if (Status == StatusType.CLOSED)
|
{
|
return $"{ID}\tCLOSED\r\n";
|
}
|
return "";
|
}
|
|
}
|
|
public class LinkCalcModel : LinkModel
|
{
|
public LinkCalcModel() { }
|
|
public LinkCalcModel(LinkCalcModel model) : base(model)
|
{
|
this.Node1 = model.Node1;
|
this.Node2 = model.Node2;
|
this.Diameter = model.Diameter;
|
this.Length = model.Length;
|
this.Roughness = model.Roughness;
|
this.MinorLoss = model.MinorLoss;
|
}
|
|
public string Node1
|
{
|
get
|
{
|
if (_StartNode != null) return _StartNode.ID;
|
return base.Node1;
|
}
|
set
|
{
|
|
base.Node1 = value;
|
}
|
}
|
|
public string Node2
|
{
|
get
|
{
|
if (_EndNode != null) return _EndNode.ID;
|
return base.Node2;
|
}
|
set
|
{
|
base.Node2 = value;
|
}
|
}
|
|
|
private NodeCalcModel _StartNode;
|
|
public NodeCalcModel StartNode
|
{
|
get { return _StartNode; }
|
set { _StartNode = value; if (_StartNode != null) this.Node1 = _StartNode.ID; }
|
}
|
|
private NodeCalcModel _EndNode;
|
|
public NodeCalcModel EndNode
|
{
|
get { return _EndNode; }
|
set { _EndNode = value; if (_EndNode != null) this.Node2 = _EndNode.ID; }
|
}
|
|
|
/// 长度
|
|
public float Length
|
{
|
get
|
{
|
if (base.Length > 0) return base.Length;
|
else
|
{
|
if (_StartNode != null && _EndNode != null)
|
{
|
////求_StartNode到_EndNode的距离
|
return (float)Math.Sqrt(Math.Pow(_StartNode.X - _EndNode.X, 2) + Math.Pow(_StartNode.Y - _EndNode.Y, 2) + Math.Pow(_StartNode.Elev - _EndNode.Elev, 2));
|
}
|
else
|
{
|
return 0;
|
}
|
}
|
}
|
set
|
{
|
base.Length = value;
|
}
|
}
|
|
//实际需水量
|
[DisplayName("流量(m³/h)")]
|
[Browsable(true)]
|
public float EN_FLOW { get; set; } = float.NaN;
|
|
//实际需水量
|
[DisplayName("流速(m/s)")]
|
[Browsable(true)]
|
public float EN_VELOCITY { get; set; } = float.NaN;
|
//实际需水量
|
|
[DisplayName("水头损失(m)")]
|
[Browsable(true)]
|
public float EN_HEADLOSS { get; set; } = float.NaN;
|
|
|
[DisplayName("沿程水损(m)")]
|
[Browsable(true)]
|
public float EN_HEADLOSS_LINE { get; set; } = float.NaN;
|
|
|
[DisplayName("局部水损(m)")]
|
[Browsable(true)]
|
public float EN_HEADLOSS_MINOR { get; set; } = float.NaN;
|
//实际需水量
|
|
[DisplayName("当前状态")]
|
|
public float EN_STATUS { get; set; } = float.NaN;
|
|
|
|
|
public bool Selected { get; set; }
|
|
|
[Description("鼠标悬于上方")]
|
[DisplayName("鼠标悬于上方")]
|
|
public bool Hovered { get; set; }
|
}
|
|
|
public class NodeModel : BaseModel
|
{
|
public NodeModel() { }
|
|
public NodeModel(NodeModel model) : base(model)
|
{
|
this.X = model.X;
|
this.Y = model.Y;
|
this.Elev = model.Elev;
|
}
|
public virtual float X { get; set; }
|
|
public virtual float Y { get; set; }
|
|
|
|
/// 标高
|
|
public virtual float Elev { get; set; }
|
|
public virtual string ToCoorString()
|
{
|
return $"{ID}\t{X}\t{Y}";
|
}
|
|
}
|
|
public class NodeCalcModel : NodeModel
|
{
|
public NodeCalcModel() { }
|
|
public NodeCalcModel(NodeCalcModel model) : base(model)
|
{
|
this.X = model.X;
|
this.Y = model.Y;
|
this.Elev = model.Elev;
|
}
|
public List<LinkCalcModel> Links = new List<LinkCalcModel>();
|
|
//实际需水量
|
|
[DisplayName("实际需水量(m³/h)")]
|
[Browsable(true)]
|
public float EN_DEMAND { get; set; } = float.NaN;
|
|
//实际需水量
|
|
[DisplayName("绝对水压(m)")]
|
[Browsable(true)]
|
public float EN_HEAD { get; set; } = float.NaN;
|
//实际需水量
|
|
[DisplayName("自由水压(m)")]
|
[Browsable(true)]
|
public float EN_PRESSURE { get; set; } = float.NaN;
|
//实际需水量
|
|
[DisplayName("水龄")]
|
public float EN_QUALITY { get; set; } = float.NaN;
|
|
|
|
|
public bool Selected { get; set; }
|
|
|
|
[Description("鼠标悬于上方")]
|
[DisplayName("鼠标悬于上方")]
|
|
public bool Hovered { get; set; }
|
}
|
|
|
public enum StatusType
|
{
|
CLOSED = 0,
|
OPEN = 1,
|
ACTIVE = 2,
|
DEFAULT = 3
|
}
|
|
public enum PumpType
|
{
|
调速泵,
|
定速泵
|
}
|
|
public enum FlowCurveType
|
{
|
流量扬程曲线 = 1,
|
流量功率曲线 = 2,
|
流量效率曲线 = 3
|
}
|
|
public enum FailType
|
{
|
缺少Node1或Node2连接属性 = 1,
|
喷头只能连接管道 = 2,
|
缺少水箱或水池对象 = 3,
|
管件对象连管件对象 = 4
|
}
|
|
public class JunctionModel : NodeCalcModel
|
{
|
|
/// 需水量
|
public float Demand { get; set; }
|
|
/// 用水模式编号
|
public string PatternID { get; set; }
|
public override string ToString()
|
{
|
var pTemp = PatternID;
|
if (string.IsNullOrEmpty(pTemp) || pTemp == ";") pTemp = "";
|
return $"{ID}\t{Elev}\t{Demand}\t{pTemp}\t;\t";
|
}
|
|
public MeterModel ToMeter()
|
{
|
return new MeterModel()
|
{
|
Elev = base.Elev,
|
ID = base.ID,
|
Name = base.Name,
|
Status = base.Status,
|
X = base.X,
|
Y = base.Y,
|
};
|
}
|
|
public NozzleModel ToNozzle()
|
{
|
return new NozzleModel()
|
{
|
Y = base.Y,
|
X = base.X,
|
Status = base.Status,
|
Name = base.Name,
|
ID = base.ID,
|
Elev = base.Elev,
|
};
|
}
|
}
|
|
public class MeterModel : NodeCalcModel
|
{
|
|
/// 需水量
|
public float Demand { get; set; }
|
|
/// 用水模式编号
|
public string PatternID { get; set; }
|
public override string ToString()
|
{
|
if (string.IsNullOrEmpty(PatternID)) PatternID = "";
|
return $"{ID}\t{Elev}\t{Demand}\t{PatternID}\tMeter\t;\t";
|
}
|
|
public JunctionModel ToJunction()
|
{
|
return new JunctionModel()
|
{
|
Y = base.Y,
|
Elev = base.Elev,
|
ID = base.ID,
|
Name = base.Name,
|
Status = base.Status,
|
X = base.X,
|
};
|
}
|
}
|
|
public class NozzleModel : NodeCalcModel
|
{
|
|
/// 流量系数K
|
|
public float FlowCoefficient { get; set; }
|
|
|
/// 需水量
|
|
public float Demand { get; set; }
|
|
/// 用水模式编号
|
|
public string PatternID { get; set; }
|
|
public string Node1 { get; set; }
|
public string Node2 { get; set; }
|
|
public override string ToString()
|
{
|
if (string.IsNullOrEmpty(PatternID)) PatternID = "";
|
return $"{ID}\t{Elev}\t{Demand}\t{PatternID}\t;\t";
|
}
|
|
public string ToEmitterString()
|
{
|
if (FlowCoefficient > 0)
|
return $"{ID}\t{FlowCoefficient * Math.Pow(10 / 101.972, 0.5) / 1000 * 60}\r\n";
|
return null;
|
}
|
|
public JunctionModel ToJunction()
|
{
|
return new JunctionModel()
|
{
|
Y = base.Y,
|
Elev = base.Elev,
|
ID = base.ID,
|
Name = base.Name,
|
Status = base.Status,
|
X = base.X,
|
};
|
}
|
}
|
|
public class ReservoisModel : NodeCalcModel
|
{
|
|
/// 总水头|绝对水压
|
|
public float Head { get; set; }
|
|
|
/// 用水模式编号
|
|
public string PatternID { get; set; }
|
|
public override string ToString()
|
{
|
return $"{ID}\t{Head}\t{PatternID}\t;\t";
|
}
|
|
}
|
|
public class TankModel : NodeCalcModel
|
{
|
|
/// 初始水位
|
|
public float InitLevel { get; set; } = 5;
|
|
|
/// 最低水位
|
|
public float MinLevel { get; set; } = 10;
|
|
|
/// 最高水位
|
|
public float MaxLevel { get; set; } = 0;
|
|
|
/// 直径
|
|
public float Diameter { get; set; } = 10;
|
|
|
/// 最小容积
|
|
public float MinVol { get; set; } = 0;
|
|
|
/// 容积曲线
|
|
public string VolCurve { get; set; }
|
|
|
/// 是否允许溢流
|
|
public bool IsOverFlow { get; set; }
|
|
public override string ToString()
|
{
|
VolCurve = "";
|
var Overflow = IsOverFlow ? "" : "";
|
return $"{ID}\t{Elev}\t{InitLevel}\t{MinLevel}\t{MaxLevel}\t{Diameter}\t{MinVol}\t{VolCurve}\t{Overflow}\t;\t";
|
}
|
}
|
|
public class PipeModel : LinkCalcModel
|
{
|
public override string ToString()
|
{
|
if (Roughness == 0) Roughness = 110;
|
return $"{ID}\t{Node1}\t{Node2}\t{Length}\t{Diameter}\t{Roughness}\t{MinorLoss}\t{Status}\t;\t";
|
}
|
}
|
|
public class PumpModel : LinkCalcModel
|
{
|
|
/// 泵类型
|
|
public PumpType Type { get; set; }
|
|
/// 额定转速
|
|
public double RatedSpeed { get; set; } = 1500;
|
|
|
/// 额定流量
|
|
public double RatedFlow { get; set; } = 0;
|
|
|
/// 额定扬程
|
|
public double RatedHead { get; set; } = 0;
|
|
|
/// 额定功率
|
|
public double RatedPower { get; set; } = 75;
|
|
|
/// 扬程曲线
|
|
public string FlowCurveID { get; set; } = "PumpDefault";
|
|
|
/// 参数
|
|
public List<string> Parameters { get; set; }
|
|
|
/// 流量曲线
|
|
public FlowCurve FlowCurve { get; set; }
|
|
|
|
}
|
|
public class ValveModel : LinkCalcModel
|
{
|
|
/// 类型
|
|
public string Type { get; set; } = "GPV";
|
|
/// 曲线
|
|
public string CurvSetting { get; set; } = "GPVDefault";
|
|
|
}/// <summary>
|
/// 流量曲线
|
|
|
public class FlowCurve
|
{
|
public string Name { get; set; }
|
|
public FlowCurveType FlowCurveType { get; set; }
|
|
public List<PointF> Data { get; set; } = new List<PointF>();
|
}
|
|
|
public class Coor
|
{
|
public string ID;
|
public PointF Position;
|
public Coor(string id, PointF position)
|
{
|
ID = id;
|
this.Position = position;
|
}
|
}
|
public class Parts
|
{
|
List<string> _parts = null;
|
List<string> _parts_before = null;
|
|
public int Length
|
{
|
get
|
{
|
if (_parts != null)
|
return _parts.Count;
|
else
|
return -1;
|
}
|
}
|
|
public int Count
|
{
|
get
|
{
|
if (_parts != null)
|
return _parts.Count;
|
else
|
return -1;
|
}
|
}
|
|
public Parts(string[] strings)
|
{
|
_parts = strings.ToList();
|
}
|
|
public Parts(string line)
|
{
|
List<string> sp = line.Split(new char[] {
|
'\t', ' '
|
}, StringSplitOptions.RemoveEmptyEntries).ToList();
|
int pos = sp.IndexOf(";");
|
if (pos > 0)
|
{
|
_parts = new List<string>();
|
_parts_before = new List<string>();
|
for (int i = 0; i < pos; i++)
|
{
|
_parts.Add(sp[i]);
|
}
|
for (int i = pos; i < sp.Count; i++)
|
{
|
_parts_before.Add(sp[i]);
|
}
|
}
|
else
|
{
|
_parts = new List<string>();
|
_parts.AddRange(sp);
|
}
|
}
|
public string this[int index]
|
{
|
get
|
{
|
if (index < 0)
|
{
|
index = Math.Abs(index);
|
if (_parts_before != null && _parts_before.Count > index)
|
return _parts_before[index];
|
else
|
return null;
|
}
|
else
|
{
|
if (_parts != null && _parts.Count > index)
|
return _parts[index];
|
else
|
return null;
|
}
|
|
}
|
set
|
{
|
_parts[index] = value;
|
}
|
}
|
public float ToFloat(int index, float defaultValue)
|
{
|
float f = defaultValue;
|
if (this[index] != null && float.TryParse(this[index], out f))
|
{
|
|
}
|
return f;
|
}
|
public int ToInt(int index, int defaultValue)
|
{
|
int f = defaultValue;
|
if (this[index] != null && int.TryParse(this[index], out f))
|
{
|
|
}
|
return f;
|
}
|
public string ToString(int index, string defaultValue)
|
{
|
string f = defaultValue;
|
if (this[index] != null)
|
{
|
return this[index];
|
}
|
return f;
|
}
|
public bool ToBool(int index, bool defaultValue)
|
{
|
bool f = defaultValue;
|
if (this[index] != null && bool.TryParse(this[index], out f))
|
{
|
|
}
|
return f;
|
}
|
}
|
|
|
|
public class TimePoint
|
{
|
public TimePoint()
|
{
|
|
}
|
public TimePoint(string key, double value)
|
{
|
Key = key;
|
Value = value;
|
}
|
public TimePoint(TimePoint point)
|
{
|
this.Key = point.Key;
|
this.Value = point.Value;
|
this.Name = point.Name;
|
this.ValueTime = point.ValueTime;
|
this.SearchRange = point.SearchRange;
|
this.isNeedtoSave = point.isNeedtoSave;
|
this.SaveKey = point.SaveKey;
|
if (point.Pattern != null) this.Pattern = point.Pattern.ToArray();
|
|
}
|
public string Name;
|
public DateTime ValueTime { get; set; }
|
public string Key { get; set; }
|
public double Value { get; set; }
|
public double[] Pattern { get; set; } = null;
|
|
public double SearchRange = 0;
|
|
public bool isNeedtoSave = false;
|
|
public string SaveKey = null;
|
|
public override string ToString()
|
{
|
return $"{Name}\t[{Key}]\t{Value}";
|
}
|
}
|
|
|
|
public class dict<TKey, TValue> : Dictionary<TKey, TValue>
|
{
|
private List<TKey> keys
|
{
|
get
|
{
|
return this.Keys.ToList();
|
}
|
}
|
|
public bool emptyCreate = true;
|
//List<dict> _list = null;
|
public dict() : base()
|
{
|
}
|
|
public dict(int capacity) : base(capacity)
|
{
|
}
|
public dict(IEnumerable<KeyValuePair<TKey, TValue>> collection) : base((IDictionary<TKey, TValue>)collection)
|
{
|
}
|
public bool Value { get; set; }
|
|
public bool SetKey(TKey key, dynamic Value)
|
{
|
if (this.Contains(key))
|
{
|
this[key] = Value;
|
return false;
|
}
|
else
|
{
|
this.Add(key, Value);
|
return true;
|
}
|
}
|
public TKey[] GetKeys()
|
{
|
return this.Keys.ToArray();
|
}
|
|
public bool Contains(TKey[] keys)
|
{
|
foreach (var key in keys)
|
if (!this.Contains(key)) return false;
|
return true;
|
}
|
public bool Contains(TKey key)
|
{
|
return this.ContainsKey(key);
|
}
|
public bool Contains(KeyValuePair<TKey, dynamic> key)
|
{
|
return this.ContainsKey(key.Key);
|
}
|
public TValue Get(TKey key, TValue @default = default(TValue))
|
{
|
if (this.Contains(key))
|
return this[key];
|
else
|
return @default;
|
}
|
public TValue Get(KeyValuePair<TKey, TValue> key, TValue @default = default(TValue))
|
{
|
if (this.Contains(key))
|
return this[key.Key];
|
else
|
return @default;
|
}
|
public TValue pop(TKey key, TValue @default = default(TValue))
|
{
|
if (this.Contains(key))
|
{
|
var temp = this[key];
|
this.Remove(key);
|
return temp;
|
}
|
else
|
return @default;
|
}
|
public TValue pop(KeyValuePair<TKey, TValue> key, TValue @default = default(TValue))
|
{
|
if (this.Contains(key))
|
{
|
var temp = this[key.Key];
|
this.Remove(key);
|
return temp;
|
}
|
else
|
return @default;
|
}
|
public TValue this[KeyValuePair<TKey, TValue> key]
|
{
|
get { return this[key.Key]; }
|
set { this[key.Key] = value; }
|
}
|
public TValue this[TKey key]
|
{
|
get
|
{
|
if (!this.ContainsKey(key))
|
{
|
lock (this)
|
{
|
if (!this.ContainsKey(key))
|
{
|
if (emptyCreate)
|
this.Add(key, default(TValue));
|
else
|
return default(TValue);
|
}
|
}
|
}
|
return base[key];
|
|
}
|
set
|
{
|
if (!this.ContainsKey(key))
|
{
|
lock (this)
|
{
|
if (!this.ContainsKey(key))
|
{
|
if (emptyCreate)
|
this.Add(key, value);
|
else
|
return;
|
}
|
}
|
}
|
base[key] = value;
|
}
|
|
}
|
|
public TValue this[int index]
|
{
|
get
|
{
|
TKey key = default(TKey);
|
if (typeof(TKey) == typeof(int))
|
key = (TKey)(object)index;
|
else
|
key = keys[index];
|
if (!base.ContainsKey(key))
|
base.Add(key, default(TValue));
|
|
return base[key];
|
}
|
set
|
{
|
TKey key = default(TKey);
|
if (typeof(TKey) == typeof(int))
|
{
|
key = (TKey)(object)index;
|
base[key] = value;
|
}
|
|
else
|
{
|
if (index < keys.Count)
|
{
|
key = keys[index];
|
base[key] = value;
|
}
|
}
|
|
|
}
|
}
|
|
public override string ToString()
|
{
|
return JsonConvert.SerializeObject(this);
|
}
|
public void LoadFromString(string s)
|
{
|
dict<TKey, TValue> d = JsonConvert.DeserializeObject<dict<TKey, TValue>>(s);
|
this.Clear();
|
foreach (var kp in d)
|
{
|
this.Add(kp.Key, kp.Value);
|
}
|
|
}
|
public bool Remove(KeyValuePair<TKey, TValue> key)
|
{
|
return this.Remove(key.Key);
|
}
|
|
|
public List<TValue> values()
|
{
|
return this.Values.ToList();
|
}
|
|
#region 将Session的元素简单放进dict中,简单处理方便使用
|
private DateTime 发送计时;
|
private string msgList = "";
|
private System.Timers.Timer t = new System.Timers.Timer();
|
|
|
public dict<TKey, TValue> ctx
|
{
|
get { return this; }
|
}
|
|
#endregion
|
|
#region IntentCommand
|
public double confidence;
|
public string methodName;
|
public dict<TKey, TValue> args;
|
public string current_arg;
|
//current_arg: str = ''
|
public dict(double confidence, string methodName, string current_arg = "", dict<TKey, TValue> args = null)
|
{
|
this.confidence = confidence;
|
this.methodName = methodName;
|
this.args = args;
|
this.current_arg = current_arg;
|
}
|
#endregion
|
|
}
|
public partial class PropertyForm : UserControl
|
{
|
private IBaseViewModel _selectedObject;
|
private MapObjectType _selectedType = MapObjectType.全部;
|
private List<SelectionSet> selectionSets;
|
public SelectionSet selectionSet = new SelectionSet();
|
private Form fr = null;
|
public PropertyForm()
|
{
|
InitializeComponent();
|
}
|
public void SetEnabled(bool isReadOnly)
|
{
|
_isEnable = isReadOnly;
|
}
|
|
public void SetWindows(Form mg)
|
{
|
if (mg.WindowState == FormWindowState.Maximized)
|
{
|
//this.StartPosition = FormStartPosition.Manual; //设置窗体位置由程序控制
|
this.Height = mg.Height - 50;
|
this.Location = new Point(mg.Left + mg.Width - this.Width, mg.Top + 50); //设置新窗体位置,当前窗体的右侧(X轴方向)
|
}
|
else
|
{
|
//this.StartPosition = FormStartPosition.Manual; //设置窗体位置由程序控制
|
this.Height = mg.Height;
|
this.Location = new Point(mg.Left + mg.Width - 15, mg.Top); //设置新窗体位置,当前窗体的右侧(X轴方向)
|
}
|
fr = mg;
|
|
//GlobalObject.PropertyForm.Show();
|
}
|
public Form GetWindow()
|
{
|
return this.fr;
|
}
|
public void SetObj(object o)
|
{
|
propertyGrid.SelectedObject = o;
|
this.Text = o.GetType().Name;
|
}
|
public void SetObj(IBaseViewModel selectedObject)
|
{
|
lock (selectedObject)
|
{
|
_selectedObject = selectedObject;
|
|
|
|
if (_selectedObject is JunctionViewModel junc)
|
{
|
_selectedType = MapObjectType.节点;
|
propertyGrid.SelectedObjects = new JunctionViewModel[] { junc };
|
}
|
else if (_selectedObject is ReservoirViewModel res)
|
{
|
_selectedType = MapObjectType.水库;
|
propertyGrid.SelectedObjects = new ReservoirViewModel[] { res };
|
}
|
else if (_selectedObject is TankViewModel tank)
|
{
|
_selectedType = MapObjectType.水池;
|
propertyGrid.SelectedObjects = new TankViewModel[] { tank };
|
}
|
else if (_selectedObject is PipeViewModel pipe)
|
{
|
_selectedType = MapObjectType.管线;
|
propertyGrid.SelectedObjects = new PipeViewModel[] { pipe };
|
}
|
else if (_selectedObject is ValveViewModel valve)
|
{
|
_selectedType = MapObjectType.阀门;
|
propertyGrid.SelectedObjects = new ValveViewModel[] { valve };
|
}
|
else if (_selectedObject is RepeaterViewModel repeater)
|
{
|
_selectedType = MapObjectType.重复器;
|
propertyGrid.SelectedObjects = new RepeaterViewModel[] { repeater };
|
}
|
//水表
|
else if (_selectedObject is MeterViewModel meter)
|
{
|
_selectedType = MapObjectType.水表;
|
propertyGrid.SelectedObjects = new MeterViewModel[] { meter };
|
}
|
//水泵
|
else if (_selectedObject is PumpViewModel pump)
|
{
|
_selectedType = MapObjectType.水泵;
|
propertyGrid.SelectedObjects = new PumpViewModel[] { pump };
|
}
|
//喷头Nozzle
|
else if (_selectedObject is NozzleViewModel nozzle)
|
{
|
_selectedType = MapObjectType.喷头;
|
propertyGrid.SelectedObjects = new NozzleViewModel[] { nozzle };
|
}
|
else
|
{
|
_selectedType = MapObjectType.全部;
|
propertyGrid.SelectedObjects = new IBaseViewModel[] { selectedObject };
|
}
|
switch (_selectedType)
|
{
|
case MapObjectType.节点:
|
Text = "节点 Properties";
|
break;
|
case MapObjectType.水库:
|
Text = "水库 Properties";
|
break;
|
case MapObjectType.水池:
|
Text = "水池 Properties";
|
break;
|
case MapObjectType.管线:
|
Text = "管线 Properties";
|
break;
|
case MapObjectType.阀门:
|
Text = "阀门 Properties";
|
break;
|
case MapObjectType.重复器:
|
Text = "重复器 Properties";
|
break;
|
}
|
|
|
}
|
|
}
|
public void SetNet(MapViewNetWork net)
|
{
|
selectionSet.net = net;
|
}
|
public void SetObjs(List<IBaseViewModel> selectedObjects)
|
{
|
if (selectedObjects == null) return;
|
selectedObjects.RemoveAll(obj => obj == null);
|
selectedObjects.ForEach(obj =>
|
{
|
if (obj.Tags == null)
|
{
|
obj.Tags = new TagList();
|
}
|
|
});
|
|
selectionSet.selectedObjects = selectedObjects.ToList();
|
if (selectedObjects.Count == 1)
|
SetObj(selectedObjects[0]);
|
else
|
ShowProperties(selectedObjects);
|
|
if (selectionSet.OnlyViewSelected)
|
RefreshListBox();
|
}
|
|
private void PropertyForm_Load_1(object sender, EventArgs e)
|
{
|
foreach (var item in Enum.GetValues(typeof(MapObjectType)))
|
{
|
comboBox_type.Items.Add(item);
|
}
|
comboBox_type.SelectedIndex = 0;
|
selectionSets = new List<SelectionSet>();
|
selectionSet = new SelectionSet();
|
listBox1.DataSource = selectionSet.View;
|
}
|
|
private void comboBox_type_SelectedIndexChanged(object sender, EventArgs e)
|
{
|
RefreshListBox();
|
}
|
void RefreshListBox()
|
{
|
if (selectionSet == null) return;
|
string txt = comboBox_type.SelectedItem.ToString();
|
MapObjectType selectedType = (MapObjectType)Enum.Parse(typeof(MapObjectType), txt);
|
// 使用 LINQ 查询筛选选择集
|
selectionSet.filterType = selectedType;
|
selectionSet.FilterString = textBox_search.Text;
|
|
|
listBox1.SelectedIndexChanged -= listBox1_SelectedIndexChanged;
|
|
|
listBox1.DataSource = selectionSet.View;
|
|
listBox1.SelectedIndexChanged += listBox1_SelectedIndexChanged;
|
}
|
|
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
|
{
|
|
if (listBox1.SelectedItems.Count == 0)
|
{
|
return;
|
}
|
else if (listBox1.SelectedItems.Count == 1)
|
{
|
var objID = listBox1.SelectedItems[0];
|
var findlist = selectionSet.net.MapObjects.FindAll(o => o.ID == objID);
|
if (findlist.Count <= 0) return;
|
IBaseViewModel mapObject = findlist[0];
|
if (mapObject != null) SetObj(mapObject);
|
GlobalObject.map.selectedObjs.ForEach(o => o.Selected = false); ;
|
GlobalObject.map.selectedObjs.Clear();
|
GlobalObject.map.selectedObjs.Add(mapObject);
|
mapObject.Selected = true;
|
GlobalObject.map.SetMapInvalidate();
|
}
|
else
|
{
|
List<IBaseViewModel> list = new List<IBaseViewModel>();
|
foreach (var o in listBox1.SelectedItems)
|
{
|
var objID = listBox1.SelectedItems[0];
|
IBaseViewModel mapObject = selectionSet.net.MapObjects.FindAll(obj => obj.ID == objID)[0];
|
list.Add(mapObject);
|
}
|
ShowProperties(list);
|
GlobalObject.map.selectedObjs.ForEach(o => o.Selected = false); ;
|
GlobalObject.map.selectedObjs.Clear();
|
list.ForEach(o => o.Selected = true);
|
GlobalObject.map.selectedObjs.AddRange(list);
|
GlobalObject.map.SetMapInvalidate();
|
}
|
|
|
|
}
|
private void listBox1_DoubleClick(object sender, EventArgs e)
|
{
|
if (listBox1.SelectedItems.Count == 1)
|
{
|
|
var objID = listBox1.SelectedItems[0];
|
IBaseViewModel mapObject = selectionSet.net.MapObjects.FindAll(obj => obj.ID == objID)[0];
|
GlobalObject.map.setCenter(mapObject);
|
|
|
GlobalObject.map.SetMapInvalidate();
|
}
|
}
|
private void PropertyForm_FormClosing(object sender, FormClosingEventArgs e)
|
{
|
e.Cancel = true;
|
this.Hide();
|
}
|
|
bool _isEnable = true;
|
|
private static Dictionary<object, List<object>> _selectedObjectsDict = new Dictionary<object, List<object>>();
|
private void propertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
|
{
|
|
if (!_isEnable)
|
{
|
MessageBox.Show("当前状态的修改将不会被保存", "重复器展开中");
|
_isEnable = true;
|
}
|
|
GlobalObject.map.SetMapInvalidate();
|
}
|
|
|
|
public void ShowProperties(IEnumerable<IBaseViewModel> selectedObjects)
|
{
|
IBaseViewModel[] objs = null;
|
try
|
{
|
if (selectedObjects != null)
|
objs = selectedObjects.ToArray();
|
}
|
catch
|
{
|
return;
|
}
|
propertyGrid.SelectedObjects = objs;
|
|
|
|
}
|
|
private void textBox_search_TextChanged(object sender, EventArgs e)
|
{
|
RefreshListBox();
|
}
|
|
private void checkBox_OnlyShowSelected_CheckedChanged(object sender, EventArgs e)
|
{
|
selectionSet.OnlyViewSelected = checkBox_OnlyShowSelected.Checked;
|
RefreshListBox();
|
}
|
|
private void label_lock_Click(object sender, EventArgs e)
|
{
|
var label_lock = (Label)sender;
|
|
GlobalObject.LockSelect = !GlobalObject.LockSelect;
|
if (GlobalObject.LockSelect)
|
{
|
label_lock.BackColor = Color.Blue;
|
label_lock.Text = "🔒";
|
}
|
else
|
{
|
label_lock.BackColor = Color.Green;
|
label_lock.Text = "🔓";
|
}
|
}
|
private void label_filter_Click(object sender, EventArgs e)
|
{
|
|
|
|
|
}
|
|
private void PropertyForm_KeyDown(object sender, KeyEventArgs e)
|
{
|
//Ctrl+A,则选中当前listbox中的所有项
|
if (e.Control && e.KeyCode == Keys.A)
|
{
|
for (int i = 0; i < listBox1.Items.Count; i++)
|
{
|
listBox1.SetSelected(i, true);
|
}
|
}
|
}
|
|
|
private void 全选ToolStripMenuItem_Click(object sender, EventArgs e)
|
{
|
listBox1.SelectedIndexChanged -= listBox1_SelectedIndexChanged;
|
for (int i = 0; i < listBox1.Items.Count; i++)
|
{
|
listBox1.SetSelected(i, true);
|
}
|
listBox1.SelectedIndexChanged += listBox1_SelectedIndexChanged;
|
this.propertyGrid.SelectedObjects = selectionSet.CurrentSelectedObjects?.ToArray();
|
GlobalObject.map.selectedObjs.ForEach(o => o.Selected = false);
|
if (selectionSet.CurrentSelectedObjects != null)
|
{
|
GlobalObject.map.selectedObjs.AddRange(selectionSet.CurrentSelectedObjects);
|
selectionSet.CurrentSelectedObjects.ForEach(o =>
|
{
|
o.Selected = true;
|
});
|
}
|
GlobalObject.map.SetMapInvalidate();
|
|
|
}
|
|
private void listBox1_MouseDown(object sender, MouseEventArgs e)
|
{
|
if (e.Button == MouseButtons.Right)
|
{
|
if (listBox1.SelectedItems.Count > 0)
|
{
|
contextMenuStrip1.Show(listBox1, e.Location);
|
}
|
}
|
}
|
}
|
|
public class SelectionSet
|
{
|
public string Name;
|
public MapObjectType filterType = MapObjectType.全部;
|
|
public string FilterString { get; set; } = "";
|
|
public TagList FilterTags { get; set; } = new TagList();
|
public List<Func<IBaseViewModel, bool>> rules = new List<Func<IBaseViewModel, bool>>();
|
public List<MapObjectType> FilterTypes = new List<MapObjectType>();
|
public MapViewNetWork net { get; set; } = null;
|
public bool OnlyViewSelected { get; set; } = true;
|
|
public List<IBaseViewModel> selectedObjects = new List<IBaseViewModel>();
|
public List<IBaseViewModel> CurrentSelectedObjects = new List<IBaseViewModel>();
|
public List<string> View
|
{
|
get
|
{
|
List<IBaseViewModel> originList;
|
List<IBaseViewModel> list;
|
List<string> list_result = new List<string>();
|
if (!OnlyViewSelected && net != null)
|
{
|
originList = net.MapObjects;
|
}
|
else
|
{
|
originList = selectedObjects;
|
}
|
|
|
if (filterType == MapObjectType.全部)
|
{
|
list = originList;
|
}
|
|
else
|
{
|
|
var filteredSets = from obj in originList
|
where obj.GetType() == filterType.GetObjType()
|
select obj;
|
list = filteredSets?.ToList();
|
}
|
|
|
|
if (FilterString != null && FilterString != "")
|
{
|
list = list?.FindAll(o => o.ID.IndexOf(FilterString) >= 0);
|
}
|
|
if (FilterTags.Count > 0)
|
{
|
foreach (var tag in FilterTags)
|
{
|
var filteredSets = from obj in list
|
where obj.Tags.Contains(tag)
|
select obj;
|
list = filteredSets?.ToList();
|
}
|
}
|
|
if (rules.Count > 0)
|
{
|
foreach (var rule in rules)
|
{
|
var filteredSets = from obj in list
|
where rule(obj)
|
select obj;
|
list = filteredSets?.ToList();
|
}
|
}
|
|
CurrentSelectedObjects = list;
|
list_result = list.Select(o => o.ID).ToList();
|
return list_result;
|
|
|
}
|
}
|
|
|
}
|
|
partial class PropertyForm
|
{
|
|
|
private System.ComponentModel.IContainer components = null;
|
|
|
/// Clean up any resources being used.
|
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
protected override void Dispose(bool disposing)
|
{
|
if (disposing && (components != null))
|
{
|
components.Dispose();
|
}
|
base.Dispose(disposing);
|
}
|
|
#region Windows Form Designer generated code
|
|
private void InitializeComponent()
|
{
|
this.components = new System.ComponentModel.Container();
|
this.propertyGrid = new System.Windows.Forms.PropertyGrid();
|
this.listBox1 = new System.Windows.Forms.ListBox();
|
this.comboBox_type = new System.Windows.Forms.ComboBox();
|
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
this.panel1 = new System.Windows.Forms.Panel();
|
this.checkBox_OnlyShowSelected = new System.Windows.Forms.CheckBox();
|
this.textBox_search = new System.Windows.Forms.TextBox();
|
this.label_filter = new System.Windows.Forms.Label();
|
this.label_lock = new System.Windows.Forms.Label();
|
this.label1 = new System.Windows.Forms.Label();
|
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
this.全选ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
this.splitContainer1.Panel1.SuspendLayout();
|
this.splitContainer1.Panel2.SuspendLayout();
|
this.splitContainer1.SuspendLayout();
|
this.panel1.SuspendLayout();
|
this.contextMenuStrip1.SuspendLayout();
|
this.SuspendLayout();
|
//
|
// propertyGrid
|
//
|
this.propertyGrid.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.propertyGrid.Location = new System.Drawing.Point(0, 0);
|
this.propertyGrid.Name = "propertyGrid";
|
this.propertyGrid.Size = new System.Drawing.Size(202, 346);
|
this.propertyGrid.TabIndex = 0;
|
this.propertyGrid.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid_PropertyValueChanged);
|
//
|
// listBox1
|
//
|
this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.listBox1.FormattingEnabled = true;
|
this.listBox1.ItemHeight = 12;
|
this.listBox1.Location = new System.Drawing.Point(0, 41);
|
this.listBox1.Name = "listBox1";
|
this.listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
|
this.listBox1.Size = new System.Drawing.Size(202, 75);
|
this.listBox1.TabIndex = 1;
|
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
|
this.listBox1.DoubleClick += new System.EventHandler(this.listBox1_DoubleClick);
|
this.listBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.listBox1_MouseDown);
|
//
|
// comboBox_type
|
//
|
this.comboBox_type.Dock = System.Windows.Forms.DockStyle.Top;
|
this.comboBox_type.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
this.comboBox_type.FormattingEnabled = true;
|
this.comboBox_type.Location = new System.Drawing.Point(0, 21);
|
this.comboBox_type.Name = "comboBox_type";
|
this.comboBox_type.Size = new System.Drawing.Size(202, 20);
|
this.comboBox_type.TabIndex = 2;
|
this.comboBox_type.SelectedIndexChanged += new System.EventHandler(this.comboBox_type_SelectedIndexChanged);
|
//
|
// splitContainer1
|
//
|
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
|
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
|
this.splitContainer1.Name = "splitContainer1";
|
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
|
//
|
// splitContainer1.Panel1
|
//
|
this.splitContainer1.Panel1.Controls.Add(this.propertyGrid);
|
//
|
// splitContainer1.Panel2
|
//
|
this.splitContainer1.Panel2.Controls.Add(this.listBox1);
|
this.splitContainer1.Panel2.Controls.Add(this.comboBox_type);
|
this.splitContainer1.Panel2.Controls.Add(this.panel1);
|
this.splitContainer1.Size = new System.Drawing.Size(202, 466);
|
this.splitContainer1.SplitterDistance = 346;
|
this.splitContainer1.TabIndex = 3;
|
//
|
// panel1
|
//
|
this.panel1.Controls.Add(this.checkBox_OnlyShowSelected);
|
this.panel1.Controls.Add(this.textBox_search);
|
this.panel1.Controls.Add(this.label_filter);
|
this.panel1.Controls.Add(this.label_lock);
|
this.panel1.Controls.Add(this.label1);
|
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
|
this.panel1.Location = new System.Drawing.Point(0, 0);
|
this.panel1.Name = "panel1";
|
this.panel1.Size = new System.Drawing.Size(202, 21);
|
this.panel1.TabIndex = 4;
|
//
|
// checkBox_OnlyShowSelected
|
//
|
this.checkBox_OnlyShowSelected.AutoSize = true;
|
this.checkBox_OnlyShowSelected.Checked = true;
|
this.checkBox_OnlyShowSelected.CheckState = System.Windows.Forms.CheckState.Checked;
|
this.checkBox_OnlyShowSelected.Location = new System.Drawing.Point(127, 2);
|
this.checkBox_OnlyShowSelected.Name = "checkBox_OnlyShowSelected";
|
this.checkBox_OnlyShowSelected.Size = new System.Drawing.Size(48, 16);
|
this.checkBox_OnlyShowSelected.TabIndex = 3;
|
this.checkBox_OnlyShowSelected.Text = "选择";
|
this.checkBox_OnlyShowSelected.UseVisualStyleBackColor = true;
|
this.checkBox_OnlyShowSelected.CheckedChanged += new System.EventHandler(this.checkBox_OnlyShowSelected_CheckedChanged);
|
//
|
// textBox_search
|
//
|
this.textBox_search.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
this.textBox_search.Location = new System.Drawing.Point(44, 0);
|
this.textBox_search.Name = "textBox_search";
|
this.textBox_search.Size = new System.Drawing.Size(77, 21);
|
this.textBox_search.TabIndex = 3;
|
this.textBox_search.TextChanged += new System.EventHandler(this.textBox_search_TextChanged);
|
//
|
// label_filter
|
//
|
this.label_filter.BackColor = System.Drawing.Color.Green;
|
this.label_filter.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
this.label_filter.Font = new System.Drawing.Font("宋体", 12F);
|
this.label_filter.ForeColor = System.Drawing.Color.White;
|
this.label_filter.Location = new System.Drawing.Point(177, -1);
|
this.label_filter.Name = "label_filter";
|
this.label_filter.Size = new System.Drawing.Size(21, 21);
|
this.label_filter.TabIndex = 4;
|
this.label_filter.Text = "🔽";
|
this.label_filter.Click += new System.EventHandler(this.label_filter_Click);
|
//
|
// label_lock
|
//
|
this.label_lock.BackColor = System.Drawing.Color.Green;
|
this.label_lock.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
this.label_lock.Font = new System.Drawing.Font("宋体", 12F);
|
this.label_lock.ForeColor = System.Drawing.Color.White;
|
this.label_lock.Location = new System.Drawing.Point(1, 0);
|
this.label_lock.Name = "label_lock";
|
this.label_lock.Size = new System.Drawing.Size(21, 21);
|
this.label_lock.TabIndex = 4;
|
this.label_lock.Text = "🔓";
|
this.label_lock.Click += new System.EventHandler(this.label_lock_Click);
|
//
|
// label1
|
//
|
this.label1.BackColor = System.Drawing.SystemColors.AppWorkspace;
|
this.label1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
this.label1.Font = new System.Drawing.Font("宋体", 12F);
|
this.label1.ForeColor = System.Drawing.Color.White;
|
this.label1.Location = new System.Drawing.Point(22, 0);
|
this.label1.Name = "label1";
|
this.label1.Size = new System.Drawing.Size(21, 21);
|
this.label1.TabIndex = 4;
|
this.label1.Text = "🔍";
|
//
|
// contextMenuStrip1
|
//
|
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
this.全选ToolStripMenuItem});
|
this.contextMenuStrip1.Name = "contextMenuStrip1";
|
this.contextMenuStrip1.Size = new System.Drawing.Size(101, 26);
|
//
|
// 全选ToolStripMenuItem
|
//
|
this.全选ToolStripMenuItem.Name = "全选ToolStripMenuItem";
|
this.全选ToolStripMenuItem.Size = new System.Drawing.Size(100, 22);
|
this.全选ToolStripMenuItem.Text = "全选";
|
this.全选ToolStripMenuItem.Click += new System.EventHandler(this.全选ToolStripMenuItem_Click);
|
//
|
// PropertyForm
|
//
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.Controls.Add(this.splitContainer1);
|
this.Name = "PropertyForm";
|
this.Size = new System.Drawing.Size(202, 466);
|
this.Load += new System.EventHandler(this.PropertyForm_Load_1);
|
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.PropertyForm_KeyDown);
|
this.splitContainer1.Panel1.ResumeLayout(false);
|
this.splitContainer1.Panel2.ResumeLayout(false);
|
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
this.splitContainer1.ResumeLayout(false);
|
this.panel1.ResumeLayout(false);
|
this.panel1.PerformLayout();
|
this.contextMenuStrip1.ResumeLayout(false);
|
this.ResumeLayout(false);
|
|
}
|
|
#endregion
|
|
public System.Windows.Forms.PropertyGrid propertyGrid;
|
public System.Windows.Forms.ListBox listBox1;
|
private System.Windows.Forms.ComboBox comboBox_type;
|
private System.Windows.Forms.SplitContainer splitContainer1;
|
private System.Windows.Forms.CheckBox checkBox_OnlyShowSelected;
|
private System.Windows.Forms.TextBox textBox_search;
|
private System.Windows.Forms.Panel panel1;
|
private System.Windows.Forms.Label label1;
|
private System.Windows.Forms.Label label_lock;
|
private System.Windows.Forms.Label label_filter;
|
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
private System.Windows.Forms.ToolStripMenuItem 全选ToolStripMenuItem;
|
}
|
|
public class DRange
|
{
|
|
public DRange(double min, double max)
|
{
|
Min = min;
|
Max = max;
|
}
|
public DRange(DRange range)
|
{
|
if (range == null)
|
{
|
Min = 0;
|
Max = 0;
|
}
|
else
|
{
|
Min = range.Min;
|
Max = range.Max;
|
}
|
|
}
|
public DRange()
|
{
|
Min = 0;
|
Max = 0;
|
}
|
public double Min { get; set; }
|
public double Max { get; set; }
|
|
public double Length { get { return Max - Min; } }
|
|
public bool IsInside(double x)
|
{
|
return x >= Min && x <= Max;
|
}
|
public bool isValid { get { return Min <= Max; } }
|
public void Union(DRange range)
|
{
|
if (range.Min < Min)
|
{
|
Min = range.Min;
|
}
|
if (range.Max > Max)
|
{
|
Max = range.Max;
|
}
|
}
|
public static DRange Union(DRange range1, DRange range2)
|
{
|
DRange range = new DRange(range1);
|
range.Union(range2);
|
return range;
|
}
|
public override string ToString()
|
{
|
return $"{Min:0.000}-{Max:0.000}";
|
}
|
}
|
public class MathSolver
|
{
|
static double ErrNum = -1;
|
public static List<double> Solve(double a, double b, double c)
|
{
|
// 求解二次方程 ax^2 + bx + c = 0
|
double delta = b * b - 4 * a * c;
|
|
if (delta >= 0)
|
{
|
double x1 = (-b + Math.Sqrt(delta)) / (2 * a);
|
double x2 = (-b - Math.Sqrt(delta)) / (2 * a);
|
return new List<double> { x1, x2 };
|
}
|
else
|
{
|
return null;
|
}
|
}
|
public static List<double> Solve(double a, double b, double c, double d)
|
{
|
double[] roots = null;
|
roots = new double[3];
|
double f = ((3 * c / a) - ((b * b) / (a * a))) / 3;
|
double g = ((2 * (b * b * b) / (a * a * a)) - (9 * b * c / (a * a)) + (27 * d / a)) / 27;
|
double h = ((g * g) / 4) + ((f * f * f) / 27);
|
|
if (h > 0)
|
{
|
double r = -(g / 2) + Math.Sqrt(h);
|
double s = Math.Sign(r) * Math.Pow(Math.Abs(r), (1 / 3.0));
|
double t = -(g / 2) - Math.Sqrt(h);
|
double u = Math.Sign(t) * Math.Pow(Math.Abs(t), (1 / 3.0));
|
|
roots[0] = (s + u) - (b / (3 * a));
|
roots[1] = -1;
|
roots[2] = -1;
|
}
|
else if (f == 0 && g == 0 && h == 0)
|
{
|
roots[0] = Math.Pow((d / a), 1 / 3.0) * -1;
|
roots[1] = roots[0];
|
roots[2] = roots[0];
|
}
|
else
|
{
|
double i = Math.Sqrt(((g * g) / 4) - h);
|
double j = Math.Pow(i, (1 / 3.0));
|
double k = Math.Acos(-(g / (2 * i)));
|
double l = j * -1;
|
double m = Math.Cos(k / 3);
|
double n = Math.Sqrt(3) * Math.Sin(k / 3);
|
double p = (b / (3 * a)) * -1;
|
|
roots[0] = 2 * j * Math.Cos(k / 3) - (b / (3 * a));
|
roots[1] = l * (m + n) + p;
|
roots[2] = l * (m - n) + p;
|
}
|
return roots?.ToList();
|
}
|
|
public static List<double> Solve(double a, double b, double c, double d, double e)
|
{
|
double x = 0; // Initial guess
|
double epsilon = 1e-7; // Precision
|
double diff = 1;
|
double maxRoot = -1;
|
List<double> roots = new List<double>();
|
while (diff > epsilon)
|
{
|
double x2 = x * x;
|
double x3 = x2 * x;
|
double x4 = x2 * x2;
|
|
double f = a * x4 + b * x3 + c * x2 + d * x + e;
|
double df = 4 * a * x3 + 3 * b * x2 + 2 * c * x + d;
|
|
double x1 = x - f / df;
|
diff = Math.Abs(x1 - x);
|
x = x1;
|
|
if (x > maxRoot)
|
{
|
maxRoot = x;
|
}
|
}
|
if (maxRoot < 0) roots = null;
|
else roots.Add(maxRoot);
|
return roots;
|
}
|
|
}
|
public partial class InputBox : Form
|
{
|
DialogResult _DialogResult;
|
|
void initPosition()
|
{
|
this.StartPosition = FormStartPosition.Manual;
|
int offsetX = -1 * this.Width / 2; // 距离鼠标左侧的间距
|
int offsetY = -1 * this.Height / 2; // 距离鼠标顶部的间距
|
int newWindowWidth = this.Width; // 新窗口的宽度
|
int newWindowHeight = this.Height; // 新窗口的高度
|
Point mousePosition = MousePosition; // 获取鼠标位置
|
|
this.Location = new Point(mousePosition.X + offsetX, mousePosition.Y + offsetY); // 计算新窗口的位置
|
}
|
public InputBox()
|
{
|
InitializeComponent();
|
initPosition();
|
|
}
|
public InputBox(string txt, string content = "")
|
{
|
|
InitializeComponent();
|
initPosition();
|
this.Text = txt;
|
this.textBox1.Text = content;
|
|
}
|
|
private void button1_Click(object sender, EventArgs e)
|
{
|
_DialogResult = DialogResult.OK;
|
this.Close();
|
|
}
|
private void button2_Click(object sender, EventArgs e)
|
{
|
_DialogResult = DialogResult.Cancel;
|
this.Close();
|
}
|
public new string ShowDialog()
|
{
|
|
base.ShowDialog();
|
if (_DialogResult == DialogResult.OK)
|
return textBox1.Text;
|
else
|
return null;
|
|
}
|
|
|
}
|
partial class InputBox
|
{
|
|
|
private System.ComponentModel.IContainer components = null;
|
|
protected override void Dispose(bool disposing)
|
{
|
if (disposing && (components != null))
|
{
|
components.Dispose();
|
}
|
base.Dispose(disposing);
|
}
|
|
#region Windows Form Designer generated code
|
|
|
/// Required method for Designer support - do not modify
|
/// the contents of this method with the code editor.
|
|
private void InitializeComponent()
|
{
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InputBox));
|
this.textBox1 = new System.Windows.Forms.TextBox();
|
this.button1 = new System.Windows.Forms.Button();
|
this.button2 = new System.Windows.Forms.Button();
|
this.SuspendLayout();
|
//
|
// textBox1
|
//
|
this.textBox1.Location = new System.Drawing.Point(12, 12);
|
this.textBox1.Name = "textBox1";
|
this.textBox1.Size = new System.Drawing.Size(380, 21);
|
this.textBox1.TabIndex = 0;
|
//
|
// button1
|
//
|
this.button1.Location = new System.Drawing.Point(268, 45);
|
this.button1.Name = "button1";
|
this.button1.Size = new System.Drawing.Size(59, 20);
|
this.button1.TabIndex = 1;
|
this.button1.Text = "确定";
|
this.button1.UseVisualStyleBackColor = true;
|
this.button1.Click += new System.EventHandler(this.button1_Click);
|
//
|
// button2
|
//
|
this.button2.Location = new System.Drawing.Point(333, 45);
|
this.button2.Name = "button2";
|
this.button2.Size = new System.Drawing.Size(59, 20);
|
this.button2.TabIndex = 1;
|
this.button2.Text = "取消";
|
this.button2.UseVisualStyleBackColor = true;
|
this.button2.Click += new System.EventHandler(this.button2_Click);
|
//
|
// InputBox
|
//
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.ClientSize = new System.Drawing.Size(404, 74);
|
this.Controls.Add(this.button2);
|
this.Controls.Add(this.button1);
|
this.Controls.Add(this.textBox1);
|
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
this.MaximizeBox = false;
|
this.MinimizeBox = false;
|
this.Name = "InputBox";
|
this.Text = "输入名称";
|
this.TopMost = true;
|
this.ResumeLayout(false);
|
this.PerformLayout();
|
|
}
|
|
#endregion
|
|
private System.Windows.Forms.TextBox textBox1;
|
private System.Windows.Forms.Button button1;
|
private System.Windows.Forms.Button button2;
|
}
|
public static class FileCopy
|
{
|
public static void Copy(string source, string destination, bool isOverWrite = true)
|
{
|
//判断源文件是否存在
|
if (!System.IO.File.Exists(source))
|
{
|
return;
|
}
|
//判断源文件是否为只读,如果是则更改为非只读
|
System.IO.FileInfo file = new System.IO.FileInfo(source);
|
if (file.IsReadOnly)
|
{
|
file.IsReadOnly = false;
|
}
|
//判断目标文件夹是否存在,不存在则创建
|
string dir = System.IO.Path.GetDirectoryName(destination);
|
try
|
{
|
System.IO.File.Copy(source, destination, isOverWrite);
|
}
|
catch (Exception)
|
{
|
|
}
|
|
}
|
}
|
|
public static class PointFExtansion
|
{
|
public static Point ToPoint(this PointF p)
|
{
|
return new Point((int)p.X, (int)p.Y);
|
}
|
}
|
|
public static class DeepCopyClass
|
{
|
public static T DeepCopyByBin<T>(this T obj)
|
{
|
object retval;
|
using (MemoryStream ms = new MemoryStream())
|
{
|
BinaryFormatter bf = new BinaryFormatter();
|
//序列化成流
|
bf.Serialize(ms, obj);
|
ms.Seek(0, SeekOrigin.Begin);
|
//反序列化成对象
|
retval = bf.Deserialize(ms);
|
ms.Close();
|
}
|
return (T)retval;
|
}
|
|
public static void SerialToFile(this object obj, string filePath)
|
{
|
// 创建文件流
|
FileStream fileStream = new FileStream(filePath, FileMode.Create);
|
|
try
|
{
|
// 创建BinaryFormatter对象
|
BinaryFormatter formatter = new BinaryFormatter();
|
|
// 序列化并保存对象到文件流
|
formatter.Serialize(fileStream, obj);
|
|
Console.WriteLine("对象已经成功序列化并保存到文件中!");
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine("发生错误:" + ex.Message);
|
}
|
finally
|
{
|
// 关闭文件流
|
fileStream.Close();
|
}
|
|
}
|
private static T CloneModel<T>(T oModel)
|
{
|
var oRes = default(T);
|
var oType = typeof(T);
|
|
//create new obj
|
oRes = (T)Activator.CreateInstance(oType);
|
|
//pass 1 property
|
var lstPro = oType.GetProperties();
|
foreach (var oPro in lstPro)
|
{
|
var oValue = oPro.GetValue(oModel, null);
|
oPro.SetValue(oRes, DeepCopy(oValue), null);
|
}
|
|
var lstField = oType.GetFields();
|
foreach (var oField in lstField)
|
{
|
var oValue = oField.GetValue(oModel);
|
oField.SetValue(oRes, DeepCopy(oValue));
|
}
|
return oRes;
|
}
|
public static object DeepCopy(this object obj)
|
{
|
if (obj == null)
|
return null;
|
Type type = obj.GetType();
|
|
if (type.IsValueType || type == typeof(string))
|
{
|
return obj;
|
}
|
else if (type.IsArray)
|
{
|
Type elementType = Type.GetType(
|
type.FullName.Replace("[]", string.Empty));
|
var array = obj as Array;
|
Array copied = Array.CreateInstance(elementType, array.Length);
|
for (int i = 0; i < array.Length; i++)
|
{
|
copied.SetValue(DeepCopy(array.GetValue(i)), i);
|
}
|
return Convert.ChangeType(copied, obj.GetType());
|
}
|
else if (type.IsClass)
|
{
|
|
object toret = Activator.CreateInstance(obj.GetType());
|
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
|
BindingFlags.NonPublic | BindingFlags.Instance);
|
foreach (FieldInfo field in fields)
|
{
|
object fieldValue = field.GetValue(obj);
|
if (fieldValue == null)
|
continue;
|
field.SetValue(toret, DeepCopy(fieldValue));
|
}
|
return toret;
|
}
|
else
|
throw new ArgumentException("Unknown type");
|
}
|
}
|
|
public class message
|
{
|
public static bool show(string caption, string content, MessageBoxButtons boxButtons = MessageBoxButtons.OKCancel)
|
{
|
var result = MessageBox.Show(content, caption, boxButtons, MessageBoxIcon.Information);
|
if (result == DialogResult.OK || result == DialogResult.Yes)
|
return true;
|
else
|
return false;
|
}
|
}
|