Skip to content
Snippets Groups Projects
Commit 90c30944 authored by Campbell Barton's avatar Campbell Barton
Browse files

add scale to bounds, scale to volume - to the 3d toolbox

parent f18b4f55
No related branches found
No related tags found
No related merge requests found
...@@ -137,6 +137,9 @@ classes = ( ...@@ -137,6 +137,9 @@ classes = (
operators.Print3DSelectReport, operators.Print3DSelectReport,
operators.Print3DScaleToVolume,
operators.Print3DScaleToBounds,
operators.Print3DExport, operators.Print3DExport,
Print3DSettings, Print3DSettings,
......
...@@ -98,6 +98,16 @@ def bmesh_calc_volume(bm): ...@@ -98,6 +98,16 @@ def bmesh_calc_volume(bm):
for f in bm.faces))) for f in bm.faces)))
def bmesh_calc_volume_signed(bm):
"""
Calculate the volume of a triangulated bmesh.
"""
def tri_signed_volume(p1, p2, p3):
return p1.dot(p2.cross(p3)) / 6.0
return sum((tri_signed_volume(*(v.co for v in f.verts))
for f in bm.faces))
def bmesh_calc_area(bm): def bmesh_calc_area(bm):
""" """
Calculate the surface area. Calculate the surface area.
......
...@@ -49,6 +49,7 @@ def clean_float(text): ...@@ -49,6 +49,7 @@ def clean_float(text):
# --------- # ---------
# Mesh Info # Mesh Info
class Print3DInfoVolume(Operator): class Print3DInfoVolume(Operator):
"""Report the volume of the active mesh""" """Report the volume of the active mesh"""
bl_idname = "mesh.print3d_info_volume" bl_idname = "mesh.print3d_info_volume"
...@@ -67,7 +68,7 @@ class Print3DInfoVolume(Operator): ...@@ -67,7 +68,7 @@ class Print3DInfoVolume(Operator):
info = [] info = []
info.append(("Volume: %s³" % clean_float("%.4f" % volume), info.append(("Volume: %s³" % clean_float("%.4f" % volume),
None)) None))
info.append(("%s cm³" % clean_float("%.4f" % ((volume * (scale * scale * scale)) / (0.01 * 0.01 * 0.01) )), info.append(("%s cm³" % clean_float("%.4f" % ((volume * (scale * scale * scale)) / (0.01 * 0.01 * 0.01))),
None)) None))
report.update(*info) report.update(*info)
...@@ -139,7 +140,6 @@ class Print3DCheckSolid(Operator): ...@@ -139,7 +140,6 @@ class Print3DCheckSolid(Operator):
return execute_check(self, context) return execute_check(self, context)
class Print3DCheckIntersections(Operator): class Print3DCheckIntersections(Operator):
"""Check geometry for self intersections""" """Check geometry for self intersections"""
bl_idname = "mesh.print3d_check_intersect" bl_idname = "mesh.print3d_check_intersect"
...@@ -236,7 +236,6 @@ class Print3DCheckThick(Operator): ...@@ -236,7 +236,6 @@ class Print3DCheckThick(Operator):
info.append(("Thin Faces: %d" % len(faces_error), info.append(("Thin Faces: %d" % len(faces_error),
(bmesh.types.BMFace, faces_error))) (bmesh.types.BMFace, faces_error)))
def execute(self, context): def execute(self, context):
return execute_check(self, context) return execute_check(self, context)
...@@ -461,7 +460,6 @@ class Print3DSelectReport(Operator): ...@@ -461,7 +460,6 @@ class Print3DSelectReport(Operator):
bmesh.types.BMFace: "faces", bmesh.types.BMFace: "faces",
} }
def execute(self, context): def execute(self, context):
obj = context.edit_object obj = context.edit_object
info = report.info() info = report.info()
...@@ -488,6 +486,101 @@ class Print3DSelectReport(Operator): ...@@ -488,6 +486,101 @@ class Print3DSelectReport(Operator):
return {'FINISHED'} return {'FINISHED'}
# -----------
# Scale to...
def _scale(scale, report=None):
if scale != 1.0:
bpy.ops.transform.resize(value=(scale,) * 3,
mirror=False, proportional='DISABLED',
snap=False,
texture_space=False)
if report is not None:
report({'INFO'}, "Scaled by %s" % clean_float("%.6f" % scale))
class Print3DScaleToVolume(Operator):
"""Scale edit-mesh or selected-objects to a set volume"""
bl_idname = "mesh.print3d_scale_to_volume"
bl_label = "Scale to Volume"
bl_options = {'REGISTER', 'UNDO'}
volume_init = FloatProperty(
options={'HIDDEN'},
)
volume = FloatProperty(
name="Volume",
unit='VOLUME',
min=0.0, max=100000.0,
)
def execute(self, context):
import math
scale = math.pow(self.volume, 1 / 3) / math.pow(self.volume_init, 1 / 3)
self.report({'INFO'}, "Scaled by %s" % clean_float("%.6f" % scale))
_scale(scale, self.report)
return {'FINISHED'}
def invoke(self, context, event):
def calc_volume(obj):
bm = mesh_helpers.bmesh_copy_from_object(obj, apply_modifiers=True)
volume = mesh_helpers.bmesh_calc_volume_signed(bm)
bm.free()
return volume
if context.mode == 'EDIT_MESH':
volume = calc_volume(context.edit_object)
else:
volume = sum(calc_volume(obj) for obj in context.selected_editable_objects
if obj.type == 'MESH')
self.volume_init = self.volume = abs(volume)
wm = context.window_manager
return wm.invoke_props_dialog(self)
class Print3DScaleToBounds(Operator):
"""Scale edit-mesh or selected-objects to fit within a maximum length"""
bl_idname = "mesh.print3d_scale_to_bounds"
bl_label = "Scale to Bounds"
bl_options = {'REGISTER', 'UNDO'}
length_init = FloatProperty(
options={'HIDDEN'},
)
length = FloatProperty(
name="Length Limit",
unit='LENGTH',
min=0.0, max=100000.0,
)
def execute(self, context):
scale = self.length / self.length_init
_scale(scale, self.report)
return {'FINISHED'}
def invoke(self, context, event):
from mathutils import Vector
def calc_length(vecs):
return max((max(v[i] for v in vecs) - min(v[i] for v in vecs)) for i in range(3))
if context.mode == 'EDIT_MESH':
length = calc_length([Vector(v) * obj.matrix_world
for v in context.edit_object.bound_box])
else:
length = calc_length([Vector(v) * obj.matrix_world
for obj in context.selected_editable_objects
if obj.type == 'MESH' for v in obj.bound_box])
self.length_init = self.length = length
wm = context.window_manager
return wm.invoke_props_dialog(self)
# ------ # ------
# Export # Export
......
...@@ -71,9 +71,9 @@ class Print3DToolBar: ...@@ -71,9 +71,9 @@ class Print3DToolBar:
row = layout.row() row = layout.row()
row.label("Statistics:") row.label("Statistics:")
col = layout.column(align=True) rowsub = layout.row(align=True)
col.operator("mesh.print3d_info_volume", text="Volume") rowsub.operator("mesh.print3d_info_volume", text="Volume")
col.operator("mesh.print3d_info_area", text="Area") rowsub.operator("mesh.print3d_info_area", text="Area")
row = layout.row() row = layout.row()
row.label("Checks:") row.label("Checks:")
...@@ -108,6 +108,12 @@ class Print3DToolBar: ...@@ -108,6 +108,12 @@ class Print3DToolBar:
# XXX TODO # XXX TODO
# col.operator("mesh.print3d_clean_thin", text="Wall Thickness") # col.operator("mesh.print3d_clean_thin", text="Wall Thickness")
row = layout.row()
row.label("Scale To:")
rowsub = layout.row(align=True)
rowsub.operator("mesh.print3d_scale_to_volume", text="Volume")
rowsub.operator("mesh.print3d_scale_to_bounds", text="Bounds")
col = layout.column() col = layout.column()
rowsub = col.row(align=True) rowsub = col.row(align=True)
rowsub.label("Export Path:") rowsub.label("Export Path:")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment