130 lines
5.1 KiB
C#
130 lines
5.1 KiB
C#
using System;
|
||
using SFML.Graphics;
|
||
using SFML.System;
|
||
using FluidSim.Components;
|
||
|
||
namespace FluidSim.Tests
|
||
{
|
||
public abstract class Scenario
|
||
{
|
||
/// <summary>Initialize the scenario with a given audio sample rate.</summary>
|
||
public abstract void Initialize(int sampleRate);
|
||
|
||
/// <summary>Advance one simulation step and return an audio sample.</summary>
|
||
public abstract float Process();
|
||
|
||
/// <summary>Draw the current simulation state onto the given SFML render target.</summary>
|
||
public abstract void Draw(RenderWindow target);
|
||
|
||
// ---------- Shared drawing helpers ----------
|
||
|
||
protected const double AmbientPressure = 101325.0;
|
||
protected const double AmbientTemperature = 300.0; // K
|
||
|
||
/// <summary>Map temperature [0 K … 2000 K] to a color: blue (0 K) → green (300 K) → red (2000 K).</summary>
|
||
protected Color TemperatureColor(double temperature)
|
||
{
|
||
// Clamp to the range we want to display
|
||
double t = Math.Clamp(temperature, 0.0, 2000.0);
|
||
|
||
byte r, g, b;
|
||
if (t < AmbientTemperature)
|
||
{
|
||
// Blue → Green
|
||
double factor = t / AmbientTemperature; // 0 at 0 K, 1 at 300 K
|
||
r = 0;
|
||
g = (byte)(255 * factor);
|
||
b = (byte)(255 * (1.0 - factor));
|
||
}
|
||
else
|
||
{
|
||
// Green → Red
|
||
double factor = (t - AmbientTemperature) / (2000.0 - AmbientTemperature); // 0 at 300 K, 1 at 2000 K
|
||
r = (byte)(255 * factor);
|
||
g = (byte)(255 * (1.0 - factor));
|
||
b = 0;
|
||
}
|
||
return new Color(r, g, b);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Draws the pipe as a smooth triangle‑strip whose radius varies with cell pressure (for visibility),
|
||
/// but colored by temperature.
|
||
/// </summary>
|
||
protected void DrawPipe(RenderWindow target, Pipe1D pipe, float pipeCenterY, float pipeStartX, float pipeEndX)
|
||
{
|
||
int n = pipe.CellCount;
|
||
if (n < 2) return;
|
||
|
||
float pipeLengthPx = pipeEndX - pipeStartX;
|
||
float dx = pipeLengthPx / (n - 1); // spacing between cell centres
|
||
|
||
float baseRadius = 25f;
|
||
float rangeFactor = 2f;
|
||
float scaleFactor = 2f;
|
||
|
||
// ----- smoothstep helper -----
|
||
static float SmoothStep(float edge0, float edge1, float x)
|
||
{
|
||
float t = Math.Clamp((x - edge0) / (edge1 - edge0), 0f, 1f);
|
||
return t * t * (3f - 2f * t);
|
||
}
|
||
|
||
// ----- Pre‑compute cell positions, radii, and temperatures -----
|
||
var centers = new float[n];
|
||
var radii = new float[n];
|
||
var temperatures = new double[n];
|
||
double R_gas = 287.0;
|
||
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
double p = pipe.GetCellPressure(i);
|
||
double rho = pipe.GetCellDensity(i);
|
||
double T = p / Math.Max(rho * R_gas, 1e-12); // ideal gas
|
||
temperatures[i] = T;
|
||
|
||
float deviation = (float)Math.Tanh((p - AmbientPressure) / AmbientPressure / rangeFactor);
|
||
radii[i] = baseRadius * (1f + deviation * scaleFactor);
|
||
if (radii[i] < 2f) radii[i] = 2f;
|
||
centers[i] = pipeStartX + i * dx;
|
||
}
|
||
|
||
// ----- Build triangle‑strip vertices -----
|
||
int segmentsPerCell = 8;
|
||
int totalPoints = n + (n - 1) * segmentsPerCell;
|
||
Vertex[] stripVertices = new Vertex[totalPoints * 2];
|
||
int idx = 0;
|
||
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
float x = centers[i];
|
||
float r = radii[i];
|
||
Color col = TemperatureColor(temperatures[i]);
|
||
|
||
stripVertices[idx++] = new Vertex(new Vector2f(x, pipeCenterY - r), col);
|
||
stripVertices[idx++] = new Vertex(new Vector2f(x, pipeCenterY + r), col);
|
||
|
||
if (i < n - 1)
|
||
{
|
||
for (int s = 1; s <= segmentsPerCell; s++)
|
||
{
|
||
float t = s / (float)segmentsPerCell;
|
||
float st = SmoothStep(0f, 1f, t);
|
||
float xi = centers[i] + (centers[i + 1] - centers[i]) * t;
|
||
float ri = radii[i] + (radii[i + 1] - radii[i]) * st;
|
||
double Ti = temperatures[i] + (temperatures[i + 1] - temperatures[i]) * st; // linear interpolation
|
||
Color coli = TemperatureColor(Ti);
|
||
|
||
stripVertices[idx++] = new Vertex(new Vector2f(xi, pipeCenterY - ri), coli);
|
||
stripVertices[idx++] = new Vertex(new Vector2f(xi, pipeCenterY + ri), coli);
|
||
}
|
||
}
|
||
}
|
||
|
||
var pipeMesh = new VertexArray(PrimitiveType.TriangleStrip, (uint)stripVertices.Length);
|
||
for (int i = 0; i < stripVertices.Length; i++)
|
||
pipeMesh[(uint)i] = stripVertices[i];
|
||
target.Draw(pipeMesh);
|
||
}
|
||
}
|
||
} |