Skip to content

Commit deacfbe

Browse files
committed
offset_edges: Divided threshold to two, changed version number to 0.2.3
1 parent 036398b commit deacfbe

File tree

1 file changed

+45
-26
lines changed

1 file changed

+45
-26
lines changed

mesh_offset_edges.py

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
bl_info = {
2323
"name": "Offset Edges",
2424
"author": "Hidesato Ikeya",
25-
"version": (0, 2, 2),
25+
"version": (0, 2, 3),
2626
"blender": (2, 70, 0),
2727
"location": "VIEW3D > Edge menu(CTRL-E) > Offset Edges",
2828
"description": "Offset Edges",
@@ -67,7 +67,7 @@ def calc_normal_from_verts(verts, fallback=Z_UP):
6767

6868
return normal
6969

70-
def get_corner_type(vec_up, vec_right2d, vec_left2d, threshold):
70+
def get_corner_type(vec_up, vec_right2d, vec_left2d, threshold_edge):
7171
# vec_right2d and vec_left2d should be perpendicular to vec_up.
7272
# All vectors in parameters should have been normalized.
7373
if vec_right2d == vec_left2d == ZERO_VEC:
@@ -76,22 +76,22 @@ def get_corner_type(vec_up, vec_right2d, vec_left2d, threshold):
7676
return 'STRAIGHT'
7777

7878
angle = vec_right2d.angle(vec_left2d)
79-
if angle < threshold:
79+
if angle < threshold_edge:
8080
return 'FOLDING'
81-
elif angle > ANGLE_180 - threshold:
81+
elif angle > ANGLE_180 - threshold_edge:
8282
return 'STRAIGHT'
8383
elif vec_right2d.cross(vec_left2d).dot(vec_up) > .0:
8484
return 'CONVEX'
8585
else:
8686
return 'CONCAVE'
8787

88-
def calc_tangent(vec_up, vec_right, vec_left, threshold):
88+
def calc_tangent(vec_up, vec_right, vec_left, threshold_edge):
8989
vec_right2d = vec_right- vec_right.project(vec_up)
9090
vec_right2d.normalize()
9191
vec_left2d = vec_left- vec_left.project(vec_up)
9292
vec_right2d.normalize()
9393

94-
corner = get_corner_type(vec_up, vec_right2d, vec_left2d, threshold)
94+
corner = get_corner_type(vec_up, vec_right2d, vec_left2d, threshold_edge)
9595
if corner == 'FOLDING':
9696
vec_tangent = ZERO_VEC
9797
elif corner == 'STRAIGHT':
@@ -237,7 +237,7 @@ def get_adj_ix(ix_start, vec_edges, half_loop):
237237

238238
return ix_right, ix_left
239239

240-
def get_normals(lp_normal, adj_faces, ix_r, ix_l, vert):
240+
def get_normals(lp_normal, adj_faces, ix_r, ix_l, vert, threshold_face):
241241
normal_r = normal_l = None
242242
if adj_faces:
243243
f_r, f_l = adj_faces[ix_r], adj_faces[ix_l]
@@ -252,7 +252,10 @@ def get_normals(lp_normal, adj_faces, ix_r, ix_l, vert):
252252

253253
if normal_r and normal_l:
254254
vec_up = (normal_r + normal_l).normalized()
255-
if vec_up == ZERO_VEC:
255+
if normal_r.angle(normal_l) < threshold_face:
256+
# Two normals are almost same, so assign None to normal_l
257+
normal_l = None
258+
elif vec_up == ZERO_VEC:
256259
vec_up = lp_normal.copy()
257260
elif normal_r or normal_l:
258261
vec_up = (normal_r or normal_l).copy()
@@ -311,12 +314,8 @@ def get_edge_rail(vert, set_edges_orig):
311314
else:
312315
return None
313316

314-
def get_cross_rail(vec_tan, vec_edge_r, vec_edge_l, normal_r, normal_l, threshold):
317+
def get_cross_rail(vec_tan, vec_edge_r, vec_edge_l, normal_r, normal_l):
315318
# Cross rail is a cross vector between normal_r and normal_l.
316-
angle = normal_r.angle(normal_l)
317-
if angle < threshold:
318-
# normal_r and normal_l are almost same
319-
return None
320319

321320
vec_cross = normal_r.cross(normal_l)
322321
if vec_cross.dot(vec_tan) < .0:
@@ -433,7 +432,8 @@ def get_directions(lp, vec_upward, normal_fallback, vert_mirror_pairs, **options
433432
opt_follow_face = options['follow_face']
434433
opt_edge_rail = options['edge_rail']
435434
opt_er_only_end = options['edge_rail_only_end']
436-
opt_threshold = options['threshold']
435+
opt_threshold_edge = options['threshold_edge']
436+
opt_threshold_face = options['threshold_face']
437437

438438
verts, edges = lp[::2], lp[1::2]
439439
set_edges = set(edges)
@@ -480,24 +480,30 @@ def get_directions(lp, vec_upward, normal_fallback, vert_mirror_pairs, **options
480480
vec_edge_r = vec_edges[ix_r]
481481
vec_edge_l = -vec_edges[ix_l]
482482

483-
vec_up, normal_r, normal_l = get_normals(lp_normal, adj_faces, ix_r, ix_l, v)
484-
vec_tan = calc_tangent(vec_up, vec_edge_r, vec_edge_l, opt_threshold)
483+
vec_up, normal_r, normal_l = \
484+
get_normals(lp_normal, adj_faces, ix_r, ix_l, v, opt_threshold_face)
485+
vec_tan = calc_tangent(vec_up, vec_edge_r, vec_edge_l, opt_threshold_edge)
485486

486487
if vec_tan != ZERO_VEC:
488+
if normal_r and normal_l:
489+
two_normals = True
490+
else:
491+
two_normals = False
492+
487493
rail = None
488494
if vert_mirror_pairs and VERT_END:
489495
if v in vert_mirror_pairs:
490496
rail, vec_up = get_mirror_rail(vert_mirror_pairs[v], vec_up)
491-
if opt_edge_rail:
497+
if two_normals or opt_edge_rail:
492498
# Get edge rail.
493499
# edge rail is a vector of an inner edge.
494-
if (not opt_er_only_end) or VERT_END:
500+
if two_normals or (not opt_er_only_end) or VERT_END:
495501
rail = get_edge_rail(v, set_edges)
496-
if (not rail) and normal_r and normal_l:
502+
if (not rail) and two_normals:
497503
# Get cross rail.
498504
# Cross rail is a cross vector between normal_r and normal_l.
499505
rail = get_cross_rail(
500-
vec_tan, vec_edge_r, vec_edge_l, normal_r, normal_l, opt_threshold)
506+
vec_tan, vec_edge_r, vec_edge_l, normal_r, normal_l)
501507
if rail:
502508
vec_tan = vec_tan.project(rail)
503509
vec_tan.normalize()
@@ -541,7 +547,7 @@ class OffsetEdges(bpy.types.Operator):
541547
('depth', "Depth", "Depth")],
542548
name="Depth mode", default='angle', update=use_cashes)
543549
angle = bpy.props.FloatProperty(
544-
name="Angle", default=0, step=.1, min=-4*pi, max=4*pi,
550+
name="Angle", default=0, precision=3, step=.1, min=-4*pi, max=4*pi,
545551
subtype='ANGLE', description="Angle", update=use_cashes)
546552
flip_angle = bpy.props.BoolProperty(
547553
name="Flip Angle", default=False,
@@ -558,9 +564,13 @@ class OffsetEdges(bpy.types.Operator):
558564
edge_rail_only_end = bpy.props.BoolProperty(
559565
name="Edge Rail Only End", default=False,
560566
description="Apply edge rail to end verts only")
561-
threshold = bpy.props.FloatProperty(
562-
name="Threshold", default=1.0e-5, step=.1, subtype='ANGLE',
563-
description="Angle threshold which determines straight or folding edges",
567+
threshold_face = bpy.props.FloatProperty(
568+
name="Face Threshold", default=1.0e-3, precision=7, step=1.0e-4, subtype='ANGLE',
569+
description="Threshold of normal angle which determines flat faces",
570+
options={'HIDDEN'})
571+
threshold_edge = bpy.props.FloatProperty(
572+
name="Edge Threshold", default=1.0e-4, precision=7, step=1.0e-4, subtype='ANGLE',
573+
description="Threshold of Edge angle which determines straight or folding",
564574
options={'HIDDEN'})
565575
interactive = bpy.props.BoolProperty(
566576
name="Interactive", default=False,
@@ -607,6 +617,11 @@ def draw(self, context):
607617

608618
layout.prop(self, 'mirror_modifier')
609619

620+
layout.separator()
621+
box = layout.box()
622+
box.label("Threshold:")
623+
box.prop(self, 'threshold_face', text="Face")
624+
box.prop(self, 'threshold_edge', text="Edge")
610625
#layout.operator('mesh.offset_edges', text='Repeat')
611626

612627
def get_offset_infos(self, bm, edit_object):
@@ -651,14 +666,16 @@ def get_offset_infos(self, bm, edit_object):
651666
follow_face = self.follow_face
652667
edge_rail = self.edge_rail
653668
er_only_end = self.edge_rail_only_end
654-
threshold = self.threshold
669+
threshold_f = self.threshold_face
670+
threshold_e = self.threshold_edge
655671

656672
offset_infos = []
657673
for lp in loops:
658674
verts, directions = get_directions(
659675
lp, vec_upward, normal_fallback, vert_mirror_pairs,
660676
follow_face=follow_face, edge_rail=edge_rail,
661-
edge_rail_only_end=er_only_end, threshold=threshold)
677+
edge_rail_only_end=er_only_end,
678+
threshold_face=threshold_f, threshold_edge=threshold_e)
662679
if verts:
663680
offset_infos.append((verts, directions))
664681

@@ -731,6 +748,8 @@ def execute(self, context):
731748

732749
offset_infos, edges_orig = self.get_offset_infos(bm, edit_object)
733750
if offset_infos is False:
751+
bpy.ops.object.editmode_toggle()
752+
# In object mode
734753
return {'CANCELLED'}
735754

736755
self.do_offset_and_free(bm, me, offset_infos, edges_orig)

0 commit comments

Comments
 (0)