The 3D print toolbox currently only outputs the volume/area of all faces.
How can I get the volume of selected mesh objects, ignoring certain faces?
Asking on behalf of a user who mailed me.
The 3D print toolbox currently only outputs the volume/area of all faces.
How can I get the volume of selected mesh objects, ignoring certain faces?
Asking on behalf of a user who mailed me.
This can be done using the Python API to get the mesh with modifiers applied, then applying the transform matrix.
The following script applies to all selected objects, showing a popup with the final volume. Not that it does not use units or scene scale.
See is_face_volume for the method of checking if a face should be included in volume calculations.
import bpy
from bpy import context
Quick way to test with/without hidden faces
USE_FILTER_FACES = True
def report_info(title="", message=""):
# show in console
print(title, message)
# show in popup
def draw_cb(self, context):
self.layout.label(text=message)
context.window_manager.popup_menu(draw_func=draw_cb, title=title, icon='INFO')
def is_face_skip(f):
"""Ignore faces that pass this test!"""
return f.hide is False
# You may want to filter based on material.
# return f.material_index == 0
def bmesh_from_object_final(ob):
import bmesh
matrix = ob.matrix_world
me = ob.to_mesh()
me.transform(matrix)
bm = bmesh.new()
bm.from_mesh(me)
if USE_FILTER_FACES:
faces_remove = [f for f in bm.faces if not is_face_skip(f)]
for f in faces_remove:
bm.faces.remove(f)
return (bm, matrix.is_negative)
def volume_and_area_from_object(ob):
bm, is_negative = bmesh_from_object_final(ob)
volume = bm.calc_volume(signed=True)
area = sum(f.calc_area() for f in bm.faces)
bm.free()
if is_negative:
volume = -volume
return volume, area
def main():
volume = 0.0
area = 0.0
object_count = 0
for ob in context.selected_objects:
if ob.type != 'MESH':
continue
volume_single, area_single = volume_and_area_from_object(ob)
volume += volume_single
area += area_single
object_count += 1
volume = abs(volume)
report_info(
title="From %d object(s)" % object_count,
message="Volume: %.4f, Area: %.4f" % (volume, area),
)
if name == "main":
main()