Files
FluidSim/Scenarios/Scenario.cs
2026-05-07 21:48:37 +02:00

195 lines
7.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using SFML.Graphics;
using SFML.System;
using FluidSim.Components;
namespace FluidSim.Tests
{
public abstract class Scenario
{
public abstract void Initialize(int sampleRate);
public abstract float Process();
public abstract void Draw(RenderWindow target);
protected const double AmbientPressure = 101325.0;
protected const double AmbientTemperature = 300.0;
// ---------- Color from pressure (volumes) ----------
protected Color PressureColor(double pressurePa)
{
double bar = pressurePa / 1e5; // convert to bar for easier mapping
byte r, g, b;
if (bar < 1.0) // vacuum → blue to green
{
double factor = Math.Clamp(bar, 0.0, 1.0);
r = 0;
g = (byte)(255 * factor);
b = (byte)(255 * (1.0 - factor));
}
else // above ambient → green to red
{
double factor = Math.Min((bar - 1.0) / 9.0, 1.0); // 1→10 bar maps to 0→1
r = (byte)(255 * factor);
g = (byte)(255 * (1.0 - factor));
b = 0;
}
return new Color(r, g, b);
}
// ---------- Color from temperature (pipes) ----------
protected Color TemperatureColor(double temperature)
{
double t = Math.Clamp(temperature, 0.0, 2000.0);
byte r, g, b;
if (t < AmbientTemperature)
{
double factor = t / AmbientTemperature;
r = 0;
g = (byte)(255 * factor);
b = (byte)(255 * (1.0 - factor));
}
else
{
double factor = (t - AmbientTemperature) / (2000.0 - AmbientTemperature);
r = (byte)(255 * factor);
g = (byte)(255 * (1.0 - factor));
b = 0;
}
return new Color(r, g, b);
}
// ---------- Draw a generic volume (e.g. plenum) ----------
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), // ← pressurebased
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 = new Vector2f(centerX - width / 2f, topY)
};
target.Draw(border);
}
// ---------- Draw an engine cylinder ----------
protected void DrawCylinder(RenderWindow target, Cylinder cylinder,
float centerX, float topY, float width, float maxHeight)
{
double fraction = cylinder.PistonFraction;
float currentHeight = (float)(maxHeight * fraction);
// Walls
var wall = new RectangleShape(new Vector2f(width, maxHeight));
wall.FillColor = new Color(60, 60, 60);
wall.Position = new Vector2f(centerX - width / 2f, topY);
target.Draw(wall);
// Gas colored by pressure now
float gasTop = topY;
var gasRect = new RectangleShape(new Vector2f(width, currentHeight));
gasRect.FillColor = PressureColor(cylinder.Pressure); // ← pressurebased
gasRect.Position = new Vector2f(centerX - width / 2f, gasTop);
target.Draw(gasRect);
// Piston line
var pistonLine = new RectangleShape(new Vector2f(width, 4f));
pistonLine.FillColor = Color.White;
pistonLine.Position = new Vector2f(centerX - width / 2f, topY + currentHeight);
target.Draw(pistonLine);
// Valve indicators
float valveW = 6f, valveH = 10f, valveY = topY + 4f;
var intakeValve = new RectangleShape(new Vector2f(valveW, valveH));
intakeValve.FillColor = cylinder.IntakeValveArea > 0 ? Color.Green : Color.Red;
intakeValve.Position = new Vector2f(centerX - width / 2f - valveW - 2f, valveY);
target.Draw(intakeValve);
var exhaustValve = new RectangleShape(new Vector2f(valveW, valveH));
exhaustValve.FillColor = cylinder.ExhaustValveArea > 0 ? Color.Green : Color.Red;
exhaustValve.Position = new Vector2f(centerX + width / 2f + 2f, valveY);
target.Draw(exhaustValve);
}
// ---------- Draw a pipe (unchanged) ----------
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);
float baseRadius = 25f;
float rangeFactor = 2f;
float scaleFactor = 2f;
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);
}
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);
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;
}
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]); // pipes still use temperature
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;
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);
}
}
}