Skip to content

Instantly share code, notes, and snippets.

@LeopoldTal
Last active December 15, 2019 21:49
Show Gist options
  • Save LeopoldTal/ceb164a1be41aca6c13e4afae254a671 to your computer and use it in GitHub Desktop.
Save LeopoldTal/ceb164a1be41aca6c13e4afae254a671 to your computer and use it in GitHub Desktop.
Making a swimming pool out of cheese
const DEFAULT_POOL_DIAMETER = 25; // m
const DEFAULT_POOL_DEPTH = 1.5; // m
// Cheese tensile strengths in kPa
// Sundaram Gunasekaran & M. Mehmet Ak
// _Cheese Rheology and Texture_ (2002)
// Table 3.2, p. 126
const CHEESES = {
'American cheese': 138,
'Appenzell': 22,
'Camembert, 15 days old': 1050,
'Camembert, 22 days old': 251,
'Cheddar': 242,
'Double Gloucester': 850,
'Edam': 290,
'Emmental': 182,
'Feta': 470,
'Gouda': 405,
'Gruyère': 77,
'Lancashire': 710,
'Leicester': 650,
'Mahon, fresh': 497,
'Mahon, aged': 2487,
'Mozzarella': 49,
'Münster': 6,
'Parmesan': 1980,
'Pecorino Romano': 2840,
'String cheese': 100
};
// Surface gravities in m/s^2
const GRAVITIES = {
Earth: 9.81,
Moon: 1.63,
Mercury: 3.7,
Venus: 8.87,
Mars: 3.72,
Jupiter: 24.79,
Saturn: 10.44,
Uranus: 8.69,
Neptune: 11.15,
Titan: 1.352,
Ceres: 0.28,
Pluto: 0.620,
Eris: 0.82,
Haumea: 0.401,
Makemake: 0.57,
Quaoar: 0.3,
Orcus: 0.2,
Sun: 274
};
// Densities in kg/L
const LIQUIDS = {
'water': 1,
'mud': 1.84,
'dry sand': 1.55,
'wet sand': 1.9,
'blood': 1.06,
'human fat': 0.9,
'pure alcohol': 0.785,
'wine (12.5°)': 0.973,
'rum (40°)': 0.914,
'olive oil': 0.8,
'molasses': 1.41,
'sulphuric acid': 1.84,
'bromine': 3.103,
'gallium (29.8°C)': 6.095,
'mercury': 13.5,
// random-packed spheres (packing ratio 62.5%)
'glass marbles': 1.6,
'ball bearings': 4.91,
'eyeballs': 0.625
};
const showNumber = n => (Math.round(100 * n) / 100).toString();
const initPoolDimensions = () => {
console.debug('Initialising pool size');
document.getElementById('pool-diameter').value = DEFAULT_POOL_DIAMETER;
document.getElementById('pool-depth').value = DEFAULT_POOL_DEPTH;
console.debug('Pool size init done.');
}
const initCheeseOptions = () => {
const cheeseNames = Object.keys(CHEESES);
console.debug(`Initialising ${cheeseNames.length} cheese options`);
const select = document.getElementById('cheese-type');
cheeseNames.sort();
cheeseNames.forEach(name => {
const option = document.createElement('option');
option.value = name;
option.innerText = name;
select.appendChild(option);
});
console.debug('Cheese options init done.');
};
const initLiquidOptions = () => {
const liquidNames = Object.keys(LIQUIDS);
console.debug(`Initialising ${liquidNames.length} pool contents options`);
const select = document.getElementById('liquid-type');
liquidNames.forEach(name => {
const option = document.createElement('option');
option.value = name;
option.innerText = name;
select.appendChild(option);
});
console.debug('Pool contents options init done.');
};
const initGravityOptions = () => {
const bodyNames = Object.keys(GRAVITIES);
console.debug(`Initialising ${bodyNames.length} gravity options`);
const select = document.getElementById('celestial-body');
bodyNames.forEach(name => {
const option = document.createElement('option');
option.value = name;
option.innerText = `${name} (${showNumber(GRAVITIES[name])}\u202fm/s²)`;
select.appendChild(option);
});
console.debug('Gravity options init done.');
};
const getWallThickness = ({
gravity,
density,
poolDiameter,
poolDepth,
tensileStrength
}) => (
gravity * density * poolDepth * poolDiameter / 2 / tensileStrength
);
const draw = (wallThickness, poolDiameter, poolDepth) => {
const totalPoolWidth = 2 * wallThickness + poolDiameter;
const drawingWidth = document.getElementById('graphic').getBoundingClientRect().width;
const getSize = n => `${
Math.floor(drawingWidth * n / totalPoolWidth)
}px`;
const wallThicknessInPx = getSize(wallThickness);
const poolDiameterInPx = getSize(poolDiameter);
const poolDepthInPx = getSize(poolDepth);
console.debug(`Drawing pool size ${totalPoolWidth}\u202fm on ${
drawingWidth}\u202fpx.`);
console.debug(`Walls: ${wallThickness}\u202f×\u202f${poolDepth}\u202fm → ${
wallThicknessInPx}\u202f×\u202f${poolDepthInPx}`);
console.debug(`Liquid: ${poolDiameter}\u202f×\u202f${poolDepth}\u202fm → ${
poolDiameterInPx}\u202f×\u202f${poolDepthInPx}`);
const walls = document.getElementsByClassName('graphic-wall');
walls[0].style.width = wallThicknessInPx;
walls[1].style.width = wallThicknessInPx;
walls[0].style.height = poolDepthInPx;
walls[1].style.height = poolDepthInPx;
const liquid = document.getElementsByClassName('graphic-liquid')[0];
liquid.style.width = poolDiameterInPx;
liquid.style.height = poolDepthInPx;
};
const compute = () => {
console.debug('Computation start');
const poolDiameter = parseFloat(document.getElementById('pool-diameter').value);
console.debug(`Input pool diameter: ${poolDiameter}\u202fm.`);
const poolDepth = parseFloat(document.getElementById('pool-depth').value);
console.debug(`Input pool depth: ${poolDepth}\u202fm.`);
const cheeseType = document.getElementById('cheese-type').value;
console.debug(`Selected cheese type: ${cheeseType}`);
const tensileStrength = CHEESES[cheeseType];
console.debug(`Input tensile strength: ${tensileStrength} kPa`);
const liquidType = document.getElementById('liquid-type').value;
console.debug(`Selected pool contents: ${liquidType}`);
const density = LIQUIDS[liquidType];
console.debug(`Input density: ${density} kg/L`);
const celestialBody = document.getElementById('celestial-body').value;
console.debug(`Selected celestial body: ${celestialBody}`);
const gravity = GRAVITIES[celestialBody];
console.debug(`Input gravity: ${gravity} m/s^2`);
const wallThickness = getWallThickness({
gravity,
density,
poolDiameter,
poolDepth,
tensileStrength
});
console.debug(`Output wall thickness: ${wallThickness} m`);
console.debug('Setting text display');
const outEl = document.getElementById('wall-thickness');
outEl.innerText = showNumber(wallThickness);
console.debug('Setting graphic display');
draw(wallThickness, poolDiameter, poolDepth);
console.debug('Computation done.');
};
const init = () => {
console.debug('Start init');
initPoolDimensions();
initCheeseOptions();
initLiquidOptions();
initGravityOptions();
document.getElementById('cheese-pool-form')
.addEventListener('change', compute);
window.addEventListener('resize', compute);
console.debug('Init done.');
};
init();
compute();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Making a swimming pool out of cheese</title>
<style>
h1 {
text-align: center;
font-family: sans-serif;
}
.graphic-wall,
.graphic-liquid {
display: inline-block;
margin: 0;
padding: 0;
}
.graphic-wall {
background: orange;
}
.graphic-liquid {
background: turquoise;
}
</style>
</head>
<body>
<h1>Making a swimming pool out of cheese</h1>
<noscript>You'll need Javascript to compute your cheese pool.</noscript>
<form id="cheese-pool-form" action="#">
<p>
Your pool is
<label for="pool-diameter">
<input
type="number"
name="pool-diameter" id="pool-diameter"
min="0.5" step="0.5"
/>&#8239;m wide
</label>
and
<label for="pool-depth">
<input
type="number"
name="pool-depth" id="pool-depth"
min="0.1" step="0.1"
/>&#8239;m deep
</label>.
</p>
<p>
<label for="cheese-type">The walls of your pool are made out of
<select name="cheese-type" id="cheese-type"></select>
</label>.
</p>
<p>
<label for="liquid-type">Your pool is full of
<select name="liquid-type" id="liquid-type"></select>
</label>.
</p>
<p>
<label for="celestial-body">Your pool is in
<select name="celestial-body" id="celestial-body"></select>
gravity.</label>
<small>
Note that the properties of cheese may change on other celestial bodies,
or in extreme Earth environments.
</small>
</p>
</form>
<p>
Your pool needs walls <strong id="wall-thickness">???</strong>&#8239;m thick.
</p>
<div id="graphic">
<div class="graphic-wall"></div><div class="graphic-liquid"></div><div class="graphic-wall"></div>
</div>
<script src="./cheese-pool.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment