2020bl_info = {
2121 "name" : "Offset Edges" ,
2222 "author" : "Hidesato Ikeya" ,
23- "version" : (0 , 2 , 5 ),
23+ "version" : (0 , 2 , 6 ),
2424 "blender" : (2 , 70 , 0 ),
2525 "location" : "VIEW3D > Edge menu(CTRL-E) > Offset Edges" ,
2626 "description" : "Offset Edges" ,
3232import math
3333from math import sin , cos , pi , copysign , radians
3434import bpy
35+ from bpy_extras import view3d_utils
3536import bmesh
3637from mathutils import Vector
3738from time import perf_counter
@@ -466,6 +467,17 @@ def get_directions(lp, vec_upward, normal_fallback, vert_mirror_pairs, **options
466467def use_cashes (self , context ):
467468 self .caches_valid = True
468469
470+ angle_presets = {'0°' : 0 ,
471+ '15°' : radians (15 ),
472+ '30°' : radians (30 ),
473+ '45°' : radians (45 ),
474+ '60°' : radians (60 ),
475+ '75°' : radians (75 ),
476+ '90°' : radians (90 ),}
477+ def assign_angle_presets (self , context ):
478+ use_cashes (self , context )
479+ self .angle = angle_presets [self .angle_presets ]
480+
469481class OffsetEdges (bpy .types .Operator ):
470482 """Offset Edges."""
471483 bl_idname = "mesh.offset_edges"
@@ -494,7 +506,7 @@ class OffsetEdges(bpy.types.Operator):
494506 name = "Depth mode" , default = 'angle' , update = use_cashes )
495507 angle = bpy .props .FloatProperty (
496508 name = "Angle" , default = 0 , precision = 3 , step = .1 ,
497- min = - 4 * pi , max = 4 * pi , subtype = 'ANGLE' ,
509+ min = - 2 * pi , max = 2 * pi , subtype = 'ANGLE' ,
498510 description = "Angle" , update = use_cashes )
499511 flip_angle = bpy .props .BoolProperty (
500512 name = "Flip Angle" , default = False ,
@@ -514,15 +526,22 @@ class OffsetEdges(bpy.types.Operator):
514526 threshold = bpy .props .FloatProperty (
515527 name = "Flat Face Threshold" , default = radians (0.05 ), precision = 5 ,
516528 step = 1.0e-4 , subtype = 'ANGLE' ,
517- description = "If angle difference between two adjacent faces is "
518- "under this value, those faces are regarded as flat." ,
519- options = {'HIDDEN' })
520- interactive = bpy .props .BoolProperty (
521- name = "Interactive" , default = False ,
529+ description = "If difference of angle between two adjacent faces is "
530+ "below this value, those faces are regarded as flat." ,
522531 options = {'HIDDEN' })
523532 caches_valid = bpy .props .BoolProperty (
524533 name = "Caches Valid" , default = False ,
525534 options = {'HIDDEN' })
535+ angle_presets = bpy .props .EnumProperty (
536+ items = [('0°' , "0°" , "0°" ),
537+ ('15°' , "15°" , "15°" ),
538+ ('30°' , "30°" , "30°" ),
539+ ('45°' , "45°" , "45°" ),
540+ ('60°' , "60°" , "60°" ),
541+ ('75°' , "75°" , "75°" ),
542+ ('90°' , "90°" , "90°" ), ],
543+ name = "Angle Presets" , default = '0°' ,
544+ update = assign_angle_presets )
526545
527546 _cache_offset_infos = None
528547 _cache_edges_orig_ixs = None
@@ -550,6 +569,8 @@ def draw(self, context):
550569 row = layout .row (align = True )
551570 row .prop (self , d_mode )
552571 row .prop (self , flip , icon = 'ARROW_LEFTRIGHT' , icon_only = True )
572+ if self .depth_mode == 'angle' :
573+ layout .prop (self , 'angle_presets' , text = "Presets" , expand = True )
553574
554575 layout .separator ()
555576
@@ -711,37 +732,6 @@ def restore_original_and_free(self, context):
711732 self ._bm_orig .free ()
712733 context .area .header_text_set ()
713734
714- def modal (self , context , event ):
715- # In edit mode
716- if event .type == 'MOUSEMOVE' :
717- edit_object = context .edit_object
718- me = edit_object .data
719-
720- vec_delta = Vector ((event .mouse_x , event .mouse_y )) - self ._initial_mouse
721- #self.width = copysign(vec_delta.length, vec_delta.dot(X_UP)) * 0.01
722- self .width = vec_delta .x * 0.01
723- #self.angle = vec_delta.y * 0.01
724- offset_infos , _ = self .get_offset_infos (self ._bm_orig , edit_object )
725- if offset_infos is False :
726- self .restore_original_and_free (context )
727- return {'CANCELLED' }
728- else :
729- context .area .header_text_set ("Width {: .4}" .format (self .width ))
730- self .do_offset_and_free (self ._bm_orig .copy (), me )
731- return {'RUNNING_MODAL' }
732-
733- elif event .type in {'RIGHTMOUSE' , 'ESC' }:
734- self .restore_original_and_free (context )
735- return {'CANCELLED' }
736-
737- elif event .type == 'LEFTMOUSE' :
738- context .area .header_text_set ()
739- self ._bm_orig .free ()
740- self .caches_valid = False # Make caches invalid
741- return {'FINISHED' }
742-
743- return {'RUNNING_MODAL' }
744-
745735 def invoke (self , context , event ):
746736 # In edit mode
747737 edit_object = context .edit_object
@@ -751,25 +741,10 @@ def invoke(self, context, event):
751741 if p .select :
752742 self .follow_face = True
753743 break
754- #bpy.ops.object.mode_set(mode="EDIT")
755- ## In edit mode
756- #return self.execute(context)
757744
758745 self .caches_valid = False
759- if self .interactive and context .space_data .type == 'VIEW_3D' :
760- self .interactive = False
761- _bm_orig = bmesh .new ()
762- _bm_orig .from_mesh (me )
763- self ._bm_orig = _bm_orig
764- self .angle = self .depth = .0
765- self ._initial_mouse = Vector ((event .mouse_x , event .mouse_y ))
766- context .window_manager .modal_handler_add (self )
767- bpy .ops .object .mode_set (mode = "EDIT" )
768- return {'RUNNING_MODAL' }
769- else :
770- self .interactive = False
771- bpy .ops .object .mode_set (mode = "EDIT" )
772- return self .execute (context )
746+ bpy .ops .object .mode_set (mode = "EDIT" )
747+ return self .execute (context )
773748
774749class OffsetEdgesMenu (bpy .types .Menu ):
775750 bl_idname = "VIEW3D_MT_edit_mesh_offset_edges"
@@ -788,8 +763,6 @@ def draw(self, context):
788763 mov = layout .operator ('mesh.offset_edges' , text = 'Move' )
789764 mov .geometry_mode = 'move'
790765
791- #off.interactive = ext.interactive = mov.interactive = True
792-
793766def draw_item (self , context ):
794767 self .layout .menu ("VIEW3D_MT_edit_mesh_offset_edges" )
795768
0 commit comments