When printing a three-dimensional object in plastic or metal, a seemingly innocent question might pop up once we create our first toy based on a mesh we created; what is its center of mass? If our model has legs but we don't want it to keel over, its center of mass better be somewhere over its feet and, preferably, as low as possible to keep it stable. This figure shows this schematically:
Once we know how to determine the volume of a mesh we can reuse many of the concepts to devise a script to determine the center of mass. Two additional bits of knowledge are needed to compute the position of the center of mass:
All of this assumes that solid sections of our mesh have a uniform density. A mesh may have any form or even be hollow but the solid parts are assumed to be of a uniform density. This is valid assumption for the materials deposited by 3D printers.
The first issue is a bit of geometry: the projected volume is essentially a triangular column (or triangular prism) capped by a possibly slanted triangular face. Calculating the center of mass might be done as follows: the x and y coordinates of the center of mass are the x and y coordinates of the center of the projected triangle on the xy-plane—those are simply the averages of the x and y coordinates respectively of the three points defining the triangular face. The z-coordinate of the center of mass is halfway along the average height of our projected column. This is the average of the z-coordinates of the three points of the triangular face divided by two.
The second issue is mainly common sense: given two masses m1 and m2 with their centers of mass at v1 and v2 respectively, their combined center of mass is the weighted average. That is to say, the center of mass is proportionally closer to the center of the mass of the heaviest component.
Of course it is common sense to us now, but it took someone like Archimedes to see that it actually was common sense. After finding out about this 'law of levers' (as he called it), he didn't shout 'eureka' or went running around naked, so it took somewhat longer to attract attention.
Let's put all this information into a recipe that we can follow:
From the outline above, it is clear that calculating the center of mass goes hand in hand with the calculation of the partial volumes, so it makes sense to redefine the meshvolume()
function to the following:
def meshvolume(me): volume = 0.0 cm = vec((0,0,0)) for f in me.faces: xy_area = Mathutils.TriangleArea(vec(f.v[0].co[:2]), vec(f.v[1].co[:2]),vec(f.v[2].co[:2])) Nz = f.no[2] avg_z = sum([f.v[i].co[2] for i in range(3)])/3.0 partial_volume = avg_z * xy_area if Nz < 0: volume -= partial_volume if Nz > 0: volume += partial_volume avg_x = sum([f.v[i].co[0] for i in range(3)])/3.0 avg_y = sum([f.v[i].co[1] for i in range(3)])/3.0 centroid = vec((avg_x,avg_y,avg_z/2)) if Nz < 0: cm -= partial_volume * centroid if Nz > 0: cm += partial_volume * centroid return volume,cm/volume
The added or changed lines of code are highlighted.
Although most of us are artists and not engineers, we still may ask how accurate the number is that we calculate for our mesh volume or center of mass. There are two things to consider—intrinsic accuracy and computational accuracy of our algorithm.
Intrinsic accuracy is what we refer to when we consider the fact that our model is made out of small polygons that approximate some imagined shape. When doing organic modeling this hardly matters; if our model looks good, it is good. However, if we try to approximate some ideal form, for example a sphere, by a polygonal model (a uv-sphere say, or an icosphere) there will be a difference between the calculated volume and the known volume of the ideal sphere. We can improve this approximation by increasing the number of subdivisions (or equivalent the size of the polygons) but we will never be able to completely eliminate this difference and the algorithm used to calculate the volume cannot change that.
Computational accuracy has several aspects. First, there is the precision of the numbers we calculate with. On most platforms that Blender runs on, calculations are performed using double precision floating point numbers. This amounts to about 17 digits of precision and there is nothing we can do to improve that. Luckily, that is ample precision to work with.
Then there is the accuracy of our algorithm. When you look at the code you will see that we are adding and multiplying a potentially huge amount of values, as a typical high-resolution model may well contain over a hundred thousand faces or even a million. For each face we calculate the volume of the projected column and all of these volumes are added (or subtracted) together. The problem is that these volumes may differ considerably in size, not only because the areas of the faces may differ but especially because the projected area of a near vertical face is very small compared to a near horizontal one.
Now if we add a very large and a very small number with limited precision calculations we will lose the small number. For example, if our precision would be limited to three significant digits, adding 0.001 and 0.0001 would end up as 0.001, losing the effect of the small number. Now our precision is a lot better (about 17 digits) but we add a lot more than two numbers. If we implement the volume()
function by using one of the cited algorithms however, the difference never adds up to more than one in million, so as long as we don't aim to do nuclear science with Blender there is no need to bother. (For those who do, an alternative is provided in the script as the function volume2()
. Still, be careful that you know what you are doing).
Python is able to work with numbers of potentially infinite size and precision but this is much slower than doing normal floating point calculations. The functions and classes provided in Mathutils
are primarily coded in C for speed and limited to double precision floats. See http://code.activestate.com/recipes/393090/ http://code.activestate.com/recipes/298339/ or Section 18.5 of Python Cookbook, 2nd edition, by O'Reilly for some other techniques and mathematical background.
3.144.222.185