From 4585823c4093102c3df0d93f99f79fe104902012 Mon Sep 17 00:00:00 2001 From: Tristan Strathearn Date: Fri, 28 Jan 2022 19:33:14 +1000 Subject: [PATCH] feat: split offset and thickness modifiers from bolt operator in favour of solidy operator usage, add ring functionality to bolt operator, rename bolt to ring_and_bolt --- __init__.py | 8 +-- menu.py | 2 +- bolt.py => ring_and_bolt.py | 138 +++++++++++------------------------- solidify.py | 58 +++++++++++---- ui_panel.py | 2 +- 5 files changed, 91 insertions(+), 117 deletions(-) rename bolt.py => ring_and_bolt.py (55%) diff --git a/__init__.py b/__init__.py index fa4e933..fdd9879 100644 --- a/__init__.py +++ b/__init__.py @@ -14,7 +14,7 @@ from . overlay import unregister_draw_handler from . import overlay from . import utils -from . import bolt +from . import ring_and_bolt from . import weighted_normal_bevel from . import vertex_bevel from . import face_sketch @@ -29,7 +29,7 @@ def register(): importlib.reload(overlay) importlib.reload(utils) - importlib.reload(bolt) + importlib.reload(ring_and_bolt) importlib.reload(weighted_normal_bevel) importlib.reload(vertex_bevel) importlib.reload(face_sketch) @@ -39,7 +39,7 @@ def register(): importlib.reload(ui_panel) importlib.reload(menu) - bolt.register() + ring_and_bolt.register() weighted_normal_bevel.register() vertex_bevel.register() face_sketch.register() @@ -53,7 +53,7 @@ def register(): def unregister(): unregister_draw_handler() - bolt.unregister() + ring_and_bolt.unregister() weighted_normal_bevel.unregister() vertex_bevel.unregister() face_sketch.unregister() diff --git a/menu.py b/menu.py index 9c78896..f1a9367 100644 --- a/menu.py +++ b/menu.py @@ -19,7 +19,7 @@ def draw(self, context): layout.operator("nd.solidify", icon='MOD_SOLIDIFY') layout.operator("nd.screw", icon='MOD_SCREW') layout.separator() - layout.operator("nd.bolt", icon='MESH_CYLINDER') + layout.operator("nd.ring_and_bolt", icon='MESH_CYLINDER') def draw_item(self, context): diff --git a/bolt.py b/ring_and_bolt.py similarity index 55% rename from bolt.py rename to ring_and_bolt.py index 1342ad3..6b986ae 100644 --- a/bolt.py +++ b/ring_and_bolt.py @@ -5,17 +5,16 @@ from . utils import add_single_vertex_object, align_object_to_3d_cursor -class ND_OT_bolt(bpy.types.Operator): - bl_idname = "nd.bolt" - bl_label = "Bolt (& Hole Cutter)" - bl_description = "Adds a bolt using the 3D cursor position & rotation" +class ND_OT_ring_and_bolt(bpy.types.Operator): + bl_idname = "nd.ring_and_bolt" + bl_label = "Ring & Bolt" + bl_description = "Adds a ring or ring_and_bolt face at the 3D cursor" bl_options = {'UNDO'} def modal(self, context, event): - offset_factor = (self.base_offset_factor / 10.0) if event.shift else self.base_offset_factor radius_factor = (self.base_radius_factor / 10.0) if event.shift else self.base_radius_factor - thickness_factor = (self.base_thickness_factor / 10.0) if event.shift else self.base_thickness_factor + width_factor = (self.base_width_factor / 10.0) if event.shift else self.base_width_factor segment_factor = 1 if event.shift else 2 self.key_shift = event.shift @@ -26,38 +25,30 @@ def modal(self, context, event): self.pin_overlay = not self.pin_overlay elif event.type in {'PLUS', 'EQUAL', 'NUMPAD_PLUS'} and event.value == 'PRESS': - if event.alt and event.ctrl: - self.base_offset_factor = min(1, self.base_offset_factor * 10.0) - elif event.alt: + if event.alt: self.base_radius_factor = min(1, self.base_radius_factor * 10.0) elif event.ctrl: - self.base_thickness_factor = min(1, self.base_thickness_factor * 10.0) + self.base_width_factor = min(1, self.base_width_factor * 10.0) elif event.type in {'MINUS', 'NUMPAD_MINUS'} and event.value == 'PRESS': - if event.alt and event.ctrl: - self.base_offset_factor = max(0.001, self.base_offset_factor / 10.0) - elif event.alt: + if event.alt: self.base_radius_factor = max(0.001, self.base_radius_factor / 10.0) elif event.ctrl: - self.base_thickness_factor = max(0.001, self.base_thickness_factor / 10.0) + self.base_width_factor = max(0.001, self.base_width_factor / 10.0) elif event.type == 'WHEELUPMOUSE': - if event.alt and event.ctrl: - self.offset += offset_factor - elif event.alt: + if event.alt: self.radius += radius_factor elif event.ctrl: - self.thickness += thickness_factor + self.width += width_factor else: self.segments = 4 if self.segments == 3 else self.segments + segment_factor elif event.type == 'WHEELDOWNMOUSE': - if event.alt and event.ctrl: - self.offset -= offset_factor - elif event.alt: + if event.alt: self.radius = max(0, self.radius - radius_factor) elif event.ctrl: - self.thickness = max(0, self.thickness - thickness_factor) + self.width = max(0, self.width - width_factor) else: self.segments = max(3, self.segments - segment_factor) @@ -75,37 +66,34 @@ def modal(self, context, event): return {'PASS_THROUGH'} self.operate(context) - update_overlay(self, context, event, pinned=self.pin_overlay, x_offset=375, lines=4) + update_overlay(self, context, event, pinned=self.pin_overlay, x_offset=300, lines=3) return {'RUNNING_MODAL'} def invoke(self, context, event): - self.base_offset_factor = 0.001 self.base_radius_factor = 0.001 - self.base_thickness_factor = 0.001 + self.base_width_factor = 0.001 self.mouse_x = 0 self.mouse_y = 0 self.segments = 3 - self.radius = 0.02 - self.thickness = 0.02 - self.offset = 0 + self.radius = 0 + self.width = 0.05 self.key_shift = False self.key_alt = False self.key_ctrl = False + bpy.ops.object.select_all(action='DESELECT') + add_single_vertex_object(self, context, "Bolt") align_object_to_3d_cursor(self, context) + self.add_displace_modifier() self.add_screw_x_modifier() self.add_screw_z_modifer() - self.add_decimate_modifier() - self.add_displace_modifier() - self.add_solidify_modifier() - self.set_cutter_visibility(context) self.pin_overlay = False init_overlay(self, event) @@ -121,17 +109,21 @@ def poll(cls, context): return context.mode == 'OBJECT' - def set_cutter_visibility(self, context): - if len(context.selected_objects) > 1: - self.obj.show_in_front = True - self.obj.color[3] = 0.2 + def add_displace_modifier(self): + displace = self.obj.modifiers.new("ND — Radius", 'DISPLACE') + displace.mid_level = 0.5 + displace.strength = self.radius + displace.direction = 'X' + displace.space = 'LOCAL' + + self.displace = displace def add_screw_x_modifier(self): - screwX = self.obj.modifiers.new("ND — Radius", 'SCREW') + screwX = self.obj.modifiers.new("ND — Width", 'SCREW') screwX.axis = 'X' screwX.angle = 0 - screwX.screw_offset = self.radius + screwX.screw_offset = self.width screwX.steps = 1 screwX.render_steps = 1 screwX.use_merge_vertices = True @@ -151,68 +143,25 @@ def add_screw_z_modifer(self): self.screwZ = screwZ - def add_decimate_modifier(self): - decimate = self.obj.modifiers.new("ND — Decimate", 'DECIMATE') - decimate.decimate_type = 'DISSOLVE' - decimate.angle_limit = radians(.25) - decimate.show_viewport = False if self.segments <= 3 else True - - self.decimate = decimate - - - def add_displace_modifier(self): - displace = self.obj.modifiers.new("ND — Offset", 'DISPLACE') - displace.mid_level = 0.5 - displace.strength = self.offset - - self.displace = displace - - - def add_solidify_modifier(self): - solidify = self.obj.modifiers.new("ND — Thickness", 'SOLIDIFY') - solidify.thickness = self.thickness - solidify.offset = 1 - - self.solidify = solidify - - - def handle_optional_boolean_ops(self, context): - if len(context.selected_objects) > 1: - self.obj.display_type = 'WIRE' - self.obj.show_in_front = False - self.obj.color[3] = 1.0 - - targets = [o for o in context.selected_objects if not (o == self.obj)] - - for target in targets: - boolean = target.modifiers.new("ND — Bolt Hole", 'BOOLEAN') - boolean.object = self.obj - else: - self.obj.display_type = 'SOLID' - - def operate(self, context): - self.decimate.show_viewport = False if self.segments <= 3 else True - self.screwX.screw_offset = self.radius + self.screwX.screw_offset = self.width self.screwZ.steps = self.segments self.screwZ.render_steps = self.segments - self.solidify.thickness = self.thickness - self.displace.strength = self.offset + self.displace.strength = self.radius - def select_bolt(self, context): + def select_ring_and_bolt(self, context): bpy.ops.object.select_all(action='DESELECT') self.obj.select_set(True) def finish(self, context): - self.handle_optional_boolean_ops(context) - self.select_bolt(context) + self.select_ring_and_bolt(context) unregister_draw_handler() def revert(self, context): - self.select_bolt(context) + self.select_ring_and_bolt(context) bpy.ops.object.delete() unregister_draw_handler() @@ -236,30 +185,23 @@ def draw_text_callback(self): draw_property( self, - "Thickness: {0:.0f}mm".format(self.thickness * 1000), - "Ctrl (±{0:.1f}mm) | Shift + Ctrl (±{1:.1f}mm)".format(self.base_thickness_factor * 1000, (self.base_thickness_factor / 10) * 1000), + "Width: {0:.0f}mm".format(self.width * 1000), + "Ctrl (±{0:.1f}mm) | Shift + Ctrl (±{1:.1f}mm)".format(self.base_width_factor * 1000, (self.base_width_factor / 10) * 1000), active=(self.key_ctrl and not self.key_alt), alt_mode=(self.key_ctrl and not self.key_alt and self.key_shift)) - draw_property( - self, - "Offset: {0:.3f}".format(self.offset), - "Ctrl + Alt (±{0:.1f}mm) | Shift + Ctrl + Alt (±{1:.1f}mm)".format(self.base_offset_factor * 1000, (self.base_offset_factor / 10) * 1000), - active=(self.key_ctrl and self.key_alt), - alt_mode=(self.key_ctrl and self.key_alt and self.key_shift)) - def menu_func(self, context): - self.layout.operator(ND_OT_bolt.bl_idname, text=ND_OT_bolt.bl_label) + self.layout.operator(ND_OT_ring_and_bolt.bl_idname, text=ND_OT_ring_and_bolt.bl_label) def register(): - bpy.utils.register_class(ND_OT_bolt) + bpy.utils.register_class(ND_OT_ring_and_bolt) bpy.types.VIEW3D_MT_object.append(menu_func) def unregister(): - bpy.utils.unregister_class(ND_OT_bolt) + bpy.utils.unregister_class(ND_OT_ring_and_bolt) bpy.types.VIEW3D_MT_object.remove(menu_func) unregister_draw_handler() diff --git a/solidify.py b/solidify.py index 678a3ac..a638a22 100644 --- a/solidify.py +++ b/solidify.py @@ -13,28 +13,40 @@ class ND_OT_solidify(bpy.types.Operator): def modal(self, context, event): thickness_factor = (self.base_thickness_factor / 10.0) if event.shift else self.base_thickness_factor + offset_factor = (self.base_offset_factor / 10.0) if event.shift else self.base_offset_factor self.key_shift = event.shift self.key_alt = event.alt + self.key_ctrl = event.ctrl if event.type == 'P' and event.value == 'PRESS': self.pin_overlay = not self.pin_overlay elif event.type in {'PLUS', 'EQUAL', 'NUMPAD_PLUS'} and event.value == 'PRESS': - self.base_thickness_factor = min(1, self.base_thickness_factor * 10.0) + if event.ctrl: + self.base_offset_factor = min(1, self.base_offset_factor * 10.0) + else: + self.base_thickness_factor = min(1, self.base_thickness_factor * 10.0) elif event.type in {'MINUS', 'NUMPAD_MINUS'} and event.value == 'PRESS': - self.base_thickness_factor = max(0.001, self.base_thickness_factor / 10.0) + if event.ctrl: + self.base_offset_factor = max(0.001, self.base_offset_factor / 10.0) + else: + self.base_thickness_factor = max(0.001, self.base_thickness_factor / 10.0) elif event.type == 'WHEELUPMOUSE': if event.alt: - self.offset = min(1, self.offset + 1) + self.weighting = min(1, self.weighting + 1) + elif event.ctrl: + self.offset += offset_factor else: self.thickness += thickness_factor elif event.type == 'WHEELDOWNMOUSE': if event.alt: - self.offset = max(-1, self.offset - 1) + self.weighting = max(-1, self.weighting - 1) + elif event.ctrl: + self.offset -= offset_factor else: self.thickness = max(0, self.thickness - thickness_factor) @@ -52,21 +64,25 @@ def modal(self, context, event): return {'PASS_THROUGH'} self.operate(context) - update_overlay(self, context, event, pinned=self.pin_overlay, x_offset=260, lines=2) + update_overlay(self, context, event, pinned=self.pin_overlay, x_offset=300, lines=3) return {'RUNNING_MODAL'} def invoke(self, context, event): self.base_thickness_factor = 0.001 + self.base_offset_factor = 0.001 self.thickness = 0.001 + self.weighting = 0 self.offset = 0 self.key_shift = False self.key_alt = False + self.key_ctrl = False self.add_smooth_shading(context) + self.add_displace_modifier(context) self.add_solidify_modifier(context) self.pin_overlay = False @@ -90,17 +106,25 @@ def add_smooth_shading(self, context): context.object.data.auto_smooth_angle = radians(30) + def add_displace_modifier(self, context): + displace = context.object.modifiers.new("ND — Offset", 'DISPLACE') + displace.strength = self.offset + + self.displace = displace + + def add_solidify_modifier(self, context): - solidify = context.object.modifiers.new("ND — solidify", 'SOLIDIFY') + solidify = context.object.modifiers.new("ND — Thickness", 'SOLIDIFY') solidify.thickness = self.thickness - solidify.offset = self.offset + solidify.offset = self.weighting self.solidify = solidify def operate(self, context): self.solidify.thickness = self.thickness - self.solidify.offset = self.offset + self.solidify.offset = self.weighting + self.displace.strength = self.offset def finish(self, context): @@ -108,6 +132,7 @@ def finish(self, context): def revert(self, context): + bpy.ops.object.modifier_remove(modifier=self.displace.name) bpy.ops.object.modifier_remove(modifier=self.solidify.name) unregister_draw_handler() @@ -119,16 +144,23 @@ def draw_text_callback(self): self, "Thickness: {0:.1f}mm".format(self.thickness * 1000), "(±{0:.1f}mm) | Shift + (±{1:.1f}mm)".format(self.base_thickness_factor * 1000, (self.base_thickness_factor / 10) * 1000), - active=(not self.key_alt), - alt_mode=(self.key_shift and not self.key_alt)) + active=(not self.key_alt and not self.key_ctrl), + alt_mode=(self.key_shift and not self.key_alt and not self.key_ctrl)) draw_property( self, - "Offset: {}".format(self.offset), - "Alt (±1)", - active=(self.key_alt), + "Offset: {}".format(['Negative', 'Neutral', 'Positive'][1 + self.weighting]), + "Alt (Negative, Neutral, Positive)", + active=(self.key_alt and not self.key_ctrl), alt_mode=False) + draw_property( + self, + "Offset: {0:.1f}mm".format(self.offset * 1000), + "Ctrl (±{0:.1f}mm) | Shift + Ctrl (±{1:.1f}mm)".format(self.base_offset_factor * 1000, (self.base_offset_factor / 10) * 1000), + active=(not self.key_alt and self.key_ctrl), + alt_mode=(self.key_shift and not self.key_alt and self.key_ctrl)) + def menu_func(self, context): self.layout.operator(ND_OT_solidify.bl_idname, text=ND_OT_solidify.bl_label) diff --git a/ui_panel.py b/ui_panel.py index 24dcb9f..fc30298 100644 --- a/ui_panel.py +++ b/ui_panel.py @@ -59,7 +59,7 @@ def draw(self, context): row = column.row(align=True) row.scale_y = 1.2 - row.operator("nd.bolt", icon='MESH_CYLINDER') + row.operator("nd.ring_and_bolt", icon='MESH_CYLINDER') def register():