6

I have to calculate the volume of an STL file, I successfully got the sizes of the model with

var box = new THREE.Box3().setFromObject( mesh );
var sizes = box.getSize();

but I just can't wrap my head around the concept of calculating it. I load the model with

var loader = new THREE.STLLoader();
loader.load(stlFileURL, function ( geometry ) {});

Can someone help me out and point me in the right direction? I'm doing it with javascript.

John
  • 143
  • 3
  • 11

3 Answers3

13

You can find it with the algorithm from my comment.

In the code snippet, the volume is computed without scaling.

Also, I've added a simple check that the algorithm calculates correctly by finding the volume of a hollow cylinder. As THREE.STLLoader() returns a non-indexed geometry, I've casted the geometry of the cylinder to non-indexed too.

Related forum topic

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.01, 1000);
camera.position.setScalar(20);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x404040);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var loader = new THREE.STLLoader();
loader.load('https://threejs.org/examples/models/stl/binary/pr2_head_pan.stl', function(geometry) {

  var mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
    color: 0xff00ff,
    wireframe: true
  }));
  mesh.rotation.set(-Math.PI / 2, 0, 0);
  mesh.scale.setScalar(100);
  scene.add(mesh);

  console.log("stl volume is " + getVolume(geometry));
});

// check with known volume:
var hollowCylinderGeom = new THREE.LatheBufferGeometry([
  new THREE.Vector2(1, 0),
  new THREE.Vector2(2, 0),
  new THREE.Vector2(2, 2),
  new THREE.Vector2(1, 2),
  new THREE.Vector2(1, 0)
], 90).toNonIndexed();
console.log("pre-computed volume of a hollow cylinder (PI * (R^2 - r^2) * h): " + Math.PI * (Math.pow(2, 2) - Math.pow(1, 2)) * 2);
console.log("computed volume of a hollow cylinder: " + getVolume(hollowCylinderGeom));


function getVolume(geometry) {

  let position = geometry.attributes.position;
  let faces = position.count / 3;
  let sum = 0;
  let p1 = new THREE.Vector3(),
    p2 = new THREE.Vector3(),
    p3 = new THREE.Vector3();
  for (let i = 0; i < faces; i++) {
    p1.fromBufferAttribute(position, i * 3 + 0);
    p2.fromBufferAttribute(position, i * 3 + 1);
    p3.fromBufferAttribute(position, i * 3 + 2);
    sum += signedVolumeOfTriangle(p1, p2, p3);
  }
  return sum;

}

function signedVolumeOfTriangle(p1, p2, p3) {
  return p1.dot(p2.cross(p3)) / 6.0;
}

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/loaders/STLLoader.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
prisoner849
  • 16,894
  • 4
  • 34
  • 68
  • This calculates the sum of the areas of the triangles? – manthrax Nov 26 '18 at 13:51
  • Whoa. Never mind. This is pretty slick. but only works for convex objects, yeah? – manthrax Nov 26 '18 at 13:52
  • 1
    @manthrax Works for those geometries that have no self-intersections/overlapping. – prisoner849 Nov 26 '18 at 13:56
  • so for 3d printing filament estimation, it would overestimate on objects with those features. Might be an acceptable tradeoff. But imagine printing a flowerpot.. the overestimation would be huuuge. – manthrax Nov 26 '18 at 14:06
  • @manthrax I've changed the answer and its code snippet a bit. Now there is a hollow cylinder instead of a boring cube :) Also added the output of both pre-calculated and calculated volumes of the cylinder. Have a look at the browser console. – prisoner849 Nov 26 '18 at 14:42
  • 1
    OK so.. the "signed" volume means the volume of interior facing triangles are subtracted from the total? So this works for any properly formed non manifold mesh? That's pretty dang clever! And presumably it doesn't matter what the origin is either.. i.e. could be far outside the model? – manthrax Nov 27 '18 at 06:58
  • 1
    @manthrax Yes, it's not mandatory for the model's geometry to be positioned in the center of coordinates, the algorithm will calculate its volume. – prisoner849 Nov 27 '18 at 09:07
  • frikken awesome. – manthrax Nov 27 '18 at 14:33
  • Is there a way to compute the volume of an animated mesh? It seems the formula only returns the rest position volume. – Minichua Nov 01 '21 at 15:37
  • @prisoner849 Your post on the three.js form works better! – Jacob Philpott Jan 31 '22 at 20:26
0

This is a pretty tricky problem. One way is to decompose the object into a bunch of convex polyhedra and sum the volumes of those...

Another way is to voxelize it, and add up the voxels on the inside to get an estimate whos accuracy is limited by the resolution of your voxelization.

Edit: prisoner849 has a rad solution!

manthrax
  • 4,918
  • 1
  • 17
  • 16
0

I'm also looking for a solution to this, And didn't have any implementation so far.

But extending from the voxelization idea like @manthrax mentioned.

I think we can voxelized into the octree structure.

If the cube still intersects with multiple triangles then voxelized deeper octree.

Until we reached the level of a single triangle cut through,
Then we calculate the volume of the cube using this method:

https://math.stackexchange.com/questions/454583/volume-of-cube-section-above-intersection-with-plane


After understood prisoner849's solution, This idea is no more valid compared to his solution.

kitta
  • 1,723
  • 3
  • 23
  • 33