| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- using Avalonia;
- using Avalonia.Media;
- using System;
- using System.Globalization;
- namespace YZWater.Avalonia.Controls.Renderers;
- /// <summary>
- /// 泵渲染器 - 绘制圆形泵体 + 旋转叶片 + 状态光晕。
- /// 抽取自 PumpStation2DControl,供多个控件复用。
- /// </summary>
- public static class PumpRenderer
- {
- /// <summary>
- /// 绘制一个泵。
- /// </summary>
- /// <param name="context">绘图上下文</param>
- /// <param name="center">泵体中心(屏幕坐标)</param>
- /// <param name="radius">泵体半径</param>
- /// <param name="isRunning">是否运行中</param>
- /// <param name="statusColor">状态颜色(运行=Success色, 停止=Disabled色)</param>
- /// <param name="rotationAngle">当前叶片旋转角度(度)</param>
- /// <param name="text">标签文字(如 P1)</param>
- /// <param name="bgBrush">泵体背景画刷</param>
- /// <param name="borderBrush">边框画刷</param>
- /// <param name="textBrush">文字画刷</param>
- /// <param name="bladeCount">叶片数量</param>
- /// <param name="bladePenThickness">叶片画笔粗细</param>
- public static void Draw(
- DrawingContext context,
- Point center,
- double radius,
- bool isRunning,
- Color statusColor,
- double rotationAngle,
- string text,
- IBrush bgBrush,
- IBrush borderBrush,
- IBrush textBrush,
- int bladeCount = 4,
- double bladePenThickness = 2.5)
- {
- var cx = center.X;
- var cy = center.Y;
- var statusBrush = new SolidColorBrush(statusColor);
- // 运行光晕
- if (isRunning)
- context.DrawEllipse(new SolidColorBrush(statusColor, 0.18), null,
- new Rect(cx - radius * 1.4, cy - radius * 1.4, radius * 2.8, radius * 2.8));
- // 泵体圆
- context.DrawEllipse(bgBrush, new Pen(statusBrush, isRunning ? 2 : 1.2),
- new Rect(cx - radius, cy - radius, radius * 2, radius * 2));
- // 旋转叶片
- for (int i = 0; i < bladeCount; i++)
- {
- var angle = (isRunning ? rotationAngle : 0) + i * (360.0 / bladeCount);
- var rad = angle * Math.PI / 180.0;
- var bx = cx + Math.Cos(rad) * radius * 0.65;
- var by = cy + Math.Sin(rad) * radius * 0.65;
- var bladeBrush = new SolidColorBrush(statusColor, isRunning ? 0.9 : 0.45);
- context.DrawLine(new Pen(bladeBrush, bladePenThickness),
- new Point(cx, cy), new Point(bx, by));
- }
- // 中心圆
- context.DrawEllipse(statusBrush, null,
- new Rect(cx - radius * 0.22, cy - radius * 0.22, radius * 0.44, radius * 0.44));
- // 标签
- if (!string.IsNullOrEmpty(text))
- {
- var fontSize = Math.Max(8, radius * 0.56);
- var formatted = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
- new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold), fontSize, textBrush);
- context.DrawText(formatted, new Point(cx - formatted.Width / 2, cy + radius + 3));
- }
- }
- // ════════════════════════════════════════════════════════
- // 立式泵(拟真)
- // ════════════════════════════════════════════════════════
- /// <summary>
- /// 绘制潜水排污泵(仿污水泵站现场):顶部电机仓 + 吊环 + 泵壳圆筒(叶轮观察窗旋转)
- /// + 底部进水喇叭口 + 自动耦合导轨。头顶一根出水管直通总管,泵体沉入集水池液面。
- /// </summary>
- /// <param name="context">绘图上下文</param>
- /// <param name="voluteCenter">泵壳筒体中心(屏幕坐标)</param>
- /// <param name="radius">筒体半径</param>
- /// <param name="isRunning">运行中(叶轮旋转 + 光晕)</param>
- /// <param name="statusColor">状态色(运行绿 / 停止灰 / 故障红)</param>
- /// <param name="rotationAngle">叶轮角度(度)</param>
- /// <param name="text">标签(泵名)</param>
- /// <param name="borderBrush">边框画刷</param>
- /// <param name="textBrush">文字画刷</param>
- /// <param name="faultFlashing">故障闪烁相位 0~1(<0 表示无故障)</param>
- public static void DrawVertical(
- DrawingContext context,
- Point voluteCenter,
- double radius,
- bool isRunning,
- Color statusColor,
- double rotationAngle,
- string text,
- IBrush borderBrush,
- IBrush textBrush,
- double faultFlashing = -1)
- {
- var cx = voluteCenter.X;
- var cy = voluteCenter.Y;
- var statusBrush = new SolidColorBrush(statusColor);
- // 圆筒金属渐变:左高光 → 中亮 → 右暗(模拟圆柱体光照)
- var shellMetal = new LinearGradientBrush
- {
- StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
- EndPoint = new RelativePoint(1, 0, RelativeUnit.Relative),
- GradientStops =
- {
- new GradientStop(Color.FromRgb(198, 206, 216), 0), // 左高光
- new GradientStop(Color.FromRgb(150, 160, 174), 0.22),
- new GradientStop(Color.FromRgb(120, 130, 144), 0.78),
- new GradientStop(Color.FromRgb(88, 96, 110), 1), // 右暗
- }
- };
- var metalDark = new SolidColorBrush(Color.FromRgb(96, 105, 118));
- var steel = new SolidColorBrush(Color.FromRgb(112, 122, 136));
- var cavity = new SolidColorBrush(Color.FromRgb(52, 60, 72));
- // ═══ 纵向尺寸规划(自顶向下)═══
- // 顶部出管法兰 cy - 2.55r ~ cy - 2.40r
- // 电机仓(顶盖) cy - 2.40r ~ cy - 1.85r
- // 泵壳圆筒 cy - 1.85r ~ cy + 1.05r
- // 进水喇叭口 cy + 1.05r ~ cy + 1.60r
- var flangeTop = cy - radius * 2.55;
- var motorTop = cy - radius * 2.40;
- var shellTop = cy - radius * 1.85;
- var shellBottom = cy + radius * 1.05;
- var bellBottom = cy + radius * 1.60;
- // ─── 顶部出管法兰(衔接排出竖管)───
- var flangeRect = new Rect(cx - radius * 0.42, flangeTop, radius * 0.84, radius * 0.15);
- context.DrawRectangle(metalDark, new Pen(borderBrush, 1), flangeRect, 1, 1);
- // ─── 电机仓(短粗顶盖 + 散热筋 + 吊环 + 接线盒)───
- var motorRect = new Rect(cx - radius * 0.62, motorTop, radius * 1.24, radius * 0.55);
- context.DrawRectangle(shellMetal, new Pen(borderBrush, 1.2), motorRect, 3, 3);
- // 散热筋(横线)
- for (int i = 1; i <= 3; i++)
- {
- var fy = motorRect.Y + motorRect.Height * i / 4.0;
- context.DrawLine(new Pen(metalDark, 1),
- new Point(motorRect.X + 3, fy), new Point(motorRect.Right - 3, fy));
- }
- // 接线盒(顶盖上方小箱,带线管)
- var boxRect = new Rect(cx - radius * 0.3, motorTop - radius * 0.22, radius * 0.6, radius * 0.22);
- context.DrawRectangle(metalDark, new Pen(borderBrush, 1), boxRect, 2, 2);
- // 吊环(接线盒顶,供起吊检修)
- var hookY = motorTop - radius * 0.30;
- context.DrawEllipse(null, new Pen(metalDark, 1.6),
- new Rect(cx - radius * 0.13, hookY - radius * 0.2, radius * 0.26, radius * 0.4));
- // ─── 运行光晕(筒体后方,呼吸脉冲)───
- if (isRunning)
- {
- var breathe = 1.5 + Math.Sin((rotationAngle * Math.PI / 180) * 2) * 0.22;
- var glowAlpha = (byte)(36 + Math.Sin((rotationAngle * Math.PI / 180) * 2) * 18);
- var glowH = (shellBottom - shellTop) * 1.5;
- context.DrawEllipse(new SolidColorBrush(Color.FromArgb(glowAlpha, 76, 175, 80)), null,
- new Rect(cx - radius * breathe, cy - glowH / 2, radius * 2 * breathe, glowH));
- }
- // ─── 泵壳圆筒(主体,细长筒体 + 上下盖法兰 + 加强筋)───
- context.DrawRectangle(shellMetal, new Pen(statusBrush, isRunning ? 2.4 : 1.4),
- new Rect(cx - radius, shellTop, radius * 2, shellBottom - shellTop), 3, 3);
- // 顶部/底部加强法兰环
- context.DrawRectangle(metalDark, new Pen(borderBrush, 1),
- new Rect(cx - radius, shellTop, radius * 2, radius * 0.14), 1, 1);
- context.DrawRectangle(metalDark, new Pen(borderBrush, 1),
- new Rect(cx - radius, shellBottom - radius * 0.14, radius * 2, radius * 0.14), 1, 1);
- // 纵向加强筋(筒体表面 4 条)
- for (int i = 1; i <= 4; i++)
- {
- var fx = cx - radius + radius * 2 * (i / 5.0);
- context.DrawLine(new Pen(new SolidColorBrush(Color.FromArgb(120, 200, 210, 220)), 1),
- new Point(fx, shellTop + radius * 0.1), new Point(fx, shellBottom - radius * 0.1));
- }
- // ─── 叶轮观察窗(筒体上部圆形舱窗,透过窗看到旋转叶轮)───
- var winCx = cx;
- var winCy = cy - radius * 0.45;
- var winR = radius * 0.48;
- context.DrawEllipse(cavity, new Pen(borderBrush, 1.2),
- new Rect(winCx - winR, winCy - winR, winR * 2, winR * 2));
- // 窗框高光(体现鼓出的玻璃窗)
- context.DrawEllipse(null, new Pen(new SolidColorBrush(Color.FromArgb(70, 220, 230, 240)), 1),
- new Rect(winCx - winR * 0.86, winCy - winR * 0.86, winR * 1.72, winR * 1.72));
- // 叶轮(运行时旋转,停止时定格 45°)
- for (int i = 0; i < 3; i++)
- {
- var angle = (isRunning ? rotationAngle : 45) + i * 120;
- var rad = angle * Math.PI / 180.0;
- var bx = winCx + Math.Cos(rad) * winR * 0.72;
- var by = winCy + Math.Sin(rad) * winR * 0.72;
- var bladeBrush = new SolidColorBrush(isRunning ? Color.FromRgb(120, 220, 130) : Color.FromRgb(150, 160, 172),
- isRunning ? 0.95 : 0.6);
- context.DrawLine(new Pen(bladeBrush, 2), new Point(winCx, winCy), new Point(bx, by));
- }
- // 轮毂
- context.DrawEllipse(statusBrush, null,
- new Rect(winCx - radius * 0.12, winCy - radius * 0.12, radius * 0.24, radius * 0.24));
- // ─── 自动耦合导轨(筒体两侧竖直导杆,直通池底)───
- var guideBrush = new Pen(steel, Math.Max(1.2, radius * 0.09));
- context.DrawLine(guideBrush, new Point(cx - radius * 1.18, shellTop + radius * 0.2),
- new Point(cx - radius * 1.18, bellBottom));
- context.DrawLine(guideBrush, new Point(cx + radius * 1.18, shellTop + radius * 0.2),
- new Point(cx + radius * 1.18, bellBottom));
- // ─── 底部进水喇叭口(锥形收口 + 滤网)───
- var bell = new StreamGeometry();
- using (var g = bell.Open())
- {
- g.BeginFigure(new Point(cx - radius, shellBottom), true);
- g.LineTo(new Point(cx - radius * 0.78, bellBottom), false);
- g.LineTo(new Point(cx + radius * 0.78, bellBottom), false);
- g.LineTo(new Point(cx + radius, shellBottom), false);
- g.EndFigure(true);
- }
- context.DrawGeometry(shellMetal, new Pen(borderBrush, 1.1), bell);
- // 喇叭口箍环 + 滤网格线
- context.DrawLine(new Pen(metalDark, 1.2),
- new Point(cx - radius * 0.82, bellBottom - radius * 0.12),
- new Point(cx + radius * 0.82, bellBottom - radius * 0.12));
- for (int i = -2; i <= 2; i++)
- {
- context.DrawLine(new Pen(new SolidColorBrush(Color.FromArgb(130, 60, 68, 80)), 1),
- new Point(cx + i * radius * 0.18, bellBottom - radius * 0.18),
- new Point(cx + i * radius * 0.18, bellBottom));
- }
- // ─── 故障标记(筒体左上方红色三角 + 闪烁)───
- if (faultFlashing >= 0)
- {
- var flash = Math.Sin(faultFlashing * Math.PI * 2) > 0;
- if (flash)
- {
- var triSize = radius * 0.5;
- var triTop = cy - radius * 2.9;
- var geo = new StreamGeometry();
- using (var g = geo.Open())
- {
- g.BeginFigure(new Point(cx, triTop), true);
- g.LineTo(new Point(cx - triSize / 2, triTop + triSize * 0.9), false);
- g.LineTo(new Point(cx + triSize / 2, triTop + triSize * 0.9), false);
- g.EndFigure(true);
- }
- context.DrawGeometry(new SolidColorBrush(Color.FromRgb(244, 67, 54)), null, geo);
- var exFt = new FormattedText("!", CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
- new Typeface("Consolas", FontStyle.Normal, FontWeight.Bold), triSize * 0.8,
- Brushes.White);
- context.DrawText(exFt, new Point(cx - exFt.Width / 2, triTop + triSize * 0.05));
- }
- }
- // ─── 标签(喇叭口下方)───
- if (!string.IsNullOrEmpty(text))
- {
- var fontSize = Math.Max(8, radius * 0.5);
- var formatted = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
- new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold), fontSize, textBrush);
- context.DrawText(formatted, new Point(cx - formatted.Width / 2, bellBottom + 2));
- }
- }
- }
|