Factorio Fluid Model Proposal
A model of a straight pipe using the wave equation. Source and sink can be turned on and off. Fluid output and intake is measured.
by TheYeast
HTML
<div id="main">
<input type="checkbox" id="cbSource" checked="checked"/>source
<div id="pipe">
</div>
<input type="checkbox" id="cbSink" checked="checked"/>sink
<div>total fluid: <span id="vTotal">s</span></div>
<div>source output: <span id="vSource">s</span></div>
<div>sink intake: <span id="vSink">s</span></div>
</div>
CSS
body {
background: #20262E;
padding: 20px;
color: #eee;
}
.seg {
position: relative;
width: 20px;
height: 20px;
}
.fluid {
position: relative;
width: 20px;
height: 20px;
}
.flow {
position: absolute;
background: #f7f;
left: 30px;
top: 5px;
height: 5px;
JavaScript
var ups = 60; // updates per second
var n = 10 + 2; // 10 pipe + source & sink
var sourceOutMax = 6000; // source supply limit per second
var sinkInMax = 6000; // sink intake limit per second
var cSquared = 0.01; // see equations and blog posts
var friction = 0.001; // see equations and blog posts
var pipe = [];
for (var i = 0; i < n; ++i) {
var div = $("<div class='seg'></div>");
var fluid = $("<div class='fluid'></div>");
var flow = $("<div class='flow'></div>");
$("#pipe").append(div);
div.append(fluid);
div.append(flow);
pipe[i] = {
level : 0,
flowBot : 0,
div : div,
divFluid : fluid,
divFlow : flow
};
}
window.setInterval(function() { update() }, 1000/ups);
function update() {
var src = updateSource(pipe[0]);
var sunk = updateSink(pipe[n-1]);
var i;
for (i = 0; i < n-1; ++i) {
updateFlow(pipe[i], pipe[i+1]);
}
for (i = 0; i < n-1; ++i) {
updateLevel(pipe[i], pipe[i+1]);
}
var t = 0;
for (i = 0; i < n; ++i) {
draw(pipe[i]);
t += pipe[i].level;
}
$("#vTotal").text(Math.round(t));
$("#vSource").text(Math.round(src*ups) + "/s");
$("#vSink").text(Math.round(sunk*ups) + "/s");
}
function updateFlow(p0, p1) {
p0.flowBot += (p0.level-p1.level) * cSquared;
p0.flowBot *= (1 - friction);
if (p0.flowBot > 0 && p0.flowBot > 0.25 * p0.level)
p0.flowBot = 0.25 * p0.level;
if (p0.flowBot < 0 && -p0.flowBot > 0.25 * p1.level)
p0.flowBot = -0.25 * p1.level;
}
function updateLevel(p0, p1) {
p0.level -= p0.flowBot;
p1.level += p0.flowBot;
}
function draw(p) {
var opc = Math.min(Math.abs(p.level) * 0.005, 1);
p.divFluid.css("opacity", opc);
p.divFluid.css("background", p.level > 0 ? "#07f" : "#f70");
var f = Math.abs(p.flowBot) * 0.5;
p.divFlow.css("width", f + "px");
p.divFlow.css("left", p.flowBot > 0 ? 50 : (50-f) + "px")
p.divFlow.css("background", p.flowBot > 0 ? "#7f0" :"#f7f");
}
function updateSource(p) {
var src = 0;
if ($("#cbSource").prop("checked")) {
src =...