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));
}
}
}