Here is a function which works with horizontal cylinder, vertical and horizontal stadium and rectangular prism with round corners, so combined vertical and horizontal stadium, with round corners where radius of corners is less than half width or height. The first three shapes are special cases of the last one.
I have used the partial cylinder function from your node.
/**
* Calculates the volume of a partially filled tank which is a
* horizontal cylender, a horizontal stadium or a vertical stadium
* or a rectangular prism with rounded edges along the length
*
* Given msg.payload containing and object containing the properties
* length, width, height, optionally cornerRadius, and depth (of fluid)
* If cornerRadius is null, 0 or not supplied then the tank is assumed to be cylindrical, or horizontal or vertical stadium
* If width == height then the tank is cylindrical
* If the radius is supplied then it is a rectangular prism with rounded corners.
*
* On return msg.payload contains the volume in cubic units of whatever the dimensions are in
*/
msg.payload = getPartialVolumeMultiShape( msg.payload.length, msg.payload.width, msg.payload.height,
msg.payload.radius, msg.payload.depth)
return msg
function getPartialVolumeMultiShape(length, width, height, radius, depth) {
// calculate radius if not supplied or zero
if (!radius) {
radius = Math.min(width, height)/2
//node.warn(`Radius: ${radius}`)
}
// calculate depths in rounded sections at the top and bottom, and in full width rectangular section
let roundDepth
let rectDepth
if (depth < radius) {
roundDepth = depth
rectDepth= 0
} else if (depth <= height - radius) {
roundDepth = radius
rectDepth = depth - radius
} else {
// fluid up into the top rounded section
roundDepth = depth - (height - 2*radius)
rectDepth = height - 2*radius
}
//node.warn(`roundDepth: ${roundDepth}, rectDepth: ${rectDepth}`)
const roundVolume = getPartialVolumeHorizonalCylinder(radius, length, roundDepth) + (width - 2*radius) * roundDepth * length
const rectVolume = width * rectDepth * length
//node.warn(`roundVolume: ${roundVolume}, rectVolume: ${rectVolume}`)
return roundVolume + rectVolume
}
function getPartialVolumeHorizonalCylinder(radius, length, fluidHeight) {
if (radius == undefined) throw "The diameter of the horizontal cylinder is undefined";
if (length == undefined) throw "The length of the horizontal cylinder is undefined";
if (fluidHeight == undefined) throw "The fill level of the horizontal cylinder is undefined";
var angle = 2 * Math.acos((radius - fluidHeight) / radius); // See θ
return 0.5 * Math.pow(radius, 2) * (angle - Math.sin(angle)) * length;
}
Test flow:
[{"id":"669c9dd973dff1e9","type":"function","z":"bdd7be38.d3b55","name":"Volume","func":"/**\n * Calculates the volume of a partially filled tank which is a \n * horizontal cylender, a horizontal stadium or a vertical stadium\n * or a rectangular prism with rounded edges along the length\n * \n * Given msg.payload containing and object containing the properties\n * length, width, height, optionally cornerRadius, and depth (of fluid)\n * If cornerRadius is null, 0 or not supplied then the tank is assumed to be cylindrical, or horizontal or vertical stadium\n * If width == height then the tank is cylindrical\n * If the radius is supplied then it is a rectangular prism with rounded corners.\n * \n * On return msg.payload contains the volume in cubic units of whatever the dimensions are in\n*/\nmsg.payload = getPartialVolumeMultiShape( msg.payload.length, msg.payload.width, msg.payload.height,\n msg.payload.radius, msg.payload.depth)\nreturn msg \n\n\nfunction getPartialVolumeMultiShape(length, width, height, radius, depth) {\n // calculate radius if not supplied or zero\n if (!radius) {\n radius = Math.min(width, height)/2\n //node.warn(`Radius: ${radius}`)\n }\n // calculate depths in rounded sections at the top and bottom, and in full width rectangular section\n let roundDepth\n let rectDepth\n if (depth < radius) {\n roundDepth = depth\n rectDepth= 0\n } else if (depth <= height - radius) {\n roundDepth = radius\n rectDepth = depth - radius\n } else {\n // fluid up into the top rounded section\n roundDepth = depth - (height - 2*radius)\n rectDepth = height - 2*radius\n }\n //node.warn(`roundDepth: ${roundDepth}, rectDepth: ${rectDepth}`)\n const roundVolume = getPartialVolumeHorizonalCylinder(radius, length, roundDepth) + (width - 2*radius) * roundDepth * length\n const rectVolume = width * rectDepth * length\n //node.warn(`roundVolume: ${roundVolume}, rectVolume: ${rectVolume}`)\n return roundVolume + rectVolume\n}\n\nfunction getPartialVolumeHorizonalCylinder(radius, length, fluidHeight) {\n if (radius == undefined) throw \"The diameter of the horizontal cylinder is undefined\";\n if (length == undefined) throw \"The length of the horizontal cylinder is undefined\";\n if (fluidHeight == undefined) throw \"The fill level of the horizontal cylinder is undefined\";\n\n var angle = 2 * Math.acos((radius - fluidHeight) / radius); // See θ\n return 0.5 * Math.pow(radius, 2) * (angle - Math.sin(angle)) * length;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":4260,"wires":[["bc3f542a653bd575"]]},{"id":"cfb009d142dffc93","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\": 200, \"width\": 200, \"length\": 500, \"depth\": 200}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\": 200, \"width\": 200, \"length\": 500, \"depth\": 200}","payloadType":"json","x":240,"y":4320,"wires":[["669c9dd973dff1e9","5e1d7493c1352c52"]]},{"id":"bc3f542a653bd575","type":"debug","z":"bdd7be38.d3b55","name":"FUNCTION","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":690,"y":4260,"wires":[]},{"id":"ec98ef0aa15ccb83","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\":300,\"width\":200,\"length\":500,\"depth\":300}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\":300,\"width\":200,\"length\":500,\"depth\":300}","payloadType":"json","x":230,"y":4560,"wires":[["669c9dd973dff1e9","8358a8c900581272"]]},{"id":"1e56c0901a028ab3","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\": 200, \"width\": 200, \"length\": 500, \"depth\": 100}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\": 200, \"width\": 200, \"length\": 500, \"depth\": 100}","payloadType":"json","x":240,"y":4360,"wires":[["669c9dd973dff1e9","5e1d7493c1352c52"]]},{"id":"86b3e3a7d5733958","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\":200,\"width\":300,\"length\":500,\"depth\":200}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\":200,\"width\":300,\"length\": 500,\"depth\":200}","payloadType":"json","x":230,"y":4440,"wires":[["669c9dd973dff1e9","3d081ee8c1bddd34"]]},{"id":"6dc4bd2072ada370","type":"tank-volume","z":"bdd7be38.d3b55","name":"","tankType":"horiz_cylin","inputField":"payload","outputField":"payload","measurement":"fluid","inputUnit1":"cm","inputUnit2":"l","outputUnit":"cm3","topLimit":0,"bottomLimit":0,"diameter":"200","length":"500","width":"100","height":"500","length2":0,"width2":0,"height2":0,"coneHeight":0,"cylinderHeight":0,"diameterTop":0,"diameterBottom":0,"customTable":[],"x":610,"y":4380,"wires":[["8af0df3473e2c1f2"]]},{"id":"5e1d7493c1352c52","type":"change","z":"bdd7be38.d3b55","name":"","rules":[{"t":"move","p":"payload.depth","pt":"msg","to":"payload.measuredHeight","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":4340,"wires":[["6dc4bd2072ada370"]]},{"id":"8af0df3473e2c1f2","type":"debug","z":"bdd7be38.d3b55","name":"CONTRIB","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.filledVolume","targetType":"msg","statusVal":"","statusType":"auto","x":820,"y":4380,"wires":[]},{"id":"3d081ee8c1bddd34","type":"change","z":"bdd7be38.d3b55","name":"","rules":[{"t":"move","p":"payload.depth","pt":"msg","to":"payload.measuredHeight","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":4460,"wires":[["6998747a59900869"]]},{"id":"6998747a59900869","type":"tank-volume","z":"bdd7be38.d3b55","name":"","tankType":"horiz_stad","inputField":"payload","outputField":"payload","measurement":"fluid","inputUnit1":"cm","inputUnit2":"l","outputUnit":"cm3","topLimit":0,"bottomLimit":0,"diameter":"200","length":"500","width":"300","height":"200","length2":0,"width2":0,"height2":0,"coneHeight":0,"cylinderHeight":0,"diameterTop":0,"diameterBottom":0,"customTable":[],"x":610,"y":4500,"wires":[["8af0df3473e2c1f2"]]},{"id":"b288ca2ca5a63ed7","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\":200,\"width\":300\"length\":500,\"depth\":100}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\":200,\"width\":300,\"length\":500,\"depth\":100}","payloadType":"json","x":220,"y":4480,"wires":[["669c9dd973dff1e9","3d081ee8c1bddd34"]]},{"id":"b47125dbe93c2686","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\":300,\"width\":200,\"length\":500,\"depth\":75}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\":300,\"width\":200,\"length\":500,\"depth\":75}","payloadType":"json","x":220,"y":4640,"wires":[["669c9dd973dff1e9","8358a8c900581272"]]},{"id":"5c5514738de5bb52","type":"tank-volume","z":"bdd7be38.d3b55","name":"","tankType":"vert_stad","inputField":"payload","outputField":"payload","measurement":"fluid","inputUnit1":"cm","inputUnit2":"l","outputUnit":"cm3","topLimit":0,"bottomLimit":0,"diameter":"200","length":"500","width":"200","height":"300","length2":0,"width2":0,"height2":0,"coneHeight":0,"cylinderHeight":0,"diameterTop":0,"diameterBottom":0,"customTable":[],"x":620,"y":4620,"wires":[["8af0df3473e2c1f2"]]},{"id":"8358a8c900581272","type":"change","z":"bdd7be38.d3b55","name":"","rules":[{"t":"move","p":"payload.depth","pt":"msg","to":"payload.measuredHeight","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":570,"y":4580,"wires":[["5c5514738de5bb52"]]},{"id":"f85444c64dd07b07","type":"inject","z":"bdd7be38.d3b55","name":"{\"height\":300,\"width\":200,\"length\":500,\"depth\":250}","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"height\":300,\"width\":200,\"length\":500,\"depth\":250}","payloadType":"json","x":230,"y":4600,"wires":[["8358a8c900581272","669c9dd973dff1e9"]]}]