diff options
Diffstat (limited to 'mesh_extra_tools/mesh_extrude_and_reshape.py')
-rw-r--r-- | mesh_extra_tools/mesh_extrude_and_reshape.py | 133 |
1 files changed, 73 insertions, 60 deletions
diff --git a/mesh_extra_tools/mesh_extrude_and_reshape.py b/mesh_extra_tools/mesh_extrude_and_reshape.py index 14d9d744..8716bfb1 100644 --- a/mesh_extra_tools/mesh_extrude_and_reshape.py +++ b/mesh_extra_tools/mesh_extrude_and_reshape.py @@ -1,4 +1,4 @@ -### BEGIN GPL LICENSE BLOCK ##### +# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -25,14 +25,17 @@ bl_info = { "version": (0, 8, 1), "blender": (2, 76, 5), "location": "View3D > TOOLS > Tools > Mesh Tools > Add: > Extrude Menu (Alt + E)", - "description": "Extrude face and merge edge intersections between the mesh and the new edges", - "wiki_url" : "http://blenderartists.org/forum/showthread.php?376618-Addon-Push-Pull-Face", - "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/", + "description": "Extrude face and merge edge intersections " + "between the mesh and the new edges", + "wiki_url": "http://blenderartists.org/forum/" + "showthread.php?376618-Addon-Push-Pull-Face", "category": "Mesh"} -import bpy, bmesh +import bpy +import bmesh from mathutils.geometry import intersect_line_line -from bpy.props import FloatProperty +from bpy.types import Operator + class BVHco(): i = 0 @@ -43,7 +46,8 @@ class BVHco(): c2y = 0.0 c2z = 0.0 -def edges_BVH_overlap(bm, edges, epsilon = 0.0001): + +def edges_BVH_overlap(bm, edges, epsilon=0.0001): bco = set() for e in edges: bvh = BVHco() @@ -113,19 +117,19 @@ def edges_BVH_overlap(bm, edges, epsilon = 0.0001): overlap[e1] = oget(e1, set()).union({e2}) return overlap -def intersect_edges_edges(overlap, precision = 4): + +def intersect_edges_edges(overlap, precision=4): epsilon = .1**precision fpre_min = -epsilon - fpre_max = 1+epsilon + fpre_max = 1 + epsilon splits = {} sp_get = splits.get new_edges1 = set() new_edges2 = set() targetmap = {} for edg1 in overlap: - #print("***", ed1.index, "***") + # print("***", ed1.index, "***") for edg2 in overlap[edg1]: - #print('loop', ed2.index) a1 = edg1.verts[0] a2 = edg1.verts[1] b1 = edg2.verts[0] @@ -133,7 +137,7 @@ def intersect_edges_edges(overlap, precision = 4): # test if are linked if a1 in {b1, b2} or a2 in {b1, b2}: - #print('linked') + # print('linked') continue aco1, aco2 = a1.co, a2.co @@ -141,23 +145,23 @@ def intersect_edges_edges(overlap, precision = 4): tp = intersect_line_line(aco1, aco2, bco1, bco2) if tp: p1, p2 = tp - if (p1 - p2).to_tuple(precision) == (0,0,0): - v = aco2-aco1 + if (p1 - p2).to_tuple(precision) == (0, 0, 0): + v = aco2 - aco1 f = p1 - aco1 - x,y,z = abs(v.x), abs(v.y), abs(v.z) + x, y, z = abs(v.x), abs(v.y), abs(v.z) max1 = 0 if x >= y and x >= z else\ 1 if y >= x and y >= z else 2 - fac1 = f[max1]/v[max1] + fac1 = f[max1] / v[max1] - v = bco2-bco1 + v = bco2 - bco1 f = p2 - bco1 - x,y,z = abs(v.x), abs(v.y), abs(v.z) + x, y, z = abs(v.x), abs(v.y), abs(v.z) max2 = 0 if x >= y and x >= z else\ 1 if y >= x and y >= z else 2 - fac2 = f[max2]/v[max2] + fac2 = f[max2] / v[max2] if fpre_min <= fac1 <= fpre_max: - #print(edg1.index, 'can intersect', edg2.index) + # print(edg1.index, 'can intersect', edg2.index) ed1 = edg1 elif edg1 in splits: @@ -168,21 +172,21 @@ def intersect_edges_edges(overlap, precision = 4): vco1 = a1.co vco2 = a2.co - v = vco2-vco1 + v = vco2 - vco1 f = p1 - vco1 - fac1 = f[max1]/v[max1] + fac1 = f[max1] / v[max1] if fpre_min <= fac1 <= fpre_max: - #print(e.index, 'can intersect', edg2.index) + # print(e.index, 'can intersect', edg2.index) break else: - #print(edg1.index, 'really does not intersect', edg2.index) + # print(edg1.index, 'really does not intersect', edg2.index) continue else: - #print(edg1.index, 'not intersect', edg2.index) + # print(edg1.index, 'not intersect', edg2.index) continue if fpre_min <= fac2 <= fpre_max: - #print(ed1.index, 'actually intersect', edg2.index) + # print(ed1.index, 'actually intersect', edg2.index) ed2 = edg2 elif edg2 in splits: @@ -193,17 +197,17 @@ def intersect_edges_edges(overlap, precision = 4): vco1 = b1.co vco2 = b2.co - v = vco2-vco1 + v = vco2 - vco1 f = p2 - vco1 - fac2 = f[max2]/v[max2] + fac2 = f[max2] / v[max2] if fpre_min <= fac2 <= fpre_max: - #print(ed1.index, 'actually intersect', e.index) + # print(ed1.index, 'actually intersect', e.index) break else: - #print(ed1.index, 'really does not intersect', ed2.index) + # print(ed1.index, 'really does not intersect', ed2.index) continue else: - #print(ed1.index, 'not intersect', edg2.index) + # print(ed1.index, 'not intersect', edg2.index) continue new_edges1.add(ed1) @@ -227,30 +231,28 @@ def intersect_edges_edges(overlap, precision = 4): new_edges2.add(ne2) splits[edg2] = sp_get(edg2, set()).union({ne2}) - if nv1 != nv2: #necessary? + if nv1 != nv2: # necessary? targetmap[nv1] = nv2 - #else: - #print('not coplanar') - #else: - #print("parallel or collinear") + return new_edges1, new_edges2, targetmap -class Extrude_and_Reshape(bpy.types.Operator): - """Push and pull face entities to sculpt 3d models""" + +class Extrude_and_Reshape(Operator): bl_idname = "mesh.extrude_reshape" bl_label = "Extrude and Reshape" + bl_description = "Push and pull face entities to sculpt 3d models" bl_options = {'REGISTER', 'GRAB_CURSOR', 'BLOCKING'} @classmethod def poll(cls, context): - return context.mode is not 'EDIT_MESH' + return context.mode is not 'EDIT_MESH' def modal(self, context, event): if self.confirm: sface = self.bm.faces.active if not sface: for face in self.bm.faces: - if face.select == True: + if face.select is True: sface = face break else: @@ -259,13 +261,13 @@ class Extrude_and_Reshape(bpy.types.Operator): edges = set() [[edges.add(ed) for ed in v.link_edges] for v in sface.verts] - overlap = edges_BVH_overlap(self.bm, edges, epsilon = 0.0001) - overlap = {k: v for k,v in overlap.items() if k not in edges} # remove repetition - - #print([e.index for e in edges]) - #for a, b in overlap.items(): - #print(a.index, [e.index for e in b]) - + overlap = edges_BVH_overlap(self.bm, edges, epsilon=0.0001) + overlap = {k: v for k, v in overlap.items() if k not in edges} # remove repetition + """ + print([e.index for e in edges]) + for a, b in overlap.items(): + print(a.index, [e.index for e in b]) + """ new_edges1, new_edges2, targetmap = intersect_edges_edges(overlap) pos_weld = set() for e in new_edges1: @@ -274,9 +276,11 @@ class Extrude_and_Reshape(bpy.types.Operator): pos_weld.add((targetmap[v1], targetmap[v2])) if targetmap: bmesh.ops.weld_verts(self.bm, targetmap=targetmap) - #print([e.is_valid for e in new_edges1]) - #print([e.is_valid for e in new_edges2]) - #sp_faces1 = set() + """ + print([e.is_valid for e in new_edges1]) + print([e.is_valid for e in new_edges2]) + sp_faces1 = set() + """ for e in pos_weld: v1, v2 = e lf1 = set(v1.link_faces) @@ -285,11 +289,11 @@ class Extrude_and_Reshape(bpy.types.Operator): for f in rlfe: try: nf = bmesh.utils.face_split(f, v1, v2) - #sp_faces1.update({f, nf[0]}) + # sp_faces1.update({f, nf[0]}) except: pass - #sp_faces2 = set() + # sp_faces2 = set() for e in new_edges2: lfe = set(e.link_faces) v1, v2 = e.verts @@ -298,7 +302,7 @@ class Extrude_and_Reshape(bpy.types.Operator): rlfe = lf1.intersection(lf2) for f in rlfe.difference(lfe): nf = bmesh.utils.face_split(f, v1, v2) - #sp_faces2.update({f, nf[0]}) + # sp_faces2.update({f, nf[0]}) bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True) return {'FINISHED'} @@ -315,7 +319,7 @@ class Extrude_and_Reshape(bpy.types.Operator): selection = self.bm.select_history[-1] except: for face in self.bm.faces: - if face.select == True: + if face.select is True: selection = face break else: @@ -325,22 +329,27 @@ class Extrude_and_Reshape(bpy.types.Operator): return {'FINISHED'} else: face = selection - #face.select = False + # face.select = False bpy.ops.mesh.select_all(action='DESELECT') geom = [] for edge in face.edges: - if abs(edge.calc_face_angle(0) - 1.5707963267948966) < 0.01: #self.angle_tolerance: + if abs(edge.calc_face_angle(0) - 1.5707963267948966) < 0.01: # self.angle_tolerance: geom.append(edge) - ret_dict = bmesh.ops.extrude_discrete_faces(self.bm, faces = [face]) + ret_dict = bmesh.ops.extrude_discrete_faces(self.bm, faces=[face]) for face in ret_dict['faces']: self.bm.faces.active = face face.select = True sface = face - dfaces = bmesh.ops.dissolve_edges(self.bm, edges = geom, use_verts=True, use_face_split=False) + dfaces = bmesh.ops.dissolve_edges( + self.bm, edges=geom, use_verts=True, use_face_split=False + ) bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True) - bpy.ops.transform.translate('INVOKE_DEFAULT', constraint_axis=(False, False, True), constraint_orientation='NORMAL', release_confirm=True) + bpy.ops.transform.translate( + 'INVOKE_DEFAULT', constraint_axis=(False, False, True), + constraint_orientation='NORMAL', release_confirm=True + ) context.window_manager.modal_handler_add(self) @@ -348,18 +357,22 @@ class Extrude_and_Reshape(bpy.types.Operator): self.confirm = False return {'RUNNING_MODAL'} -def operator_draw(self,context): + +def operator_draw(self, context): layout = self.layout col = layout.column(align=True) col.operator("mesh.extrude_reshape", text="Extrude and Reshape") + def register(): bpy.utils.register_class(Extrude_and_Reshape) bpy.types.VIEW3D_MT_edit_mesh_extrude.append(operator_draw) + def unregister(): bpy.types.VIEW3D_MT_edit_mesh_extrude.remove(operator_draw) bpy.utils.unregister_class(Extrude_and_Reshape) + if __name__ == "__main__": register() |