From 90c30944807f4aabe5bdee18799b4e3a8bac8f81 Mon Sep 17 00:00:00 2001 From: Campbell Barton <ideasman42@gmail.com> Date: Mon, 6 May 2013 07:04:51 +0000 Subject: [PATCH] add scale to bounds, scale to volume - to the 3d toolbox --- object_print3d_utils/__init__.py | 3 + object_print3d_utils/mesh_helpers.py | 10 +++ object_print3d_utils/operators.py | 101 +++++++++++++++++++++++++-- object_print3d_utils/ui.py | 12 +++- 4 files changed, 119 insertions(+), 7 deletions(-) diff --git a/object_print3d_utils/__init__.py b/object_print3d_utils/__init__.py index fbaec5abe..7ba258a26 100644 --- a/object_print3d_utils/__init__.py +++ b/object_print3d_utils/__init__.py @@ -137,6 +137,9 @@ classes = ( operators.Print3DSelectReport, + operators.Print3DScaleToVolume, + operators.Print3DScaleToBounds, + operators.Print3DExport, Print3DSettings, diff --git a/object_print3d_utils/mesh_helpers.py b/object_print3d_utils/mesh_helpers.py index a9bd3c750..faf16d2e3 100644 --- a/object_print3d_utils/mesh_helpers.py +++ b/object_print3d_utils/mesh_helpers.py @@ -98,6 +98,16 @@ def bmesh_calc_volume(bm): 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): """ Calculate the surface area. diff --git a/object_print3d_utils/operators.py b/object_print3d_utils/operators.py index 76d2dc6e4..6e5a380ac 100644 --- a/object_print3d_utils/operators.py +++ b/object_print3d_utils/operators.py @@ -49,6 +49,7 @@ def clean_float(text): # --------- # Mesh Info + class Print3DInfoVolume(Operator): """Report the volume of the active mesh""" bl_idname = "mesh.print3d_info_volume" @@ -67,7 +68,7 @@ class Print3DInfoVolume(Operator): info = [] info.append(("Volume: %sÂł" % clean_float("%.4f" % volume), 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)) report.update(*info) @@ -139,7 +140,6 @@ class Print3DCheckSolid(Operator): return execute_check(self, context) - class Print3DCheckIntersections(Operator): """Check geometry for self intersections""" bl_idname = "mesh.print3d_check_intersect" @@ -236,7 +236,6 @@ class Print3DCheckThick(Operator): info.append(("Thin Faces: %d" % len(faces_error), (bmesh.types.BMFace, faces_error))) - def execute(self, context): return execute_check(self, context) @@ -461,7 +460,6 @@ class Print3DSelectReport(Operator): bmesh.types.BMFace: "faces", } - def execute(self, context): obj = context.edit_object info = report.info() @@ -488,6 +486,101 @@ class Print3DSelectReport(Operator): 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 diff --git a/object_print3d_utils/ui.py b/object_print3d_utils/ui.py index 9a141dd7b..84c3b3f74 100644 --- a/object_print3d_utils/ui.py +++ b/object_print3d_utils/ui.py @@ -71,9 +71,9 @@ class Print3DToolBar: row = layout.row() row.label("Statistics:") - col = layout.column(align=True) - col.operator("mesh.print3d_info_volume", text="Volume") - col.operator("mesh.print3d_info_area", text="Area") + rowsub = layout.row(align=True) + rowsub.operator("mesh.print3d_info_volume", text="Volume") + rowsub.operator("mesh.print3d_info_area", text="Area") row = layout.row() row.label("Checks:") @@ -108,6 +108,12 @@ class Print3DToolBar: # XXX TODO # 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() rowsub = col.row(align=True) rowsub.label("Export Path:") -- GitLab