using Avalonia; using Avalonia.Media; using System; using System.Globalization; namespace YZWater.Avalonia.Controls.Renderers; /// /// 泵渲染器 - 绘制圆形泵体 + 旋转叶片 + 状态光晕。 /// 抽取自 PumpStation2DControl,供多个控件复用。 /// public static class PumpRenderer { /// /// 绘制一个泵。 /// /// 绘图上下文 /// 泵体中心(屏幕坐标) /// 泵体半径 /// 是否运行中 /// 状态颜色(运行=Success色, 停止=Disabled色) /// 当前叶片旋转角度(度) /// 标签文字(如 P1) /// 泵体背景画刷 /// 边框画刷 /// 文字画刷 /// 叶片数量 /// 叶片画笔粗细 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)); } } // ════════════════════════════════════════════════════════ // 立式泵(拟真) // ════════════════════════════════════════════════════════ /// /// 绘制潜水排污泵(仿污水泵站现场):顶部电机仓 + 吊环 + 泵壳圆筒(叶轮观察窗旋转) /// + 底部进水喇叭口 + 自动耦合导轨。头顶一根出水管直通总管,泵体沉入集水池液面。 /// /// 绘图上下文 /// 泵壳筒体中心(屏幕坐标) /// 筒体半径 /// 运行中(叶轮旋转 + 光晕) /// 状态色(运行绿 / 停止灰 / 故障红) /// 叶轮角度(度) /// 标签(泵名) /// 边框画刷 /// 文字画刷 /// 故障闪烁相位 0~1(<0 表示无故障) 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)); } } }