Changeset View
Changeset View
Standalone View
Standalone View
object_print3d_utils/operators.py
| Show All 17 Lines | |||||
| # <pep8-80 compliant> | # <pep8-80 compliant> | ||||
| # All Operator | # All Operator | ||||
| import bpy | import bpy | ||||
| from bpy.types import Operator | from bpy.types import Operator | ||||
| from bpy.props import ( | from bpy.props import ( | ||||
| IntProperty, | IntProperty, | ||||
| FloatProperty, | FloatProperty, | ||||
| ) | ) | ||||
| import bmesh | import bmesh | ||||
| from . import ( | from . import ( | ||||
| mesh_helpers, | mesh_helpers, | ||||
| report, | report, | ||||
| ) | ) | ||||
| def clean_float(text): | def clean_float(text): | ||||
| # strip trailing zeros: 0.000 -> 0.0 | # strip trailing zeros: 0.000 -> 0.0 | ||||
| index = text.rfind(".") | index = text.rfind(".") | ||||
| if index != -1: | if index != -1: | ||||
| index += 2 | index += 2 | ||||
| head, tail = text[:index], text[index:] | head, tail = text[:index], text[index:] | ||||
| ▲ Show 20 Lines • Show All 382 Lines • ▼ Show 20 Lines | |||||
| class MESH_OT_Print3D_Clean_Non_Manifold(Operator): | class MESH_OT_Print3D_Clean_Non_Manifold(Operator): | ||||
| """Cleanup problems, like holes, non-manifold vertices, and inverted normals""" | """Cleanup problems, like holes, non-manifold vertices, and inverted normals""" | ||||
| bl_idname = "mesh.print3d_clean_non_manifold" | bl_idname = "mesh.print3d_clean_non_manifold" | ||||
| bl_label = "Print3D Clean Non-Manifold and Inverted" | bl_label = "Print3D Clean Non-Manifold and Inverted" | ||||
| bl_options = {'REGISTER', 'UNDO'} | bl_options = {'REGISTER', 'UNDO'} | ||||
| threshold = bpy.props.FloatProperty( | threshold: bpy.props.FloatProperty( | ||||
| name="threshold", | name="threshold", | ||||
| description="Minimum distance between elements to merge", | description="Minimum distance between elements to merge", | ||||
| default=0.0001, | default=0.0001, | ||||
| ) | ) | ||||
| sides = bpy.props.IntProperty( | sides: bpy.props.IntProperty( | ||||
| name="sides", | name="sides", | ||||
| description="Number of sides in hole required to fill", | description="Number of sides in hole required to fill", | ||||
| default=4, | default=4, | ||||
| ) | ) | ||||
| def execute(self, context): | def execute(self, context): | ||||
| self.context = context | self.context = context | ||||
| mode_orig = context.mode | mode_orig = context.mode | ||||
| self.setup_environment() | self.setup_environment() | ||||
| bm_key_orig = self.elem_count(context) | bm_key_orig = self.elem_count(context) | ||||
| ▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | |||||
| # ... helper function for info UI | # ... helper function for info UI | ||||
| class MESH_OT_Print3D_Select_Report(Operator): | class MESH_OT_Print3D_Select_Report(Operator): | ||||
| """Select the data associated with this report""" | """Select the data associated with this report""" | ||||
| bl_idname = "mesh.print3d_select_report" | bl_idname = "mesh.print3d_select_report" | ||||
| bl_label = "Print3D Select Report" | bl_label = "Print3D Select Report" | ||||
| bl_options = {'INTERNAL'} | bl_options = {'INTERNAL'} | ||||
| index = IntProperty() | index: IntProperty() | ||||
| _type_to_mode = { | _type_to_mode = { | ||||
| bmesh.types.BMVert: 'VERT', | bmesh.types.BMVert: 'VERT', | ||||
| bmesh.types.BMEdge: 'EDGE', | bmesh.types.BMEdge: 'EDGE', | ||||
| bmesh.types.BMFace: 'FACE', | bmesh.types.BMFace: 'FACE', | ||||
| } | } | ||||
| _type_to_attr = { | _type_to_attr = { | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| class MESH_OT_Print3D_Scale_To_Volume(Operator): | class MESH_OT_Print3D_Scale_To_Volume(Operator): | ||||
| """Scale edit-mesh or selected-objects to a set volume""" | """Scale edit-mesh or selected-objects to a set volume""" | ||||
| bl_idname = "mesh.print3d_scale_to_volume" | bl_idname = "mesh.print3d_scale_to_volume" | ||||
| bl_label = "Scale to Volume" | bl_label = "Scale to Volume" | ||||
| bl_options = {'REGISTER', 'UNDO'} | bl_options = {'REGISTER', 'UNDO'} | ||||
| volume_init = FloatProperty( | volume_init: FloatProperty( | ||||
| options={'HIDDEN'}, | options={'HIDDEN'}, | ||||
| ) | ) | ||||
| volume = FloatProperty( | volume: FloatProperty( | ||||
| name="Volume", | name="Volume", | ||||
| unit='VOLUME', | unit='VOLUME', | ||||
| min=0.0, max=100000.0, | min=0.0, max=100000.0, | ||||
| ) | ) | ||||
| def execute(self, context): | def execute(self, context): | ||||
| import math | import math | ||||
| scale = math.pow(self.volume, 1 / 3) / math.pow(self.volume_init, 1 / 3) | scale = math.pow(self.volume, 1 / 3) / math.pow(self.volume_init, 1 / 3) | ||||
| self.report({'INFO'}, "Scaled by %s" % clean_float("%.6f" % scale)) | self.report({'INFO'}, "Scaled by %s" % clean_float("%.6f" % scale)) | ||||
| _scale(scale, self.report) | _scale(scale, self.report) | ||||
| return {'FINISHED'} | return {'FINISHED'} | ||||
| Show All 22 Lines | |||||
| class MESH_OT_Print3D_Scale_To_Bounds(Operator): | class MESH_OT_Print3D_Scale_To_Bounds(Operator): | ||||
| """Scale edit-mesh or selected-objects to fit within a maximum length""" | """Scale edit-mesh or selected-objects to fit within a maximum length""" | ||||
| bl_idname = "mesh.print3d_scale_to_bounds" | bl_idname = "mesh.print3d_scale_to_bounds" | ||||
| bl_label = "Scale to Bounds" | bl_label = "Scale to Bounds" | ||||
| bl_options = {'REGISTER', 'UNDO'} | bl_options = {'REGISTER', 'UNDO'} | ||||
| length_init = FloatProperty( | length_init: FloatProperty( | ||||
| options={'HIDDEN'}, | options={'HIDDEN'}, | ||||
| ) | ) | ||||
| axis_init = IntProperty( | axis_init: IntProperty( | ||||
| options={'HIDDEN'}, | options={'HIDDEN'}, | ||||
| ) | ) | ||||
| length = FloatProperty( | length: FloatProperty( | ||||
| name="Length Limit", | name="Length Limit", | ||||
| unit='LENGTH', | unit='LENGTH', | ||||
| min=0.0, max=100000.0, | min=0.0, max=100000.0, | ||||
| ) | ) | ||||
| def execute(self, context): | def execute(self, context): | ||||
| scale = self.length / self.length_init | scale = self.length / self.length_init | ||||
| _scale(scale, | _scale(scale, | ||||
| report=self.report, | report=self.report, | ||||
| report_suffix=", Clamping %s-Axis" % "XYZ"[self.axis_init]) | report_suffix=", Clamping %s-Axis" % "XYZ"[self.axis_init]) | ||||
| return {'FINISHED'} | return {'FINISHED'} | ||||
| def invoke(self, context, event): | def invoke(self, context, event): | ||||
| from mathutils import Vector | from mathutils import Vector | ||||
| def calc_length(vecs): | def calc_length(vecs): | ||||
| return max(((max(v[i] for v in vecs) - min(v[i] for v in vecs)), i) for i in range(3)) | return max(((max(v[i] for v in vecs) - min(v[i] for v in vecs)), i) for i in range(3)) | ||||
| if context.mode == 'EDIT_MESH': | if context.mode == 'EDIT_MESH': | ||||
| length, axis = calc_length([Vector(v) * obj.matrix_world | length, axis = calc_length([Vector(v) @ obj.matrix_world | ||||
| for obj in [context.edit_object] | for obj in [context.edit_object] | ||||
| for v in obj.bound_box]) | for v in obj.bound_box]) | ||||
| else: | else: | ||||
| length, axis = calc_length([Vector(v) * obj.matrix_world | length, axis = calc_length([Vector(v) @ obj.matrix_world | ||||
| for obj in context.selected_editable_objects | for obj in context.selected_editable_objects | ||||
| if obj.type == 'MESH' for v in obj.bound_box]) | if obj.type == 'MESH' for v in obj.bound_box]) | ||||
| if length == 0.0: | if length == 0.0: | ||||
| self.report({'WARNING'}, "Object has zero bounds") | self.report({'WARNING'}, "Object has zero bounds") | ||||
| return {'CANCELLED'} | return {'CANCELLED'} | ||||
| self.length_init = self.length = length | self.length_init = self.length = length | ||||
| Show All 25 Lines | |||||