using SFML.Graphics; using SFML.System; using FluidSim.Core; using FluidSim.Components; namespace FluidSim.Tests { public abstract class Scenario { protected const float AmbientPressure = 101325f; protected const float AmbientTemperature = 300f; public float Throttle { get; set; } public abstract void Initialize(int sampleRate); public abstract float Process(); public abstract void Draw(RenderWindow target); protected Color PressureColor(float pressurePa) { float bar = pressurePa / 1e5f; byte r, g, b; if (bar < 1f) { float f = Math.Clamp(bar, 0f, 1f); r = 0; g = (byte)(255 * f); b = (byte)(255 * (1 - f)); } else { float f = Math.Min((bar - 1f) / 9f, 1f); r = (byte)(255 * f); g = (byte)(255 * (1 - f)); b = 0; } return new Color(r, g, b); } protected Color TemperatureColor(float t) { t = Math.Clamp(t, 0f, 2000f); byte r, g, b; if (t < AmbientTemperature) { float f = t / AmbientTemperature; r = 0; g = (byte)(255 * f); b = (byte)(255 * (1 - f)); } else { float f = (t - AmbientTemperature) / (2000f - AmbientTemperature); r = (byte)(255 * f); g = (byte)(255 * (1 - f)); b = 0; } return new Color(r, g, b); } protected void DrawVolume(RenderWindow target, Volume0D volume, float centerX, float topY, float width, float height) { var rect = new RectangleShape(new Vector2f(width, height)) { FillColor = PressureColor(volume.Pressure), Position = new Vector2f(centerX - width / 2f, topY) }; target.Draw(rect); var border = new RectangleShape(new Vector2f(width, height)) { FillColor = Color.Transparent, OutlineColor = Color.White, OutlineThickness = 1f, Position = rect.Position }; target.Draw(border); } protected void DrawCylinder(RenderWindow target, Cylinder cylinder, float centerX, float topY, float width, float maxHeight) { float fraction = cylinder.PistonFraction; float currentHeight = maxHeight * fraction; var wall = new RectangleShape(new Vector2f(width, maxHeight)) { FillColor = new Color(60, 60, 60), Position = new Vector2f(centerX - width / 2f, topY) }; target.Draw(wall); var gas = new RectangleShape(new Vector2f(width, currentHeight)) { FillColor = PressureColor(cylinder.Pressure), Position = new Vector2f(centerX - width / 2f, topY) }; target.Draw(gas); var piston = new RectangleShape(new Vector2f(width, 4f)) { FillColor = Color.White, Position = new Vector2f(centerX - width / 2f, topY + currentHeight) }; target.Draw(piston); float valveW = 6f, valveH = 10f, valveY = topY + 4f; var iv = new RectangleShape(new Vector2f(valveW, valveH)) { FillColor = cylinder.IntakeValveArea > 0f ? Color.Green : Color.Red, Position = new Vector2f(centerX - width / 2f - valveW - 2f, valveY) }; target.Draw(iv); var ev = new RectangleShape(new Vector2f(valveW, valveH)) { FillColor = cylinder.ExhaustValveArea > 0f ? Color.Green : Color.Red, Position = new Vector2f(centerX + width / 2f + 2f, valveY) }; target.Draw(ev); } protected void DrawPipe(RenderWindow target, PipeSystem pipeSystem, int pipeIndex, float pipeCenterY, float pipeStartX, float pipeEndX) { int start = pipeSystem.GetPipeStart(pipeIndex); int end = pipeSystem.GetPipeEnd(pipeIndex); int n = end - start; if (n < 2) return; float pipeLen = pipeEndX - pipeStartX; float dx = pipeLen / (n - 1); float baseRadius = 25f; var centers = new float[n]; var radii = new float[n]; var temps = new float[n]; for (int i = 0; i < n; i++) { int cell = start + i; float p = pipeSystem.GetCellPressure(cell); float rho = pipeSystem.GetCellDensity(cell); temps[i] = p / MathF.Max(rho * 287f, 1e-12f); float dev = MathF.Tanh((p - AmbientPressure) / AmbientPressure * 0.5f); radii[i] = baseRadius * (1f + dev * 2f); if (radii[i] < 2f) radii[i] = 2f; centers[i] = pipeStartX + i * dx; } int segments = 8; var va = new VertexArray(PrimitiveType.TriangleStrip); for (int i = 0; i < n; i++) { float x = centers[i], r = radii[i]; Color col = TemperatureColor(temps[i]); va.Append(new Vertex(new Vector2f(x, pipeCenterY - r), col)); va.Append(new Vertex(new Vector2f(x, pipeCenterY + r), col)); if (i < n - 1) { for (int s = 1; s <= segments; s++) { float t = s / (float)segments; float xi = centers[i] + (centers[i + 1] - centers[i]) * t; float ri = radii[i] + (radii[i + 1] - radii[i]) * t; float Ti = temps[i] + (temps[i + 1] - temps[i]) * t; Color colS = TemperatureColor(Ti); va.Append(new Vertex(new Vector2f(xi, pipeCenterY - ri), colS)); va.Append(new Vertex(new Vector2f(xi, pipeCenterY + ri), colS)); } } } target.Draw(va); } } }