def create_mesh(self,context,name="Sprite",width=100,height=100,pos=Vector((0,0,0))): me = bpy.data.meshes.new(name) me.show_double_sided = True obj = bpy.data.objects.new(name,me) context.scene.objects.link(obj) context.scene.objects.active = obj obj.select = True bpy.ops.object.mode_set(mode="EDIT") bm = bmesh.from_edit_mesh(me) vert1 = bm.verts.new(Vector((0,0,-height))*self.scale) vert2 = bm.verts.new(Vector((width,0,-height))*self.scale) vert3 = bm.verts.new(Vector((width,0,0))*self.scale) vert4 = bm.verts.new(Vector((0,0,0))*self.scale) bm.faces.new([vert1,vert2,vert3,vert4]) bmesh.update_edit_mesh(me) bpy.ops.object.mode_set(mode="OBJECT") obj.data.uv_textures.new("UVMap") set_uv_default_coords(context,obj) obj.location = Vector((pos[0],pos[1],-pos[2]))*self.scale + Vector((self.offset[0],self.offset[1],self.offset[2]))*self.scale obj["coa_sprite"] = True if self.parent != "None": obj.parent = bpy.data.objects[self.parent] return obj
def execute(self, context): obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() uv_layer = bm.loops.layers.uv.verify() if context.tool_settings.use_uv_select_sync: sel_faces = [f for f in bm.faces] else: sel_faces = [f for f in bm.faces if f.select] overlapped_info = common.get_overlapped_uv_info(bm, sel_faces, uv_layer, 'FACE') for info in overlapped_info: if context.tool_settings.use_uv_select_sync: info["subject_face"].select = True else: for l in info["subject_face"].loops: l[uv_layer].select = True bmesh.update_edit_mesh(obj.data) return {'FINISHED'}
def create_streets(offset_val): #grab selection, etc. mode("EDIT") mode("FACE") obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) for i in bm.faces: i.select = True #bevel out streets bpy.ops.mesh.bevel( offset_type = "WIDTH", offset = offset_val, clamp_overlap = True ) for i in bm.faces: if i.select: i.material_index = 1 bpy.ops.object.material_slot_assign else: i.material_index = 0 bpy.ops.object.material_slot_assign bpy.ops.object.material_slot_assign mode("EDIT") bmesh.update_edit_mesh(me)
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: sface = face break else: return {'FINISHED'} edges = set() for v in sface.verts: for ed in v.link_edges: edges.add(ed) edges = list(edges) bm_edges = self.bm.edges #bm_edges.difference_update(set_edges) set_edges, bm_edges = edges_BVH_overlap(edges, bm_edges, precision = 0.001) new_edges, targetmap = intersect_edges_edges(set_edges, bm_edges, precision = 4) if targetmap: bmesh.ops.weld_verts(self.bm, targetmap=targetmap) bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True) return {'FINISHED'} if self.cancel: return {'FINISHED'} self.cancel = event.type == 'ESC' self.confirm = event.type == 'LEFTMOUSE' return {'PASS_THROUGH'}
def main(self, context, chboxhide, chboxshow): obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) try: v1 = [v for v in bm.verts if (v.select == True and v.hide == False)] e1 = [e for e in bm.edges if (e.select == True and e.hide == False)] f1 = [f for f in bm.faces if (f.select == True and f.hide == False)] if len(v1) > 0 or len(e1) > 0 or f1 > 0: if chboxhide: bpy.ops.mesh.select_all(action='INVERT') bpy.ops.mesh.hide(unselected=False) bpy.ops.mesh.select_all(action='SELECT') elif chboxshow: bpy.ops.mesh.reveal() except: if chboxshow: bpy.ops.mesh.reveal() bmesh.update_edit_mesh(me, True)
def offset_profile(self, ob_edit, info_profile): me = ob_edit.data bm = bmesh.from_edit_mesh(me) if self.caches_valid and self._cache_offset_infos: offset_infos, edges_orig = self.get_caches(bm) else: offset_infos, edges_orig = self.get_offset_infos(bm, ob_edit) if offset_infos is False: return {'CANCELLED'} self.save_caches(offset_infos, edges_orig) ref_verts = [v for v, _, _ in offset_infos] edges = edges_orig for width, depth, _ in info_profile: exverts, exedges, _ = self.extrude_and_pairing(bm, edges, ref_verts) self.move_verts(bm, me, width * self.magni_w, depth * self.magni_d, offset_infos, exverts, update=False) ref_verts = exverts edges = exedges bm.normal_update() bmesh.update_edit_mesh(me) self.caches_valid = False return {'FINISHED'}
def modal(self, context, event): if event.type in {'LEFTMOUSE', 'MIDDLEMOUSE', 'RIGHTMOUSE', 'WHEELDOWNMOUSE', 'WHEELUPMOUSE', 'G', 'X', 'Y', 'Z', 'MOUSEMOVE'}: return {'PASS_THROUGH'} elif event.type in {'RET', 'NUMPAD_ENTER'}: del bpy.types.Scene.PreSelOff # Consolidate changes. for v in self.vsellist: v.select = True for e in self.esellist: e.select = True for f in self.fsellist: f.select = True self.bm.verts.remove(self.originvert) bmesh.update_edit_mesh(self.mesh, destructive=True) self.mesh.update() self.bm.free() self.snapelem = context.tool_settings.snap_element self.snapstate = context.tool_settings.use_snap context.tool_settings.snap_element = self.snapelsave context.tool_settings.use_snap = self.snapstsave bpy.ops.object.editmode_toggle() bpy.ops.object.origin_set(type='ORIGIN_CURSOR') self.space3d.cursor_location = self.cursorsave if self.mode == 'EDIT': bpy.ops.object.editmode_toggle() bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'FINISHED'} return {'RUNNING_MODAL'}
def modal_tweak_move_tool(self, context, eventd): if eventd['release'] in self.keymap['action']: return 'main' rgn,r3d = eventd['region'],eventd['r3d'] if eventd['type'] == 'MOUSEMOVE' and self.tweak_data: cx,cy = eventd['mouse'] lx,ly = self.tweak_data['mouse'] dx,dy = cx-lx,cy-ly dv = Vector((dx,dy)) imx = self.imx def update(p3d, d): if d >= 1.0: return p3d p2d = location_3d_to_region_2d(rgn, r3d, p3d) p2d += dv * (1.0-d) hit_p3d,_ = self.src_bmc.raycast_screen(p2d, rgn, r3d) return hit_p3d or p3d vertices = self.dest_bme.verts for i_v,c,d in self.tweak_data['lmverts']: nc = update(c,d) vertices[i_v].co = imx * nc bmesh.update_edit_mesh(self.dest_obj.data, tessface=True, destructive=False) self.tar_bmeshrender.dirty() return ''
def noise_obj(obj, context, self): bm = bmesh.from_edit_mesh(obj.data) verts = [v for v in bm.verts if v.select] if not verts: verts = [v for v in bm.verts if v.hide is False] for vert in verts: noise_pos = self.frequency * vert.co.copy() noise_pos.x += self.offset_x noise_pos.z += self.offset_y noise_pos.z += self.offset_z noise_val = None if self.noise_type == 'Turbulence': noise_val = mathu.noise.turbulence(noise_pos, self.octaves, self.hard, mathu.noise.types.STDPERLIN, self.amplitude_scale, self.frequency_scale) elif self.noise_type == 'Fractal': noise_val = mathu.noise.fractal(noise_pos, self.amplitude_scale, self.frequency_scale, self.octaves, mathu.noise.types.STDPERLIN) else: noise_val = mathu.noise.hetero_terrain(noise_pos, self.amplitude_scale, self.frequency_scale, self.octaves, 0, mathu.noise.types.STDPERLIN) vert_offset = vert.normal.copy().normalized() * noise_val vert.co += vert_offset * self.intensity bm.normal_update() bmesh.update_edit_mesh(obj.data)
def extend_vertex(): obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) verts = bm.verts faces = bm.faces plane = [f for f in faces if f.select][0] plane_vert_indices = [v for v in plane.verts[:]] all_selected_vert_indices = [v for v in verts if v.select] M = set(plane_vert_indices) N = set(all_selected_vert_indices) O = N.difference(M) O = list(O) (v1_ref, v1_idx, v1), (v2_ref, v2_idx, v2) = [(i, i.index, i.co) for i in O] plane_co = plane.calc_center_median() plane_no = plane.normal new_co = intersect_line_plane(v1, v2, plane_co, plane_no, False) new_vertex = verts.new(new_co) A_len = (v1 - new_co).length B_len = (v2 - new_co).length vertex_reference = v1_ref if (A_len < B_len) else v2_ref bm.edges.new([vertex_reference, new_vertex]) bmesh.update_edit_mesh(me, True)
def modal(self, context, event): op = context.window_manager.operators #print([o.name for o in op]) if op and op[-1].name == 'Translate': # print('-------------------') sface = self.bm.faces.active if not sface: for face in self.bm.faces: if face.select == True: sface = face break else: return {'FINISHED'} set_edges = set() for v in sface.verts: for ed in v.link_edges: set_edges.add(ed) bm_edges = set(self.bm.edges) # .difference_update(set_edges) bm_edges.difference_update(set_edges) set_edges, bm_edges = list_BVH(set_edges, bm_edges, precision=0.0001) new_edges, targetmap = intersect_edges_edges(set_edges, bm_edges) if targetmap: bmesh.ops.weld_verts(self.bm, targetmap=targetmap) bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True) return {'FINISHED'} if self.cancel: return {'FINISHED'} self.cancel = event.type == 'ESC' return {'PASS_THROUGH'}
def extrude_buildings(bm, me, height_min=.10, height_max=.25): extrude_buildings.roofs = [] #create array to put selected faces in bm_faces = [] for face in bm.faces[:]: face.select = False #select by criteria: plot index with certain area if face.material_index == 0: if face.calc_area() > (.01 * create_grid.size) and face.calc_area() < (0.3 * create_grid.size): bm_faces.append(face) #extrude geometry for face in bm_faces[:]: new_faces = bmesh.ops.extrude_face_region( bm, geom = [face]) #new face[0] is equal to the newly created geometry translated upwards new_face = [e for e in new_faces['geom'] if isinstance(e, bmesh.types.BMFace)] #get roofs for reference extrude_buildings.roofs.append(new_face[0]) #translate extrusion up bmesh.ops.translate( bm, vec = Vector((0, 0, uniform(height_min, height_max))), verts = new_face[0].verts ) bmesh.update_edit_mesh(bpy.context.object.data)
def mat_slot_assign(bm, me): for i in bm.faces[:]: #i.material_index = 0 <- Plot #i.material_index = 1 <- Streets #i.material_index = 2 <- Rivers if i.index in geo.rivers: i.select = True i.material_index = 2 bpy.ops.object.material_slot_assign i.select = False #i.material_index = 3 <- Buildings elif i in buildings.master_list: i.select = True i.material_index = 3 bpy.ops.object.material_slot_assign i.select = False #i.material_index = 4 <- Parks elif i.index in geo.parks: i.select = True i.material_index = 4 bpy.ops.object.material_slot_assign i.select = False #scrub materials that don't contain users for mat in bpy.data.materials: if not mat.users: bpy.data.materials.remove(mat) bmesh.update_edit_mesh(me)
def execute(self, context): self.report({'INFO'}, "Flip/Rotate UV") obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() # get UV layer uv_layer = _get_uv_layer(self, bm) if not uv_layer: return {'CANCELLED'} # get selected face src_info = _get_src_face_info(self, bm, [uv_layer], True) if not src_info: return {'CANCELLED'} face_count = len(src_info[list(src_info.keys())[0]]) self.report({'INFO'}, "{} face(s) are selected".format(face_count)) # paste ret = _paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N', self.flip, self.rotate, self.seams) if ret: return {'CANCELLED'} bmesh.update_edit_mesh(obj.data) if compat.check_version(2, 80, 0) < 0: if self.seams is True: obj.data.show_edge_seams = True return {'FINISHED'}
def main(context): obj = context.active_object me = obj.data bm = bmesh.from_edit_mesh(me) uv_layer = bm.loops.layers.uv.verify() bm.faces.layers.tex.verify() # currently blender needs both layers. # adjust UVs for f in bm.faces: norm = f.normal ax, ay, az = abs(norm.x), abs(norm.y), abs(norm.z) axis = -1 if ax > ay and ax > az: axis = 0 if ay > ax and ay > az: axis = 1 if az > ax and az > ay: axis = 2 for l in f.loops: luv = l[uv_layer] if axis == 0: # x plane luv.uv.x = l.vert.co.y luv.uv.y = l.vert.co.z if axis == 1: # u plane luv.uv.x = l.vert.co.x luv.uv.y = l.vert.co.z if axis == 2: # z plane luv.uv.x = l.vert.co.x luv.uv.y = l.vert.co.y bmesh.update_edit_mesh(me)
def modal(self, context, event): if event.type == 'INBETWEEN_MOUSEMOVE': return {'RUNNING_MODAL'} actob = context.active_object mat = actob.matrix_world bm = bmesh.from_edit_mesh(actob.data) bm.clear() bm.from_mesh(self.mesh) retval = self.modal_mouse.modal(context, event) if self.modal_mouse.orientation.orientation == 'GLOBAL': self.use_world_coords = True else: self.use_world_coords = False if retval == {'PASS_THROUGH'}: if event.value == 'PRESS': if event.type == 'E': ls = ['none', 'extrude', 'individual'] i = ls.index(self.extrude) self.extrude = ls[(i + 1) % 3] elif event.type == 'V': if self.use_even_offset_tangent: self.use_even_offset_tangent = False self.use_even_offset_normal = False else: self.use_even_offset_tangent = True self.use_even_offset_normal = True elif event.type == 'C': ls = ['all', 'selected', 'deselected', 'individual'] i = ls.index(self.normal_calculation) s = ls[(i + 1) % 4] self.tangent_calculation = ls[1] if s == 'all' else s self.normal_calculation = s result = self.modal_mouse.result translation = result['translation'] self.offset_tangent = translation[0] self.offset_normal = translation[1] self.execute(context) if event.type in ('SPACE', 'RET', 'NUMPAD_ENTER', 'LEFTMOUSE'): self.modal_mouse.draw_handler_remove(context) bpy.data.meshes.remove(self.mesh) context.area.tag_redraw() return {'FINISHED'} elif event.type in ('ESC', 'RIGHTMOUSE'): self.modal_mouse.draw_handler_remove(context) bm.clear() bm.from_mesh(self.mesh) bm.normal_update() bmesh.update_edit_mesh(actob.data, True, True) bpy.data.meshes.remove(self.mesh) context.area.tag_redraw() return {'FINISHED'} return {'RUNNING_MODAL'}
def execute(self, context): mesh = context.object.data bm = bmesh.from_edit_mesh(mesh) try: selection = bm.select_history[0] except: for face in bm.faces: if face.select == True: selection = face #else: #selection = None if not isinstance(selection, bmesh.types.BMFace): raise SelectionError('The selection is not a face') else: face = selection geom = [] for edge in face.edges: #print(edge.calc_face_angle()- 1.5707963267948966) if abs(edge.calc_face_angle(0) - 1.5707963267948966) < 0.001: geom.append(edge) dict = bmesh.ops.extrude_discrete_faces(bm, faces = [face]) bpy.ops.mesh.select_all(action='DESELECT') for face in dict['faces']: face.select = True bmesh.ops.dissolve_edges(bm, edges = geom, use_verts=True, use_face_split=False) bmesh.update_edit_mesh(mesh, tessface=True, destructive=True) bpy.ops.transform.translate('INVOKE_DEFAULT', constraint_axis=(False, False, True), constraint_orientation='NORMAL') return {'FINISHED'}
def align_uvs(context, influence): editor = bpy.context.area.spaces[0] gps = editor.grease_pencil.layers[-1].active_frame.strokes[-1].points obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) uv_layer = bm.loops.layers.uv.verify() bm.faces.layers.tex.verify() selected_uv_verts = [] for f in bm.faces: for l in f.loops: l_uv = l[uv_layer] if l_uv.select: selected_uv_verts.append(l_uv) selected_uv_verts_positions = [] for vert in selected_uv_verts: selected_uv_verts_positions.append(vert.uv) gpencil_points = [] for point in gps: gpencil_points.append(point.co) for i, v in enumerate(selected_uv_verts): nearest_point = get_nearest_interpolated_point_on_stroke(selected_uv_verts_positions[i], gpencil_points, context) # newcoord = obj.matrix_world.inverted() * region_to_location(nearest_point, obj.matrix_world * v.co) v.uv = v.uv.lerp(nearest_point, influence) bmesh.update_edit_mesh(me, True) if context.user_preferences.addons[__name__].preferences.clear_strokes: editor.grease_pencil.layers[-1].active_frame.clear()
def execute(self, context): self.init(context) ob = context.active_object bm = bmesh.from_edit_mesh(ob.data) # Add Layers layer = bm.verts.layers.int.new('at_shift_outline_extrude') for i, eve in enumerate(bm.verts): # 完全新規の頂点の値は0になるので、それと被らないように +1 eve[layer] = i + 1 layer_loop = bm.loops.layers.int.new('at_shift_outline_extrude') for i, efa in enumerate(bm.faces): for loop in efa.loops: loop[layer_loop] = i + 1 # Extrude if self.extrude == 'individual': # 面の選択状態を確保 selected_faces = [i for i, f in enumerate(bm.faces) if f.select] # 全ての面を非選択 for efa in bm.faces: efa.select = False # 頂点・辺のみ押し出し bpy.ops.mesh.extrude_region(False, mirror=False) # 頂点・辺の選択状態を確保 selected_verts = [i for i, v in enumerate(bm.verts) if v.select] selected_edges = [i for i, e in enumerate(bm.edges) if e.select] # 面再選択、押し出し bm.faces.ensure_lookup_table() for i in selected_faces: bm.faces[i].select = True bpy.ops.mesh.extrude_faces_indiv(False, mirror=False) # 頂点・辺を再選択 for i in selected_verts: bm.verts[i].select = True for i in selected_edges: bm.edges[i].select = True # select_flush_mode()はしなくても大丈夫か elif self.extrude == 'extrude': bpy.ops.mesh.extrude_region(False, mirror=False) # Translate self.execute_tangent(context, bm) self.execute_normal(context, bm) # Remove Layers bm.verts.layers.int.remove(layer) bm.loops.layers.int.remove(layer_loop) # Update bm.normal_update() bmesh.update_edit_mesh(ob.data, True, True) context.area.tag_redraw() return {'FINISHED'}
def execute(self, context): # final attempt to enter unfragmented bm/mesh # ghastly, but what can I do? it works with these # fails without. bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') obj = context.active_object me = obj.data bm = bmesh.from_edit_mesh(me) bm.verts.ensure_lookup_table() bm.edges.ensure_lookup_table() edges = [e for e in bm.edges if e.select and not e.hide] if len(edges) == 2: message = do_vtx_if_appropriate(bm, edges) if isinstance(message, set): msg = messages.get(message.pop()) return self.cancel_message(msg) bm = message else: return self.cancel_message('select two edges!') bm.verts.index_update() bm.edges.index_update() bmesh.update_edit_mesh(me, True) return {'FINISHED'}
def align_vertices(context, influence): # Object currently in edit mode. obj = bpy.context.edit_object # Object's mesh datablock. me = obj.data # Convert mesh data to bmesh. bm = bmesh.from_edit_mesh(me) # Get all selected vertices (in their local space). selected_verts = [v for v in bm.verts if v.select] verts_local_3d = [v.co for v in selected_verts] # Convert selected vertices' positions to 2D screen space. # IMPORTANT: Multiply vertex coordinates with the world matrix to get their WORLD position, not local position. verts_world_2d = vectors_to_screenpos(context, verts_local_3d, obj.matrix_world) # For each vert, look up or to the side and find the nearest interpolated gpencil point for this vertex. for i, v in enumerate(selected_verts): nearest_point = get_nearest_interpolated_point_on_stroke(verts_world_2d[i], gpencil_to_screenpos(context), context) # Get new vertex coordinate by converting from 2D screen space to 3D world space. Must multiply depth coordinate # with world matrix and then final result by INVERTED world matrix to get a correct final value. newcoord = obj.matrix_world.inverted() * region_to_location(nearest_point, obj.matrix_world * v.co) # Apply the final position using an influence slider. v.co = v.co.lerp(newcoord, influence) # Recalculate mesh normals (so lighting looks right). for edge in bm.edges: edge.normal_update() # Push bmesh changes back to the actual mesh datablock. bmesh.update_edit_mesh(me, True)
def cut_visible_by_perpendicular(self): obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) verts = [v for v in bm.verts if (v.select and not v.hide)] if not len(verts) == 2: msg = "select two vertices" self.report({"WARNING"}, msg) return {'CANCELLED'} v1, v2 = [v.co for v in verts] print('vectors found:\n', v1, '\n', v2) mid_vec = v1.lerp(v2, 0.5) plane_no = v2 - mid_vec plane_co = mid_vec dist = 0.0001 # hidden geometry will not be affected. visible_geom = [g for g in bm.faces[:] + bm.verts[:] + bm.edges[:] if not g.hide] bmesh.ops.bisect_plane( bm, geom=visible_geom, dist=dist, plane_co=plane_co, plane_no=plane_no, use_snap_center=False, clear_outer=False, clear_inner=False) bmesh.update_edit_mesh(me, True)
def draw_verts(self,context,obj): bm = bmesh.from_edit_mesh(obj.data) selected_verts_count = 0 for vert in bm.verts: if vert.select: selected_verts_count += 1 if selected_verts_count > 1: for vert in bm.verts: if vert.select: vert.select = False for face in bm.faces: if face.select: face.select = False for edge in bm.edges: if edge.select: edge.select = False bmesh.update_edit_mesh(obj.data) selected_vert = [] for vert in bm.verts: if vert.select: selected_vert.append(vert) new_vert = bm.verts.new(obj.matrix_world.inverted() * context.scene.cursor_location) new_vert.select = True if len(selected_vert) > 0: bm.edges.new([selected_vert[0],new_vert]) for vert in selected_vert: vert.select = False bmesh.update_edit_mesh(obj.data)
def clean_verts(bm,obj): ### find corrupted faces faces = [] for face in bm.faces: i = 0 for edge in face.edges: if not edge.is_manifold: i += 1 if i == len(face.edges): faces.append(face) bmesh.ops.delete(bm,geom=faces,context=5) edges = [] for face in bm.faces: i = 0 for vert in face.verts: if not vert.is_manifold and not vert.is_boundary: i+=1 if i == len(face.verts): for edge in face.edges: if edge not in edges: edges.append(edge) bmesh.ops.collapse(bm,edges=edges) bmesh.update_edit_mesh(obj.data) for vert in bm.verts: if not vert.is_boundary: vert.select = False verts = [] for vert in bm.verts: if len(vert.link_edges) in [3,4] and not vert.is_boundary: verts.append(vert) bmesh.ops.dissolve_verts(bm,verts=verts) bmesh.update_edit_mesh(obj.data)
def normal_fill(self,context): obj = context.active_object bpy.ops.mesh.edge_face_add() bpy.ops.uv.project_from_view(camera_bounds=False, correct_aspect=True, scale_to_bounds=True) self.reset_spritesheet(context,obj) bm = bmesh.from_edit_mesh(obj.data) unselected_faces = [] for face in bm.faces: if face.select == False: unselected_faces.append(face) face.select = True bpy.ops.uv.project_from_view(camera_bounds=False, correct_aspect=True, scale_to_bounds=True) for face in unselected_faces: face.select = False bmesh.update_edit_mesh(obj.data) self.revert_rest_spritesheet(context,obj)
def execute(self, context): mesh = bpy.context.active_object.data bm = bmesh.from_edit_mesh(mesh) face_normal_influence_layer = bm.faces.layers.int['face-normal-influence'] # Determine enumerated face normal influence value. face_normal_influence = self.face_influence_map[self.influence] # Select faces by given normal vector influence. if self.action == 'GET': context.tool_settings.mesh_select_mode = (False, False, True) for f in bm.faces: if f[face_normal_influence_layer] == face_normal_influence: f.select = True else: f.select = False bm.select_mode = {'FACE'} bm.select_flush_mode() # Assign given face normal influence to selected faces. elif self.action == 'SET' and mesh.total_face_sel: selected_faces = [f for f in bm.faces if f.select] for f in selected_faces: f[face_normal_influence_layer] = face_normal_influence # Update the mesh. bmesh.update_edit_mesh(mesh) if self.action == 'SET' and self.update: bpy.ops.mesh.yavne_update_vertex_normals() return {'FINISHED'}
def __init__(self): mesh = bpy.context.active_object.data bm = bmesh.from_edit_mesh(mesh) vert_float_layers = bm.verts.layers.float vert_int_layers = bm.verts.layers.int face_int_layers = bm.faces.layers.int # Reference addon. self.addon = bpy.context.user_preferences.addons[self.addon_key] # Ensure that the 'vertex-normal-weight' custom data layer exists. if not 'vertex-normal-weight' in vert_int_layers.keys(): vert_int_layers.new('vertex-normal-weight') # Ensure that the 'face-normal-influence' custom data layer exists. if not 'face-normal-influence' in face_int_layers.keys(): face_int_layers.new('face-normal-influence') # Ensure that vertex normal component layers exist. if not 'vertex-normal-x' in vert_float_layers.keys(): vert_float_layers.new('vertex-normal-x') if not 'vertex-normal-y' in vert_float_layers.keys(): vert_float_layers.new('vertex-normal-y') if not 'vertex-normal-z' in vert_float_layers.keys(): vert_float_layers.new('vertex-normal-z') # Update the mesh. bmesh.update_edit_mesh(mesh)
def main(self, context, chboxVert0, chboxVert1, chboxVert2): obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) vertices = [v for v in bm.verts if (v.select and not v.hide)] if not len(vertices) == 3: msg = "select ONLY 3 vertices" self.report({"WARNING"}, msg) return {'CANCELLED'} v1, v2, v3 = [v for v in vertices] if chboxVert0: corte(bm, v1, v2, v3) if chboxVert1: corte(bm, v2, v1, v3) if chboxVert2: corte(bm, v3, v1, v2) verticeje = v3.co else: print("Select 1 option") bmesh.update_edit_mesh(me, True)
def execute(self, context): mesh = context.object.data bm = bmesh.from_edit_mesh(mesh) # get or create color layer colors = bm.loops.layers.color.active if not colors: colors = bm.loops.layers.color.new("Col") # get Draw brush current color color = bpy.data.brushes["Draw"].color if tuple(bm.select_mode)[0] == 'FACE': # in face mode, assign colors to selected faces loops only (faces color) floops = [ l for f in bm.faces for l in f.loops if f.select ] for loop in floops: loop[colors] = color else: # assign colors to all loops connected to selected vertices (vertex color) vloops = [ l for v in bm.verts for l in v.link_loops if v.select ] for loop in vloops: loop[colors] = color bmesh.update_edit_mesh(mesh) return {'FINISHED'}
def SuccessFinished(me, startTime): #use for backtrack of steps #bpy.ops.ed.undo_push() bmesh.update_edit_mesh(me) #elapsed = round(time.clock()-startTime, 2) #if (elapsed >= 0.05): operator.report({'INFO'}, "UvSquares finished, elapsed:", elapsed, "s.") return
bm.faces.ensure_lookup_table() ## Deselect all and select the required faces bpy.ops.mesh.select_all(action = 'DESELECT') ## Select alternate faces for i in range(0, len(bm.faces)): if i % 2 == 0: bm.faces[i].select = True # select index 4 ## Show the updates in the viewport bmesh.update_edit_mesh(me, True) ## Extrude selected faces bpy.ops.mesh.extrude_region_move(MESH_OT_extrude_region={"use_normal_flip":False, "mirror":False}, TRANSFORM_OT_translate={"value":(0, 0, 0), "orient_type":'GLOBAL', "orient_matrix":((0, 0, 0), (0, 0, 0), (0, 0, 0)), "orient_matrix_type":'GLOBAL', "constraint_axis":(False, False, False), "mirror":False, "use_proportional_edit":False, "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "use_proportional_connected":False, "use_proportional_projected":False, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "cursor_transform":False, "texture_space":False, "remove_on_cancel":False, "release_confirm":False, "use_accurate":False}) ## Scaled the extruded part bpy.ops.transform.resize(value=(2, 2, 2), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False) ## Exit edit mode bpy.ops.object.editmode_toggle()
def execute(self, context): self.report({'INFO'}, "Flip/Rotate UV") obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() # get UV layer if not bm.loops.layers.uv: self.report({'WARNING'}, "Object must have more than one UV map") return {'CANCELLED'} uv_layer = bm.loops.layers.uv.verify() # get selected face dest_uvs = [] dest_pin_uvs = [] dest_seams = [] dest_face_indices = [] for face in bm.faces: if face.select: dest_face_indices.append(face.index) uvs = [l[uv_layer].uv.copy() for l in face.loops] pin_uvs = [l[uv_layer].pin_uv for l in face.loops] seams = [l.edge.seam for l in face.loops] dest_uvs.append(uvs) dest_pin_uvs.append(pin_uvs) dest_seams.append(seams) if not dest_uvs or not dest_pin_uvs: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} self.report({'INFO'}, "%d face(s) are selected" % len(dest_uvs)) # paste for idx, duvs, dpuvs, dss in zip(dest_face_indices, dest_uvs, dest_pin_uvs, dest_seams): duvs_fr = [uv for uv in duvs] dpuvs_fr = [pin_uv for pin_uv in dpuvs] dss_fr = [s for s in dss] # flip UVs if self.flip is True: duvs_fr.reverse() dpuvs_fr.reverse() dss_fr.reverse() # rotate UVs for _ in range(self.rotate): uv = duvs_fr.pop() pin_uv = dpuvs_fr.pop() s = dss_fr.pop() duvs_fr.insert(0, uv) dpuvs_fr.insert(0, pin_uv) dss_fr.insert(0, s) # paste UVs for l, duv, dpuv, ds in zip( bm.faces[idx].loops, duvs_fr, dpuvs_fr, dss_fr): l[uv_layer].uv = duv l[uv_layer].pin_uv = dpuv if self.seams is True: l.edge.seam = ds self.report({'INFO'}, "%d face(s) are flipped/rotated" % len(dest_uvs)) bmesh.update_edit_mesh(obj.data) if self.seams is True: obj.data.show_edge_seams = True return {'FINISHED'}
def make_line(self, bm_geom, location): obj = self.main_snap_obj.data[0] bm = self.main_bm split_faces = set() update_edit_mesh = False if bm_geom is None: vert = bm.verts.new(location) self.list_verts.append(vert) update_edit_mesh = True elif isinstance(bm_geom, bmesh.types.BMVert): if (bm_geom.co - location).length_squared < .001: if self.list_verts == [] or self.list_verts[-1] != bm_geom: self.list_verts.append(bm_geom) else: vert = bm.verts.new(location) self.list_verts.append(vert) update_edit_mesh = True elif isinstance(bm_geom, bmesh.types.BMEdge): self.list_edges.append(bm_geom) ret = intersect_point_line(location, bm_geom.verts[0].co, bm_geom.verts[1].co) if (ret[0] - location).length_squared < .001: if ret[1] == 0.0: vert = bm_geom.verts[0] elif ret[1] == 1.0: vert = bm_geom.verts[1] else: edge, vert = bmesh.utils.edge_split(bm_geom, bm_geom.verts[0], ret[1]) update_edit_mesh = True if self.list_verts == [] or self.list_verts[-1] != vert: self.list_verts.append(vert) self.geom = vert # hack to highlight in the drawing # self.list_edges.append(edge) else: # constrain point is near vert = bm.verts.new(location) self.list_verts.append(vert) update_edit_mesh = True elif isinstance(bm_geom, bmesh.types.BMFace): split_faces.add(bm_geom) vert = bm.verts.new(location) self.list_verts.append(vert) update_edit_mesh = True # draw, split and create face if len(self.list_verts) >= 2: v1, v2 = self.list_verts[-2:] edge = bm.edges.get([v1, v2]) if edge: self.list_edges.append(edge) else: if not v2.link_edges: edge = bm.edges.new([v1, v2]) self.list_edges.append(edge) else: # split face v1_link_faces = v1.link_faces v2_link_faces = v2.link_faces if v1_link_faces and v2_link_faces: split_faces.update(set(v1_link_faces).intersection(v2_link_faces)) else: if v1_link_faces: faces = v1_link_faces co2 = v2.co.copy() else: faces = v2_link_faces co2 = v1.co.copy() for face in faces: if bmesh.geometry.intersect_face_point(face, co2): co = co2 - face.calc_center_median() if co.dot(face.normal) < 0.001: split_faces.add(face) if split_faces: edge = bm.edges.new([v1, v2]) self.list_edges.append(edge) ed_list = get_loose_linked_edges(v2) for face in split_faces: facesp = bmesh.utils.face_split_edgenet(face, ed_list) del split_faces else: if self.intersect: facesp = bmesh.ops.connect_vert_pair(bm, verts=[v1, v2], verts_exclude=bm.verts) # print(facesp) if not self.intersect or not facesp['edges']: edge = bm.edges.new([v1, v2]) self.list_edges.append(edge) else: for edge in facesp['edges']: self.list_edges.append(edge) update_edit_mesh = True # create face if self.create_face: ed_list = set(self.list_edges) for edge in v2.link_edges: if edge not in ed_list and edge.other_vert(v2) in self.list_verts: ed_list.add(edge) break ed_list.update(get_loose_linked_edges(v2)) bmesh.ops.edgenet_fill(bm, edges=list(ed_list)) update_edit_mesh = True # print('face created') if update_edit_mesh: obj.data.update_gpu_tag() obj.data.update_tag() obj.update_from_editmode() obj.update_tag() bmesh.update_edit_mesh(obj.data) self.sctx.tag_update_drawn_snap_object(self.main_snap_obj) #bm.verts.index_update() bpy.ops.ed.undo_push(message="Undo draw line*") return [obj.matrix_world @ v.co for v in self.list_verts]
def align(self, context, type, axis, direction, orientation): active = context.active_object mx = active.matrix_world if orientation == 'LOCAL' else context.scene.cursor.matrix if orientation == 'CURSOR' else Matrix( ) mode = context.scene.M3.align_mode # in VIEW mode the axis is calculated from from viewport direction giving in the pie if mode == 'VIEW': axis_right, axis_up, flip_right, flip_up = get_right_and_up_axes( context, mx=mx) if type == 'MINMAX': axis = axis_right if direction in ['RIGHT', 'LEFT' ] else axis_up elif type in ['ZERO', 'AVERAGE', 'CURSOR']: axis = axis_right if direction == "HORIZONTAL" else axis_up bm = bmesh.from_edit_mesh(active.data) bm.normal_update() bm.verts.ensure_lookup_table() verts = [v for v in bm.verts if v.select] # axis coordinates in local space if orientation == 'LOCAL': axiscoords = [v.co[axis] for v in verts] # coordinates in world space elif orientation == 'WORLD': axiscoords = [(active.matrix_world @ v.co)[axis] for v in verts] # coordinates in cursor space elif orientation == 'CURSOR': axiscoords = [ (mx.inverted_safe() @ active.matrix_world @ v.co)[axis] for v in verts ] # get min or max target value if type == "MIN": target = min(axiscoords) elif type == "MAX": target = max(axiscoords) # min or max in VIEW mode elif type == 'MINMAX': if direction == 'RIGHT': target = min(axiscoords) if flip_right else max(axiscoords) elif direction == 'LEFT': target = max(axiscoords) if flip_right else min(axiscoords) elif direction == 'TOP': target = min(axiscoords) if flip_up else max(axiscoords) elif direction == 'BOTTOM': target = max(axiscoords) if flip_up else min(axiscoords) # get the zero target value elif type == "ZERO": target = 0 # get the average target value elif type == "AVERAGE": target = sum(axiscoords) / len(axiscoords) # get cursor target value elif type == "CURSOR": if orientation == 'LOCAL': c_world = context.scene.cursor.location c_local = mx.inverted() @ c_world target = c_local[axis] elif orientation == 'WORLD': target = context.scene.cursor.location[axis] elif orientation == 'CURSOR': target = 0 # set the new coordinates for v in verts: if orientation == 'LOCAL': v.co[axis] = target elif orientation == 'WORLD': # bring vertex coords into world space world_co = active.matrix_world @ v.co # set the target value world_co[axis] = target # bring it back into local space v.co = active.matrix_world.inverted_safe() @ world_co elif orientation == 'CURSOR': # bring vertex coords into cursor space cursor_co = mx.inverted_safe() @ active.matrix_world @ v.co # set the target value cursor_co[axis] = target # bring it back into local space v.co = active.matrix_world.inverted_safe() @ mx @ cursor_co bm.normal_update() bmesh.update_edit_mesh(active.data)
def center(self, context, axis, direction, orientation): active = context.active_object mx = active.matrix_world if orientation == 'LOCAL' else context.scene.cursor.matrix if orientation == 'CURSOR' else Matrix( ) mode = context.scene.M3.align_mode # calculate axis from viewport if mode == 'VIEW': axis_right, axis_up, flip_right, flip_up = get_right_and_up_axes( context, mx=mx) axis = axis_right if direction == "HORIZONTAL" else axis_up bm = bmesh.from_edit_mesh(active.data) bm.normal_update() bm.verts.ensure_lookup_table() verts = [v for v in bm.verts if v.select] # use the single vert's coordinate as the origin if len(verts) == 1: origin = verts[0].co # use the midpoint between two verts/one edge as the origin elif len(verts) == 2: origin = get_center_between_verts(*verts) # use the bounding box center as the origin else: _, origin = create_selection_bbox([v.co for v in verts]) # the target location will be the origin with the axis zeroed out if orientation == 'LOCAL': target = origin.copy() target[axis] = 0 # create translation matrix mxt = get_loc_matrix(target - origin) elif orientation == 'WORLD': # bring into world space origin = active.matrix_world @ origin target = origin.copy() target[axis] = 0 # create translation matrix (in local space again) mxt = get_loc_matrix( active.matrix_world.inverted().to_3x3() @ (target - origin)) elif orientation == 'CURSOR': # bring into cursor space origin = mx.inverted_safe() @ active.matrix_world @ origin target = origin.copy() target[axis] = 0 # create translation matrix (in local space again) mxt = get_loc_matrix(active.matrix_world.inverted().to_3x3() @ mx.to_3x3() @ (target - origin)) # move the selection for v in verts: v.co = mxt @ v.co bmesh.update_edit_mesh(active.data)
def __exit__(self, type, value, traceback): bmesh.update_edit_mesh(self.mesh)
def execute(self, context): props = context.scene.muv_props.cpuv_selseq if len(props.src_uvs) == 0 or len(props.src_pin_uvs) == 0: self.report({'WARNING'}, "Need copy UV at first") return {'CANCELLED'} if self.uv_map == "": self.report({'INFO'}, "Paste UV coordinate (selection sequence)") else: self.report( {'INFO'}, "Paste UV coordinate (selection sequence) (UV map:%s)" % (self.uv_map)) obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if muv_common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() # get UV layer if self.uv_map == "": if not bm.loops.layers.uv: self.report({'WARNING'}, "Object must have more than one UV map") return {'CANCELLED'} uv_layer = bm.loops.layers.uv.verify() else: uv_layer = bm.loops.layers.uv[self.uv_map] # get selected face dest_uvs = [] dest_pin_uvs = [] dest_seams = [] dest_face_indices = [] for hist in bm.select_history: if isinstance(hist, bmesh.types.BMFace) and hist.select: dest_face_indices.append(hist.index) uvs = [l[uv_layer].uv.copy() for l in hist.loops] pin_uvs = [l[uv_layer].pin_uv for l in hist.loops] seams = [l.edge.seam for l in hist.loops] dest_uvs.append(uvs) dest_pin_uvs.append(pin_uvs) dest_seams.append(seams) if len(dest_uvs) == 0 or len(dest_pin_uvs) == 0: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs): self.report( {'WARNING'}, "Number of selected faces is different from copied faces " + "(src:%d, dest:%d)" % (len(props.src_uvs), len(dest_uvs))) return {'CANCELLED'} # paste for i, idx in enumerate(dest_face_indices): suv = None spuv = None ss = None duv = None if self.strategy == 'N_N': suv = props.src_uvs[i] spuv = props.src_pin_uvs[i] ss = props.src_seams[i] duv = dest_uvs[i] elif self.strategy == 'N_M': suv = props.src_uvs[i % len(props.src_uvs)] spuv = props.src_pin_uvs[i % len(props.src_pin_uvs)] ss = props.src_seams[i % len(props.src_seams)] duv = dest_uvs[i] if len(suv) != len(duv): self.report({'WARNING'}, "Some faces are different size") return {'CANCELLED'} suvs_fr = [uv for uv in suv] spuvs_fr = [pin_uv for pin_uv in spuv] ss_fr = [s for s in ss] # flip UVs if self.flip_copied_uv is True: suvs_fr.reverse() spuvs_fr.reverse() ss_fr.reverse() # rotate UVs for _ in range(self.rotate_copied_uv): uv = suvs_fr.pop() pin_uv = spuvs_fr.pop() s = ss_fr.pop() suvs_fr.insert(0, uv) spuvs_fr.insert(0, pin_uv) ss_fr.insert(0, s) # paste UVs for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr, spuvs_fr, ss_fr): l[uv_layer].uv = suv l[uv_layer].pin_uv = spuv if self.copy_seams is True: l.edge.seam = ss self.report({'INFO'}, "%d face(s) are copied" % len(dest_uvs)) bmesh.update_edit_mesh(obj.data) if self.copy_seams is True: obj.data.show_edge_seams = True return {'FINISHED'}
def adapt(self, event): global started def removecaps(): self.capped = False for posn in range(len(self.vertlist)): for [e1, e2, v1, v2, fj, fo1, fo2] in self.caplist[posn]: if e1 == None: continue bmesh.utils.face_split(fj, v1, v2) templ = [] for f in e1.link_faces: templ.append(f) bmesh.utils.face_join(templ) templ = [] for f in e2.link_faces: templ.append(f) bmesh.utils.face_join(templ) self.mesh.calc_tessface() if self.mbns == 0: if self.Cap != self.oldcap: if self.dist != 0: self.mbns = 2 if self.Cap == True: self.capped = False else: removecaps() self.oldcap = self.Cap if self.Both != self.oldboth: if self.dist != 0: # enter edge-building through the backdoor to instantaneously show both inserts self.mbns = 2 if self.Both == True: # if just set for posn in range(len(self.vertlist)): if self.negsubd[posn]: self.possubd[posn] = False if self.possubd[posn]: self.negsubd[posn] = False else: if self.capped: self.capped = False removecaps() # if just unset: remove one side of edges if self.dist < 0: for posn in range(len(self.vertlist)): bpy.ops.mesh.select_all(action='DESELECT') for vert in self.dissverts2[posn]: vert.select = True for edge in self.dissedges2[posn]: edge.select = True bpy.ops.mesh.dissolve_edges(use_verts=True) self.mesh.calc_tessface() for vert in self.dissverts1[posn]: vert.select = True for edge in self.dissedges1[posn]: edge.select = True self.possubd[posn] = False self.railedges2[posn] = [] self.railverts2[posn] = [] self.dissverts2[posn] = [] self.dissedges2[posn] = [] if self.dist >= 0: for posn in range(len(self.vertlist)): if self.railedges1[posn] != []: bpy.ops.mesh.select_all(action='DESELECT') for vert in self.dissverts1[posn]: vert.select = True for edge in self.dissedges1[posn]: edge.select = True bpy.ops.mesh.dissolve_edges(use_verts=True) self.mesh.calc_tessface() for vert in self.dissverts2[posn]: vert.select = True for edge in self.dissedges2[posn]: edge.select = True self.negsubd[posn] = False self.railedges1[posn] = [] self.railverts1[posn] = [] self.dissverts1[posn] = [] self.dissedges1[posn] = [] for vert in self.vertlist[posn]: vert.select = True for edge in self.edgelist[posn]: edge.select = True self.oldboth = self.Both self.dist = self.Distance if self.dist != self.olddist: self.mbns = 2 self.olddist = self.dist else: if self.mbns != 2: if event != None: # do mouse handling left-right mx = event.mouse_region_x mean = max(-1 * self.meanmin, self.meanmax) self.dist = self.basev + ((mx - self.basex) / 200) * mean self.Distance = self.dist self.distset = True else: self.mbns = 0 # dont do anything if zero - removing edges will be handled once exiting with ENTER if self.Distance == 0: return #negative side handling if self.dist < 0 or self.Both == True: for posn in range(len(self.vertlist)): if not (self.negsubd[posn]): if self.Both == False: # if just switched sides: remove positive side if self.possubd[posn] == True: bpy.ops.mesh.select_all(action='DESELECT') for vert in self.dissverts2[posn]: vert.select = True for edge in self.dissedges2[posn]: edge.select = True self.mesh.update() bpy.ops.mesh.dissolve_edges( use_verts=True, use_face_split=False) self.railedges2[posn] = [] self.railverts2[posn] = [] self.dissverts2[posn] = [] self.dissedges2[posn] = [] bpy.ops.mesh.select_all(action='DESELECT') self.possubd[posn] = False self.railedges1[posn] = [] self.railverts1[posn] = [] self.dissverts1[posn] = [] self.dissedges1[posn] = [] for posn in range(len(self.vertlist)): if not (self.negsubd[posn]): self.negsubd[posn] = True # if just switched sides: look for slide constellations for i, vert in enumerate(self.vertlist[posn]): if i == len(self.vertlist[posn]) - 1: break for loop in vert.link_loops: if loop.link_loop_next.vert == self.vertlist[ posn][i + 1]: self.railverts1[posn].append( loop.link_loop_prev.vert) e = loop.link_loop_prev.edge self.railedges1[posn].append(e) if self.vertlist[posn].index(vert) == len( self.vertlist[posn]) - 2: self.railverts1[posn].append( loop.link_loop_next.link_loop_next. vert) e = loop.link_loop_next.edge self.railedges1[posn].append(e) if self.railedges1[posn] != []: # insert parallel edges prev = None popout = False for idx in range(len(self.railedges1[posn])): if popout: break edge = self.railedges1[posn][idx] if idx == len( self.railedges1[posn] ) - 1 and self.railverts1[posn][ 0] == self.railverts1[posn][ len(self.railverts1[posn]) - 1]: # this handles closed edgeloops vert = startvert self.railedges1[posn].pop( len(self.railedges1[posn]) - 1) self.railverts1[posn].pop( len(self.railverts1[posn]) - 1) popout = True else: dummy, vert = bmesh.utils.edge_split( edge, self.vertlist[posn][ self.railedges1[posn].index(edge)], 0.5) if idx == 0: startvert = vert self.dissverts1[posn].append(vert) if not (prev == None): e = bmesh.ops.connect_verts( self.bm, verts=[vert, prev]) self.dissedges1[posn].append(e['edges'][0]) prev = vert self.mesh.calc_tessface() # select inserted edges/verts for posn in range(len(self.vertlist)): for v in self.dissverts1[posn]: v.select = True for e in self.dissedges1[posn]: e.select = True # do distance shifting for posn in range(len(self.vertlist)): if self.railedges1[posn] != []: for v in self.vertlist[posn]: pv = self.dissverts1[posn][self.vertlist[posn].index( v)] rv = self.railverts1[posn][self.vertlist[posn].index( v)] sv = self.bmundo.verts[v.index] vec = rv.co - sv.co vec.length = abs(self.dist) pv.co = sv.co + vec #positive side handling if self.dist > 0 or self.Both == True: for posn in range(len(self.vertlist)): if not (self.possubd[posn]): if self.Both == False: # if just switched sides: remove positive side if self.negsubd[posn] == True: bpy.ops.mesh.select_all(action='DESELECT') for vert in self.dissverts1[posn]: vert.select = True for edge in self.dissedges1[posn]: edge.select = True bpy.ops.mesh.dissolve_edges( use_verts=True, use_face_split=False) self.railedges1[posn] = [] self.railverts1[posn] = [] self.dissverts1[posn] = [] self.dissedges1[posn] = [] bpy.ops.mesh.select_all(action='DESELECT') self.negsubd[posn] = False self.railedges2[posn] = [] self.railverts2[posn] = [] self.dissverts2[posn] = [] self.dissedges2[posn] = [] for posn in range(len(self.vertlist)): if not (self.possubd[posn]): # if just switched sides: look for slide constellations for i, vert in enumerate(self.vertlist[posn]): if (i == len(self.vertlist[posn]) - 1) or (i > 0 and vert == self.vertlist[posn][0]): break for loop in vert.link_loops: if loop.link_loop_prev.vert == self.vertlist[ posn][i + 1]: self.railverts2[posn].append( loop.link_loop_next.vert) e = loop.edge self.railedges2[posn].append(e) if self.vertlist[posn].index(vert) == len( self.vertlist[posn]) - 2: self.railverts2[posn].append( loop.link_loop_prev.link_loop_prev. vert) e = loop.link_loop_prev.link_loop_prev.edge self.railedges2[posn].append(e) for posn in range(len(self.vertlist)): if not (self.possubd[posn]): self.possubd[posn] = True if self.railedges2[posn] != []: # insert parallel edges prev = None popout = False for idx in range(len(self.railedges2[posn])): if popout: break edge = self.railedges2[posn][idx] if idx == len( self.railedges2[posn] ) - 1 and self.railverts2[posn][ 0] == self.railverts2[posn][ len(self.railverts2[posn]) - 1]: # this handles closed edgeloops vert = startvert self.railedges2[posn].pop( len(self.railedges2[posn]) - 1) self.railverts2[posn].pop( len(self.railverts2[posn]) - 1) popout = True else: dummy, vert = bmesh.utils.edge_split( edge, self.vertlist[posn][ self.railedges2[posn].index(edge)], 0.5) if idx == 0: startvert = vert self.dissverts2[posn].append(vert) if not (prev == None): e = bmesh.ops.connect_verts( self.bm, verts=[vert, prev]) self.dissedges2[posn].append(e['edges'][0]) prev = vert prevedge = edge self.mesh.calc_tessface() # select inserted edges/verts for posn in range(len(self.vertlist)): for v in self.dissverts2[posn]: v.select = True for e in self.dissedges2[posn]: e.select = True # do distance shifting for posn in range(len(self.vertlist)): if self.railedges2[posn] != []: for v in self.vertlist[posn]: pv = self.dissverts2[posn][self.vertlist[posn].index( v)] rv = self.railverts2[posn][self.vertlist[posn].index( v)] sv = self.bmundo.verts[v.index] vec = rv.co - sv.co vec.length = abs(self.dist) pv.co = sv.co + vec # create cap if not (self.capped): self.capsellist = [] for posn in range(len(self.vertlist)): if self.Both and self.Cap: self.capped = True def capendpoint(i): self.capedges = [] es1 = None es2 = None vert = self.vertlist[posn][i] for e in vert.link_edges: v = e.other_vert(vert) if not (v in self.vertlist[posn]) and not ( v in self.dissverts1[posn]) and not ( v in self.dissverts2[posn]): self.capedges.append(e) if len(self.capedges) == 1: e = self.capedges[0] for f in e.link_faces: v2 = e.other_vert(vert) v2.select = True if self.dissverts1[posn][i] in f.verts: f1, l1 = bmesh.utils.face_split( f, v2, self.dissverts1[posn][i]) if e in f.edges: fj1 = f fo1 = f1 else: fj1 = f1 fo1 = f for es in v2.link_edges: if es.other_vert( v2 ) == self.dissverts1[posn][i]: es.select = True es1 = es elif self.dissverts2[posn][i] in f.verts: f2, l1 = bmesh.utils.face_split( f, v2, self.dissverts2[posn][i]) if e in f.edges: fj2 = f fo2 = f2 else: fj2 = f2 fo2 = f for es in v2.link_edges: if es.other_vert( v2 ) == self.dissverts2[posn][i]: es.select = True es2 = es f3 = bmesh.utils.face_join((fj1, fj2)) if es1 == None: self.caplist[posn].append( (None, None, None, None, None, None, None)) else: self.caplist[posn].append( (es1, es2, vert, v2, f3, fo1, fo2)) self.capsellist.append(es1) self.capsellist.append(es2) self.caplist[posn] = [] capendpoint(0) capendpoint(-1) self.mesh.calc_tessface() # select original verts/edges for posn in range(len(self.vertlist)): for edge in self.edgelist[posn]: edge.select = True for vert in self.vertlist[posn]: vert.select = True bmesh.update_edit_mesh(self.mesh, destructive=True) self.mesh.update()
def uv_checkforerrors(self, context, node): if node.type == "MESH": if (node.data is not None): #os.system("cls") mesh = node.data bm = bmesh.from_edit_mesh(mesh) bm.select_mode = {"VERT"} #bm.select_mode = {"VERT"} bm.select_flush(False) uv_layer = bm.loops.layers.uv.active uv_errors = [] for face in bm.faces: for loop in face.loops: vert = loop.vert vert.select_set(False) #loop.select(False) #print(" Vert: (%f,%f,%f)" % vert.co[:]) uv_loop = loop[uv_layer] uv = uv_loop.uv #print(" UV: %f, %f" % uv[:]) ux = uv[0] uy = uv[1] for checkloop in face.loops: if checkloop == loop: break vert2 = checkloop.vert checkuv_loop = checkloop[uv_layer] checkuv = checkuv_loop.uv if self.uv_error(vert, vert2, uv, checkuv): uv_error_entry = LLUVHelpers_TriangleError( vert, vert2, uv_loop, checkuv_loop) uv_errors.append(uv_error_entry) total_errors = len(uv_errors) if total_errors > 0: can_select = True for uv_error in uv_errors: print("[ERROR]: UV problem detected!") print(" Vert1: (%f,%f,%f)" % uv_error.vert1.co[:]) print(" Vert2: (%f,%f,%f)" % uv_error.vert2.co[:]) print(" UV1: (%f,%f)" % uv_error.loop1.uv[:]) print(" UV2: (%f,%f)" % uv_error.loop2.uv[:]) if can_select: uv_error.vert1.select_set(True) uv_error.vert2.select_set(True) uv_error.loop1.select = True uv_error.loop2.select = True if self.select_all == False: can_select = False self.report({ "WARNING" }, "[LL-UV-Helper] {} total problems found on UV map. Check selected vertices for wrapping issues." .format(total_errors)) else: self.report({"INFO"}, "[LL-UV-Helper] No UV problems found.") bm.select_flush(True) bmesh.update_edit_mesh(mesh)
def execute(self, context): mortise_properties = context.scene.woodwork.mortise_properties thickness_properties = mortise_properties.thickness_properties height_properties = mortise_properties.height_properties obj = context.object matrix_world = obj.matrix_world mesh = obj.data if mesh.is_editmode: # Gain direct access to the mesh bm = bmesh.from_edit_mesh(mesh) else: # Create a bmesh from mesh # (won't affect mesh, unless explicitly written back) bm = bmesh.new() bm.from_mesh(mesh) # Get active face faces = bm.faces face = faces.active # Check if face could be transformed to mortise ... if not self.__check_face(face): return {'CANCELLED'} # Extract face infos face_to_be_transformed = FaceToBeTransformed(face) face_to_be_transformed.extract_features(matrix_world) # Init default values, look if face has changed too if (thickness_properties.value == -1.0 or (not MathUtils.almost_equal_relative_or_absolute( face_to_be_transformed.shortest_length, self.shortest_length))): thickness_properties.value = \ face_to_be_transformed.shortest_length / 3.0 thickness_properties.percentage = 1.0 / 3.0 thickness_properties.centered = True if (height_properties.value == -1.0 or (not MathUtils.almost_equal_relative_or_absolute( face_to_be_transformed.longest_length, self.longest_length))): height_properties.value = (face_to_be_transformed.longest_length * 2.0) / 3.0 height_properties.percentage = 2.0 / 3.0 height_properties.centered = True if (mortise_properties.depth_value == -1.0 or (not MathUtils.almost_equal_relative_or_absolute( face_to_be_transformed.longest_length, self.longest_length))): mortise_properties.depth_value = \ face_to_be_transformed.shortest_length haunch_properties = height_properties.haunch_first_side haunch_properties.depth_value = \ mortise_properties.depth_value / 3.0 haunch_properties.depth_percentage = 1.0 / 3.0 haunch_properties = height_properties.haunch_second_side haunch_properties.depth_value = \ mortise_properties.depth_value / 3.0 haunch_properties.depth_percentage = 1.0 / 3.0 haunch_properties = thickness_properties.haunch_first_side haunch_properties.depth_value = \ mortise_properties.depth_value / 3.0 haunch_properties.depth_percentage = 1.0 / 3.0 haunch_properties = thickness_properties.haunch_second_side haunch_properties.depth_value = \ mortise_properties.depth_value / 3.0 haunch_properties.depth_percentage = 1.0 / 3.0 # used to reinit default values when face changes self.shortest_length = face_to_be_transformed.shortest_length self.longest_length = face_to_be_transformed.longest_length # If percentage specified, compute length values if thickness_properties.type == "percentage": thickness_properties.value = \ face_to_be_transformed.shortest_length * \ thickness_properties.percentage if height_properties.type == "percentage": height_properties.value = face_to_be_transformed.longest_length * \ height_properties.percentage # Init values linked to shoulder size if thickness_properties.centered: thickness_properties.shoulder_value = ( (face_to_be_transformed.shortest_length - thickness_properties.value) / 2.0) thickness_properties.shoulder_percentage = \ thickness_properties.shoulder_value / \ face_to_be_transformed.shortest_length if height_properties.centered: height_properties.shoulder_value = ( (face_to_be_transformed.longest_length - height_properties.value) / 2.0) height_properties.shoulder_percentage = \ height_properties.shoulder_value / \ face_to_be_transformed.longest_length # If shoulder percentage specified, compute length values if thickness_properties.shoulder_type == "percentage": thickness_properties.shoulder_value = \ face_to_be_transformed.shortest_length * \ thickness_properties.shoulder_percentage if thickness_properties.type != "max": if (thickness_properties.shoulder_value + thickness_properties.value > face_to_be_transformed.shortest_length): thickness_properties.value = \ face_to_be_transformed.shortest_length - \ thickness_properties.shoulder_value thickness_properties.percentage =\ thickness_properties.value / \ face_to_be_transformed.shortest_length if height_properties.shoulder_type == "percentage": height_properties.shoulder_value = \ face_to_be_transformed.longest_length * \ height_properties.shoulder_percentage if height_properties.type != "max": if (height_properties.shoulder_value + height_properties.value > face_to_be_transformed.longest_length): height_properties.value = \ face_to_be_transformed.longest_length - \ height_properties.shoulder_value height_properties.percentage = \ height_properties.value / \ face_to_be_transformed.longest_length if height_properties.haunched_first_side: haunch_properties = height_properties.haunch_first_side if haunch_properties.type == "percentage": haunch_properties.depth_value = \ mortise_properties.depth_value * \ haunch_properties.depth_percentage if height_properties.haunched_second_side: haunch_properties = height_properties.haunch_second_side if haunch_properties.type == "percentage": haunch_properties.depth_value = \ mortise_properties.depth_value * \ haunch_properties.depth_percentage if thickness_properties.haunched_first_side: haunch_properties = thickness_properties.haunch_first_side if haunch_properties.type == "percentage": haunch_properties.depth_value = \ mortise_properties.depth_value * \ haunch_properties.depth_percentage if thickness_properties.haunched_second_side: haunch_properties = thickness_properties.haunch_second_side if haunch_properties.type == "percentage": haunch_properties.depth_value = \ mortise_properties.depth_value * \ haunch_properties.depth_percentage # Check input values if height_properties.type != "max": total_length = height_properties.shoulder_value + \ height_properties.value elif height_properties.centered: total_length = face_to_be_transformed.longest_length else: total_length = height_properties.shoulder_value if ((not MathUtils.almost_equal_relative_or_absolute( total_length, face_to_be_transformed.longest_length)) and (total_length > face_to_be_transformed.longest_length)): self.report({'ERROR_INVALID_INPUT'}, "Size of length size shoulder and mortise height are " "too long.") return {'CANCELLED'} if thickness_properties.type != "max": total_length = thickness_properties.shoulder_value + \ thickness_properties.value elif thickness_properties.centered: total_length = face_to_be_transformed.shortest_length else: total_length = thickness_properties.shoulder_value if ((not MathUtils.almost_equal_relative_or_absolute( total_length, face_to_be_transformed.shortest_length)) and (total_length > face_to_be_transformed.shortest_length)): self.report( {'ERROR_INVALID_INPUT'}, "Size of width size shoulder and mortise thickness are " "too long.") return {'CANCELLED'} # Create mortise builder_properties = \ MortiseOperator.__mortise_properties_to_builder_properties( mortise_properties) mortise_builder = TenonMortiseBuilder(builder_properties) mortise_builder.create(bm, matrix_world, face_to_be_transformed) # Flush selection bm.select_flush_mode() if mesh.is_editmode: bmesh.update_edit_mesh(mesh) else: bm.to_mesh(mesh) mesh.update() return {'FINISHED'}
def Duplicate(self, context, act_obj): """Create 2 copy selection. the firs orygnal posisiton. the second modifi""" main_select_obj = bpy.context.selected_objects object_B = firstD(context) print(object_B) bm = bmesh.from_edit_mesh(act_obj.data) face = [f for f in bm.faces if f.select] # get select faces angle = 0.0 save_pos = {} distance = -0.000002 for i in face:#?? ?????? for edge in i.edges:# ?? ?????? ??? ????? angle = edge.calc_face_angle_signed()# ??????? ???? angle = degrees(angle)# ????????? ???? ? ???????????? ??? if angle > 89.99:# ???? 90 ????????1 vert1, vert2 = edge.verts# ??????? ??????? ???? ???????? if not vert1.index in save_pos: save_pos[vert1.index] = vert1.co.copy() if not vert2.index in save_pos: save_pos[vert2.index] = vert2.co.copy() # ??????? ???? ?????, ??? ?????? ??????? ?????, ???? ????? ???? ??? ??? ?????? link1 = vert1.link_edges link2 = vert2.link_edges for l in link1: for e in i.edges: if l == e and not l == edge: V1, V2 = l.verts vec = V2.co #if V1 == vert1: vec = V2.co - V1.co if V2 == vert1: vec = V1.co - V2.co vec.normalize() vert1.co += vec * distance for l in link2: for e in i.edges: if l == e and not l == edge: V1, V2 = l.verts vec = V2.co if V1 == vert2: vec = V2.co - V1.co if V2 == vert2: vec = V1.co - V2.co vec.normalize() vert2.co += vec * distance bpy.ops.mesh.duplicate_move(MESH_OT_duplicate={"mode": 1}) bm.verts.ensure_lookup_table() for key, value in save_pos.items(): bm.verts[key].co = value bmesh.update_edit_mesh(act_obj.data) bm.free() bpy.ops.mesh.separate(type='SELECTED') bpy.ops.object.mode_set(mode='OBJECT') sel_obj = bpy.context.selected_objects object_C = None object_C_Name = None for i in sel_obj: object_C_Name = i.name object_C = i break for i in main_select_obj: i.select = True print(object_B) print(object_C) return object_B, object_C
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 is True: sface = face break else: return {'FINISHED'} # edges to intersect 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]) """ new_edges1, new_edges2, targetmap = intersect_edges_edges(overlap) pos_weld = set() for e in new_edges1: v1, v2 = e.verts if v1 in targetmap and v2 in targetmap: 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() """ for e in pos_weld: v1, v2 = e lf1 = set(v1.link_faces) lf2 = set(v2.link_faces) rlfe = lf1.intersection(lf2) for f in rlfe: try: nf = bmesh.utils.face_split(f, v1, v2) # sp_faces1.update({f, nf[0]}) except: pass # sp_faces2 = set() for e in new_edges2: lfe = set(e.link_faces) v1, v2 = e.verts lf1 = set(v1.link_faces) lf2 = set(v2.link_faces) rlfe = lf1.intersection(lf2) for f in rlfe.difference(lfe): nf = bmesh.utils.face_split(f, v1, v2) # sp_faces2.update({f, nf[0]}) bmesh.update_edit_mesh(self.mesh, tessface=True, destructive=True) return {'FINISHED'} if self.cancel: return {'FINISHED'} self.cancel = event.type in {'ESC', 'NDOF_BUTTON_ESC'} self.confirm = event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER'} return {'PASS_THROUGH'}
def invoke(self, context, event): reset_params(self) if context.area.type == 'VIEW_3D': # the arguments we pass the the callbackection args = (self, context) # Add the region OpenGL drawing callback # draw in view space with 'POST_VIEW' and 'PRE_VIEW' cur_stretch_settings = context.scene.mi_cur_stretch_settings curve_settings = context.scene.mi_settings active_obj = context.scene.objects.active bm = bmesh.from_edit_mesh(active_obj.data) # get loops self.loops = loop_t.get_connected_input(bm) self.loops = loop_t.check_loops(self.loops, bm) if self.loops: self.manipulator = context.space_data.show_manipulator context.space_data.show_manipulator = False for loop in self.loops: loop_verts = [active_obj.matrix_world * bm.verts[i].co for i in loop[0]] loop_line = cur_main.pass_line(loop_verts, loop[1]) new_curve = cur_main.create_curve_to_line(cur_stretch_settings.points_number, loop_line, self.all_curves, loop[1]) # set closed curve if loop[1] is True: new_curve.closed = True self.all_curves.append(new_curve) self.active_curve = new_curve cur_main.generate_bezier_points(self.active_curve, self.active_curve.display_bezier, curve_settings.curve_resolution) self.original_verts_data.append( cur_main.pass_line([bm.verts[i].co.copy() for i in loop[0]] , loop[1]) ) # move point to the curve for curve in self.all_curves: update_curve_line(active_obj, curve, self.loops, self.all_curves, bm, curve_settings.spread_mode, self.original_verts_data[self.all_curves.index(curve)]) # get meshes for snapping if curve_settings.surface_snap is True: meshes_array = ut_base.get_obj_dup_meshes(curve_settings.snap_objects, curve_settings.convert_instances, context) if meshes_array: self.picked_meshes = meshes_array self.mi_deform_handle_3d = bpy.types.SpaceView3D.draw_handler_add(mi_curve_draw_3d, args, 'WINDOW', 'POST_VIEW') self.mi_deform_handle_2d = bpy.types.SpaceView3D.draw_handler_add(mi_curve_draw_2d, args, 'WINDOW', 'POST_PIXEL') self.gh_circle_select_handle = bpy.types.SpaceView3D.draw_handler_add(gh_circle_draw_2d, args, 'WINDOW', 'POST_PIXEL') context.window_manager.modal_handler_add(self) bm.normal_update() bmesh.update_edit_mesh(active_obj.data) return {'RUNNING_MODAL'} else: #finish_work(self, context) self.report({'WARNING'}, "No loops found!") return {'CANCELLED'} else: #finish_work(self, context) self.report({'WARNING'}, "View3D not found, cannot run operator!") return {'CANCELLED'}
def uv_checkforerrors_v2(self, context, node): if node.type == "MESH": if (node.data is not None): preferences = leader.get_preferences(context) if preferences is not None: select_mode = preferences.uvhelpers_errorchecker_select_mode else: select_mode = "VERTEX" if select_mode == "FACE": bpy.context.tool_settings.mesh_select_mode = (False, False, True) elif select_mode == "EDGE": bpy.context.tool_settings.mesh_select_mode = (False, True, False) else: bpy.context.tool_settings.mesh_select_mode = (True, False, False) #py.context.tool_settings.mesh_select_mode = (False, False, True) mesh = node.data bm = bmesh.from_edit_mesh(mesh) bm.select_flush(False) uv_layer = bm.loops.layers.uv.active uv_errors = [] for face in bm.faces: if face in uv_errors: continue face.select = False if (len(face.loops) == 3): vloop1 = face.loops[0] vloop2 = face.loops[1] vloop3 = face.loops[2] vert1 = vloop1.vert vert2 = vloop2.vert vert3 = vloop3.vert vert1.select_set(False) vert2.select_set(False) vert3.select_set(False) uvloop1 = vloop1[uv_layer] uvloop2 = vloop2[uv_layer] uvloop3 = vloop3[uv_layer] uv1 = uvloop1.uv uv2 = uvloop2.uv uv3 = uvloop3.uv #uv1 = vert1.co.xy #uv2 = vert2.co.xy #uv3 = vert3.co.xy if self.uv_error_v2(uv1, uv2, uv3): uv_error_entry = LLUVHelpers_TriangleErrorv2( face, vert1, vert2, vert3, uvloop1, uvloop2, uvloop3) uv_errors.append(uv_error_entry) total_errors = len(uv_errors) if total_errors > 0: can_select = True select_all = preferences is not None and preferences.uvhelpers_errorchecker_select_all is True for uv_error in uv_errors: print("[ERROR]: UV problem detected!") print(" Vert1: (%f,%f,%f)" % uv_error.vert1.co[:]) print(" Vert2: (%f,%f,%f)" % uv_error.vert2.co[:]) print(" Vert3: (%f,%f,%f)" % uv_error.vert3.co[:]) print(" UV1: (%f,%f)" % uv_error.loop1.uv[:]) print(" UV2: (%f,%f)" % uv_error.loop2.uv[:]) print(" UV3: (%f,%f)" % uv_error.loop3.uv[:]) if can_select: uv_error.vert1.select_set(True) uv_error.vert2.select_set(True) uv_error.vert3.select_set(True) uv_error.loop1.select = True uv_error.loop2.select = True uv_error.loop3.select = True if select_all == False: can_select = False break self.report({ "WARNING" }, "[LL-UV-Helper] {} total problems found on UV map. Check selected vertices for wrapping issues." .format(total_errors)) else: self.report({"INFO"}, "[LL-UV-Helper] No UV problems found.") #total_errors.clear() bm.select_flush(True) bmesh.update_edit_mesh(mesh)
def execute(self, context): mesh = context.object.data if not mesh.is_editmode: self.report({'INFO'}, 'Must be in edit mode') return {'CANCELLED'} bm = bmesh.from_edit_mesh(mesh) bm = bmesh.from_edit_mesh(mesh) bm.faces.ensure_lookup_table() uv_layer = bm.loops.layers.uv[0] for face in bm.faces: if not face.select: continue center = face.calc_center_median() loops = face.loops # find the bottom two verticies nLoops = len(loops) firstBottomLoop = 0 bottomValue = loopSortValue(loops, 0) for li in range(nLoops): testValue = loopSortValue(loops, li) if testValue < bottomValue: bottomValue = testValue firstBottomLoop = li # the "x-axis" is the bottom verticies vector secondBottomLoop = firstBottomLoop + 1 if secondBottomLoop == len(loops): secondBottomLoop = 0 x = loops[secondBottomLoop].vert.co - loops[firstBottomLoop].vert.co x.normalize() # get the "y-axis" from the bottom verticies vector y = x.cross(face.normal) y.normalize() y.negate() # find texture scale and center of current UV screen area offset = [0.5, 0.5] scale = self.pixelSize / 128.0 roundSize = 128 for area in bpy.context.screen.areas : if area.type == 'IMAGE_EDITOR': currentTexture = area.spaces.active.image scale = self.pixelSize / currentTexture.size[1] roundSize = currentTexture.size[1] for region in area.regions: if region.type == 'WINDOW': offset = region.view2d.region_to_view(region.width / 2, region.height / 2) # calculate UVs for li in range(nLoops): loop = loops[li] d = loop.vert.co - center u = min(max(round(d.dot(x) * 100), -1), 1) * scale / 2 + offset[0] v = min(max(round(d.dot(y) * 100), -1), 1) * scale / 2 + offset[1] uv = (round(u * roundSize) / roundSize, round(v * roundSize) / roundSize) loop[uv_layer].uv = uv bmesh.update_edit_mesh(mesh, True) return {'FINISHED'}
def execute(self, ops_obj, context): # Note: the current system only works if the # f[tex_layer].image doesn't return None # which will happen in certain cases obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() if not bm.loops.layers.uv: ops_obj.report({'WARNING'}, "Object must have more than one UV map") return {'CANCELLED'} uv_layer = bm.loops.layers.uv.verify() tex_layer = bm.faces.layers.tex.verify() sel_faces = [f for f in bm.faces if f.select] dest_img = bpy.data.images[ops_obj.dest_img_name] info = {} for f in sel_faces: if not f[tex_layer].image in info.keys(): info[f[tex_layer].image] = {} info[f[tex_layer].image]['faces'] = [] info[f[tex_layer].image]['faces'].append(f) for img in info: if img is None: continue src_img = img ratio = Vector((dest_img.size[0] / src_img.size[0], dest_img.size[1] / src_img.size[1])) if ops_obj.origin == 'CENTER': origin = Vector((0.0, 0.0)) num = 0 for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin = origin + uv num = num + 1 origin = origin / num elif ops_obj.origin == 'LEFT_TOP': origin = Vector((100000.0, -100000.0)) for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = min(origin.x, uv.x) origin.y = max(origin.y, uv.y) elif ops_obj.origin == 'LEFT_CENTER': origin = Vector((100000.0, 0.0)) num = 0 for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = min(origin.x, uv.x) origin.y = origin.y + uv.y num = num + 1 origin.y = origin.y / num elif ops_obj.origin == 'LEFT_BOTTOM': origin = Vector((100000.0, 100000.0)) for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = min(origin.x, uv.x) origin.y = min(origin.y, uv.y) elif ops_obj.origin == 'CENTER_TOP': origin = Vector((0.0, -100000.0)) num = 0 for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = origin.x + uv.x origin.y = max(origin.y, uv.y) num = num + 1 origin.x = origin.x / num elif ops_obj.origin == 'CENTER_BOTTOM': origin = Vector((0.0, 100000.0)) num = 0 for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = origin.x + uv.x origin.y = min(origin.y, uv.y) num = num + 1 origin.x = origin.x / num elif ops_obj.origin == 'RIGHT_TOP': origin = Vector((-100000.0, -100000.0)) for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = max(origin.x, uv.x) origin.y = max(origin.y, uv.y) elif ops_obj.origin == 'RIGHT_CENTER': origin = Vector((-100000.0, 0.0)) num = 0 for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = max(origin.x, uv.x) origin.y = origin.y + uv.y num = num + 1 origin.y = origin.y / num elif ops_obj.origin == 'RIGHT_BOTTOM': origin = Vector((-100000.0, 100000.0)) for f in info[img]['faces']: for l in f.loops: uv = l[uv_layer].uv origin.x = max(origin.x, uv.x) origin.y = min(origin.y, uv.y) info[img]['ratio'] = ratio info[img]['origin'] = origin for img in info: if img is None: continue for f in info[img]['faces']: f[tex_layer].image = dest_img for l in f.loops: uv = l[uv_layer].uv origin = info[img]['origin'] ratio = info[img]['ratio'] diff = uv - origin diff.x = diff.x / ratio.x diff.y = diff.y / ratio.y uv.x = origin.x + diff.x uv.y = origin.y + diff.y l[uv_layer].uv = uv bmesh.update_edit_mesh(obj.data) return {'FINISHED'}
def edgeMerger(): # Lets start gathering the stuff we will use later ob = bpy.context.selected_objects[0] obData = ob.data print(_warnMsg[3] % str(len(obData.polygons))) global _mergeAgain, _mergeAgainCount _mergeAgain = False # Lets just make sure we are in edit mode before we begin if (ob.mode != 'EDIT'): bpy.ops.object.mode_set(mode='EDIT', toggle=False) showme(_apply) # Runs only the first time the script start if _mergeAgainCount == 0: # clean slate, deselect anything and show everything bpy.ops.mesh.reveal() bpy.ops.mesh.select_all(action='DESELECT') showme(_apply) _mergeAgainCount += 1 # We are ready to begin the actual mesh editing # Documentation recomends that for any nitty gritty operations # We use Bmesh bm = bmesh.new() bm = bmesh.from_edit_mesh(obData) print(_warnMsg[4] % str(len(bm.faces))) showme(_apply) findingDoubles = [] # Store a verts dict for referece edge_medians = {} # Loop over edges #for edg_pos,edge in enumerate(bm.edges): for edg_pos, edge in enumerate(bm.edges): #print("Edge %s in pos: %s" % (str(edge.index), str(edg_pos))) this_edge_median = median_get(edge.verts) edge_medians[str(edge.index)] = this_edge_median bm.edges.ensure_lookup_table() bm.verts.ensure_lookup_table() # Try to find identical edge medians from different edges for i, em in edge_medians.items(): #print([em, i, this_edge_median] ) # If this Edge's Median is equal to any other Median except itself if em == this_edge_median and (str(i) != str(edge.index)): #print("Edge %s matches %s " % (str(i) ,str(edge.index))) edge.select = True # TODO: Include some math from the custom normals to help decide if welded edges # should be smooth[True False] # Lets get some math on the normals # having two edges, treat common vertex as individual # option 1 # ((e1v1 + e1v2)/2)-e1 # option 2 # e1v1.angle(e1v2) + e2v1.angle(e2v2) ''' print ([ edge.verts[0].normal.angle(Vector([0,0,1])),edge.verts[1].normal.angle(Vector([0,0,1])), bm.edges[int(i)].verts[0].normal.angle(Vector([0,0,1])),bm.edges[int(i)].verts[1].normal.angle(Vector([0,0,1])) ]) ''' # These lists will hold the welding params vert_keeper = [] vert_welder = [] # Loop over verts in the matched edge for vert in edge.verts: if vert not in vert_welder: vert_welder.append(vert) # Loop over verts in the matching edge # TODO: Is there a reason to maybe revert matching and matched? # bottom edge being in matched in matcher allows edge welding stacks for vert in bm.edges[int(i)].verts: if vert not in vert_welder: vert_welder.append(vert) if vert not in vert_keeper: vert_keeper.append(vert) # Build a tracemap list of verts to merge thru weld findingDoubles.append( bmesh.ops.find_doubles(bm, verts=vert_welder, keep_verts=vert_keeper, dist=0.0001)) # Use core operator weld_verts, cause all the cool kids use it if len(findingDoubles): for fd in findingDoubles: for fd_vm, fd_vk in fd["targetmap"].items(): if fd_vm.is_valid and fd_vk.is_valid: bmesh.ops.weld_verts(bm, targetmap={fd_vm: fd_vk}) # Dead vertices in targetmap mean a merge didn't take place, set to try again else: _mergeAgain = True # return all changes to the actual mesh bmesh.update_edit_mesh(ob.data, loop_triangles=True, destructive=True) ob.data.calc_loop_triangles() showme(_apply) return
def modal(self, context, event): context.area.tag_redraw() context.area.header_text_set("NewPoint: Ctrl+Click, SelectAdditive: Shift+Click, DeletePoint: Del, SurfaceSnap: Shift+Tab, SelectLinked: L/Shift+L, SpreadMode: M, CircleSelect: C, BoxSelect: B") user_preferences = context.user_preferences addon_prefs = user_preferences.addons[__package__].preferences curve_settings = context.scene.mi_settings cur_stretch_settings = context.scene.mi_cur_stretch_settings active_obj = context.scene.objects.active bm = bmesh.from_edit_mesh(active_obj.data) region = context.region rv3d = context.region_data m_coords = event.mouse_region_x, event.mouse_region_y self.select_coords = m_coords keys_pass = mi_inputs.get_input_pass(mi_inputs.pass_keys, addon_prefs.key_inputs, event) # make picking if self.curve_tool_mode == 'IDLE' and event.value == 'PRESS' and keys_pass is False: if event.type in {'LEFTMOUSE', 'SELECTMOUSE'}: # pick point test picked_point, picked_length, picked_curve = cur_main.pick_all_curves_point(self.all_curves, context, m_coords) if picked_point: self.deform_mouse_pos = m_coords self.active_curve = picked_curve self.active_curve.active_point = picked_point.point_id additive_sel = event.shift if additive_sel is False and picked_point.select is False: for curve in self.all_curves: if curve is not self.active_curve: cur_main.select_all_points(curve.curve_points, False) # deselect points curve.active_point = None cur_main.select_point(self.active_curve, picked_point, additive_sel) self.curve_tool_mode = 'SELECT_POINT' else: # add point if event.ctrl and self.active_curve and self.active_curve.active_point: act_point = cur_main.get_point_by_id(self.active_curve.curve_points, self.active_curve.active_point) new_point_pos = ut_base.get_mouse_on_plane(context, act_point.position, None, m_coords) if new_point_pos: for curve in self.all_curves: if curve is not self.active_curve: cur_main.select_all_points(curve.curve_points, False) # deselect points curve.active_point = None new_point = cur_main.add_point(new_point_pos, self.active_curve) self.active_curve.active_point = new_point.point_id self.curve_tool_mode = 'MOVE_POINT' # add to display cur_main.curve_point_changed(self.active_curve, self.active_curve.curve_points.index(new_point), curve_settings.curve_resolution, self.active_curve.display_bezier) #return {'RUNNING_MODAL'} elif event.type in {'DEL'}: for curve in self.all_curves: sel_points = cur_main.get_selected_points(curve.curve_points) if sel_points: for point in sel_points: #the_act_point = cur_main.get_point_by_id(self.active_curve.curve_points, self.active_curve.active_point) #the_act_point_index = self.active_curve.curve_points.index(point) if len(curve.curve_points) > 2: cur_main.delete_point(point, curve, curve.display_bezier, curve_settings.curve_resolution) else: point.select = False curve.display_bezier.clear() cur_main.generate_bezier_points(curve, curve.display_bezier, curve_settings.curve_resolution) curve.active_point = None # move point to the curve update_curve_line(active_obj, curve, self.loops, self.all_curves, bm, curve_settings.spread_mode, self.original_verts_data[self.all_curves.index(curve)]) bm.normal_update() bmesh.update_edit_mesh(active_obj.data) elif event.type in {'TAB'} and event.shift: if curve_settings.surface_snap is True: curve_settings.surface_snap = False else: curve_settings.surface_snap = True if not self.picked_meshes: # get meshes for snapping meshes_array = ut_base.get_obj_dup_meshes(curve_settings.snap_objects, curve_settings.convert_instances, context) if meshes_array: self.picked_meshes = meshes_array # Select Linked elif event.type == 'L': picked_point, picked_length, picked_curve = cur_main.pick_all_curves_point(self.all_curves, context, m_coords) if picked_point: if not event.shift: for curve in self.all_curves: if curve is not picked_curve: cur_main.select_all_points(curve.curve_points, False) curve.active_point = None cur_main.select_all_points(picked_curve.curve_points, True) picked_curve.active_point = picked_point.point_id self.active_curve = picked_curve # Change Spread Type elif event.type == 'M': if curve_settings.spread_mode == 'Original': curve_settings.spread_mode = 'Uniform' else: curve_settings.spread_mode = 'Original' for curve in self.all_curves: update_curve_line(active_obj, curve, self.loops, self.all_curves, bm, curve_settings.spread_mode, self.original_verts_data[self.all_curves.index(curve)]) # update mesh bm.normal_update() bmesh.update_edit_mesh(active_obj.data) # Set to Select Multy elif event.type == 'C': self.curve_tool_mode = 'SELECT_MULTI' self.curve_tool_mult_mode = 'CIRCLE' elif event.type == 'B': self.curve_tool_mode = 'SELECT_MULTI' self.curve_tool_mult_mode = 'BOX' elif self.curve_tool_mode == 'SELECT_MULTI': # Switch Selection tool off if event.value == 'PRESS': if self.curve_tool_mult_mode == 'CIRCLE' and event.type == 'C': self.curve_tool_mode = 'IDLE' self.mouse_down = False self.mmouse_down = False return {'RUNNING_MODAL'} if self.curve_tool_mult_mode == 'BOX' and event.type == 'B': self.curve_tool_mode = 'IDLE' self.mouse_down = False self.mmouse_down = False return {'RUNNING_MODAL'} # TOOLS WORK if self.curve_tool_mode == 'SELECT_POINT': if event.type in {'LEFTMOUSE', 'SELECTMOUSE'} and event.value == 'RELEASE': self.curve_tool_mode = 'IDLE' return {'RUNNING_MODAL'} else: # set to move point if ( Vector((m_coords[0], m_coords[1])) - Vector((self.deform_mouse_pos[0], self.deform_mouse_pos[1])) ).length > 4.0: self.curve_tool_mode = 'MOVE_POINT' return {'RUNNING_MODAL'} elif self.curve_tool_mode == 'MOVE_POINT': if event.type in {'LEFTMOUSE', 'SELECTMOUSE'} and event.value == 'RELEASE': # Snap to Surface if curve_settings.surface_snap is True and self.picked_meshes: for curve in self.all_curves: selected_points = cur_main.get_selected_points(curve.curve_points) if selected_points: cur_main.snap_to_surface(context, selected_points, self.picked_meshes, region, rv3d, None) if len(selected_points) == 1: cur_main.curve_point_changed(curve, curve.curve_points.index(selected_points[0]), curve_settings.curve_resolution, curve.display_bezier) else: cur_main.generate_bezier_points(curve, curve.display_bezier, curve_settings.curve_resolution) # move point to the curve for curve in self.all_curves: selected_points = cur_main.get_selected_points(curve.curve_points) if selected_points: update_curve_line(active_obj, curve, self.loops, self.all_curves, bm, curve_settings.spread_mode, self.original_verts_data[self.all_curves.index(curve)]) bm.normal_update() bmesh.update_edit_mesh(active_obj.data) self.curve_tool_mode = 'IDLE' return {'RUNNING_MODAL'} else: # move points act_point = cur_main.get_point_by_id(self.active_curve.curve_points, self.active_curve.active_point) new_point_pos = ut_base.get_mouse_on_plane(context, act_point.position, None, m_coords) if new_point_pos: move_offset = new_point_pos - act_point.position camera_dir = (rv3d.view_rotation * Vector((0.0, 0.0, -1.0))).normalized() for curve in self.all_curves: selected_points = cur_main.get_selected_points(curve.curve_points) if selected_points: # Move Points without Snapping for point in selected_points: point.position += move_offset if len(selected_points) == 1: cur_main.curve_point_changed(curve, curve.curve_points.index(selected_points[0]), curve_settings.curve_resolution, curve.display_bezier) else: cur_main.generate_bezier_points(curve, curve.display_bezier, curve_settings.curve_resolution) return {'RUNNING_MODAL'} elif self.curve_tool_mode == 'SELECT_MULTI': # first check if self.curve_tool_mult_mode == 'CIRCLE': if event.type == 'WHEELDOWNMOUSE': self.select_radius *= 1.2 elif event.type == 'WHEELUPMOUSE': self.select_radius /= 1.2 if self.select_radius < 4: self.select_radius = 4 # second check if event.type in {'LEFTMOUSE', 'SELECTMOUSE'} and event.value == 'PRESS': self.mouse_down = True if self.curve_tool_mult_mode == 'CIRCLE': pts, lns, crvs = cur_main.pick_all_curves_points_radius(self.all_curves, context, m_coords, self.select_radius) cur_main.select_point_multi(self.all_curves, pts, True) if self.curve_tool_mult_mode == 'BOX': self.select_box_anchor = m_coords if event.type in {'LEFTMOUSE', 'SELECTMOUSE'} and event.value == 'RELEASE': self.mouse_down = False if self.curve_tool_mult_mode == 'BOX': pts, crvs = cur_main.pick_all_curves_points_box(self.all_curves, context, m_coords, self.select_box_anchor) cur_main.select_point_multi(self.all_curves, pts, True) if event.type in {'MIDDLEMOUSE'} and event.value == 'PRESS': self.mmouse_down = True if self.curve_tool_mult_mode == 'CIRCLE': pts, lns, crvs = cur_main.pick_all_curves_points_radius(self.all_curves, context, m_coords, self.select_radius) cur_main.select_point_multi(self.all_curves, pts, False) if self.curve_tool_mult_mode == 'BOX': self.select_box_anchor = m_coords if event.type in {'MIDDLEMOUSE'} and event.value == 'RELEASE': self.mmouse_down = False if self.curve_tool_mult_mode == 'BOX': pts, crvs = cur_main.pick_all_curves_points_box(self.all_curves, context, m_coords, self.select_box_anchor) cur_main.select_point_multi(self.all_curves, pts, False) if event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'RELEASE': self.curve_tool_mode = 'IDLE' return {'RUNNING_MODAL'} if event.type in {'MOUSEMOVE'}: if not self.mouse_down and not self.mmouse_down: return {'PASS_THROUGH'} elif self.mouse_down: if self.curve_tool_mult_mode == 'CIRCLE': pts, lns, crvs = cur_main.pick_all_curves_points_radius(self.all_curves, context, m_coords, self.select_radius) cur_main.select_point_multi(self.all_curves,pts, True) elif self.mmouse_down: if self.curve_tool_mult_mode == 'CIRCLE': pts, lns, crvs = cur_main.pick_all_curves_points_radius(self.all_curves, context, m_coords, self.select_radius) cur_main.select_point_multi(self.all_curves, pts, False) return {'RUNNING_MODAL'} else: if event.value == 'RELEASE' and event.type in {'LEFTMOUSE', 'SELECTMOUSE'}: self.curve_tool_mode = 'IDLE' return {'RUNNING_MODAL'} # get keys if keys_pass is True: # allow navigation return {'PASS_THROUGH'} elif event.type in {'RIGHTMOUSE', 'ESC'}: bpy.types.SpaceView3D.draw_handler_remove(self.mi_deform_handle_3d, 'WINDOW') bpy.types.SpaceView3D.draw_handler_remove(self.mi_deform_handle_2d, 'WINDOW') bpy.types.SpaceView3D.draw_handler_remove(self.gh_circle_select_handle, 'WINDOW') finish_work(self, context) context.area.header_text_set() return {'FINISHED'} return {'RUNNING_MODAL'}
def execute(self, context): active_obj = context.scene.objects.active active_mesh = active_obj.data #if WPLSMTHDEF_G.mesh_name != active_obj.name: if (active_mesh.uv_textures.get(kWPLSmoothHolderUVMap1) is None) or ( active_mesh.uv_textures.get(kWPLSmoothHolderUVMap2) is None): self.report({'ERROR'}, "No interpolate, save mesh state first!") return {'FINISHED'} selverts = get_selected_vertsIdx(active_mesh) select_and_change_mode(active_obj, 'EDIT') edit_obj = bpy.context.edit_object active_mesh = edit_obj.data matrix_world = active_obj.matrix_world matrix_world_inv = active_obj.matrix_world.inverted() matrix_world_nrml = matrix_world_inv.transposed().to_3x3() bm = bmesh.from_edit_mesh(active_mesh) bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() bm.verts.index_update() verts_map = {} uv_layer_holdr1 = bm.loops.layers.uv.get(kWPLSmoothHolderUVMap1) uv_layer_holdr2 = bm.loops.layers.uv.get(kWPLSmoothHolderUVMap2) for face in bm.faces: for vert, loop in zip(face.verts, face.loops): verts_map[vert.index] = mathutils.Vector( (loop[uv_layer_holdr1].uv[0], loop[uv_layer_holdr1].uv[1], loop[uv_layer_holdr2].uv[0])) if len(selverts) == 0: selverts = [] for v in bm.verts: if verts_map[v.index] is not None: if (v.co - verts_map[v.index]).length > kRaycastEpsilon: # vert moved selverts.append(v.index) if len(selverts) == 0: self.report({'ERROR'}, "No selected verts found!") return {'FINISHED'} checked_verts = copy.copy(selverts) verts_shifts = {} propagation_stages = [] for stage in range(1, self.SmoothingLoops + 1): stage_verts = {} checked_verts_cc = copy.copy(checked_verts) for v_idx in checked_verts_cc: v = bm.verts[v_idx] if (v_idx not in verts_shifts) and (v_idx in verts_map): verts_shifts[v_idx] = mathutils.Vector(v.co - verts_map[v_idx]) for edg in v.link_edges: v2 = edg.other_vert(v) if v2.index not in checked_verts_cc: #print("found new vert",v2.index,"at stage",stage) #v2.select = True if v2.index not in checked_verts: checked_verts.append(v2.index) if (v2.index not in stage_verts): stage_verts[v2.index] = [] if v_idx not in stage_verts[v2.index]: stage_verts[v2.index].append(v_idx) if len(stage_verts) == 0: break propagation_stages.append(stage_verts) #print("vert stages",propagation_stages) #print("verts_shifts",verts_shifts) new_positions = {} stage_cnt = 1.0 for stage_verts in propagation_stages: stage_weight = pow(1.0 - stage_cnt / len(propagation_stages), self.Sloppiness) for s_idx in stage_verts: avg_shift = mathutils.Vector((0, 0, 0)) avg_count = 0.0 for p_idx in stage_verts[s_idx]: avg_shift = avg_shift + verts_shifts[p_idx] avg_count = avg_count + 1.0 if avg_count > 0: s_shift = mathutils.Vector(avg_shift) / avg_count verts_shifts[s_idx] = s_shift s_v = bm.verts[s_idx] #print("shifting vert",s_idx, s_v.index, s_v.co,verts_map[s_idx]) s_v_co2 = s_v.co + s_shift * stage_weight if (self.CollisionDist > 0.0): s_dir_g = (matrix_world_nrml * s_shift.normalized()) s_v_g = matrix_world * s_v.co min_okdst = (s_shift * stage_weight).length loc_g = fuzzySceneRayCast(s_v_g, s_dir_g, self.CollisionFuzz, [active_obj.name]) if loc_g is not None: loc_l = matrix_world_inv * loc_g hit_dst = (loc_l - s_v.co).length - self.CollisionDist if hit_dst < min_okdst: if hit_dst > 0: #s_v_co2 = s_v.co+hit_dst*(loc_l-s_v.co).normalized() s_v_co2 = s_v.co + hit_dst * s_shift.normalized( ) else: s_v_co2 = s_v.co #s_v.co = s_v_co2 new_positions[s_idx] = s_v_co2 stage_cnt = stage_cnt + 1.0 # updateing positions as post-step for s_idx in new_positions: s_v = bm.verts[s_idx] s_v.co = new_positions[s_idx] bm.normal_update() bmesh.update_edit_mesh(active_mesh, True) return {'FINISHED'}
def deform_obj(obj, context, self): offset_rotation = 0.2 offset_axis = 5.0 bend_scale = 0.7 # get vertices verts = None if obj.mode == 'EDIT': # this works only in edit mode, bm = bmesh.from_edit_mesh(obj.data) verts = [v for v in bm.verts if v.select] if len(verts) == 0: verts = [v for v in bm.verts if v.hide is False] else: # this works only in object mode, verts = [v for v in obj.data.vertices if v.select] if len(verts) == 0: verts = [v for v in obj.data.vertices if v.hide is False] # TODO Move it into utilities method. As Extrude class has the same # min/max. if verts: if obj.mode == 'EDIT': bm.verts.ensure_lookup_table() x_min = verts[0].co.x x_max = verts[0].co.x y_min = verts[0].co.y y_max = verts[0].co.y z_min = verts[0].co.z z_max = verts[0].co.z for vert in verts: if vert.co.x > x_max: x_max = vert.co.x if vert.co.x < x_min: x_min = vert.co.x if vert.co.y > y_max: y_max = vert.co.y if vert.co.y < y_min: y_min = vert.co.y if vert.co.z > z_max: z_max = vert.co.z if vert.co.z < z_min: z_min = vert.co.z x_orig = ((x_max - x_min) / 2.0) + x_min y_orig = ((y_max - y_min) / 2.0) + y_min z_orig = z_min if self.deform_axis == 'Z': y_orig = y_min z_orig = ((z_max - z_min) / 2.0) + z_min rot_origin = Vector((x_orig, y_orig, z_orig)) visual_max = z_max - z_min if self.deform_axis == 'Z': visual_max = y_max - y_min if visual_max != 0.0: for vert in verts: vec = vert.co.copy() visual_up_pos = None if self.deform_axis != 'Z': visual_up_pos = vec.z - z_min else: visual_up_pos = vec.y - y_min # TAPER CODE # scale the vert if self.taper_value != 0: taper_value = ((self.taper_value) * (visual_up_pos / visual_max)) if self.deform_axis != 'Z': vert.co.xy -= (vert.co.xy - rot_origin.xy) * taper_value else: vert.co.xz -= (vert.co.xz - rot_origin.xz) * taper_value # TWIST CODE # rotate the vert if self.twist_angle != 0: twist_angle = self.twist_angle * (visual_up_pos / visual_max) # if self.deform_axis == 'X': # rot_angle = -rot_angle rot_mat = None if self.deform_axis != 'Z': rot_mat = Matrix.Rotation(twist_angle, 3, 'Z') else: rot_mat = Matrix.Rotation(twist_angle, 3, 'Y') vert.co = rot_mat * (vert.co - rot_origin) + rot_origin # BEND CODE beta = math.radians(self.bend_angle * (visual_up_pos / visual_max)) if beta != 0: final_offset = visual_up_pos * self.offset_rotation if beta < 0: final_offset = -final_offset move_to_rotate = ((visual_up_pos / beta) + final_offset) * self.bend_scale if self.deform_axis == 'X': vert.co.y -= move_to_rotate elif self.deform_axis == 'Y' or self.deform_axis == 'Z': vert.co.x -= move_to_rotate if self.deform_axis != 'Z': vert.co.z = rot_origin.z else: vert.co.y = rot_origin.y # rotate the vert rot_angle = beta if self.deform_axis == 'X' or self.deform_axis == 'Z': rot_angle = -rot_angle rot_mat = Matrix.Rotation(rot_angle, 3, self.deform_axis) vert.co = rot_mat * (vert.co - rot_origin) + rot_origin # back the rotation offset back_offset = (visual_up_pos / (beta)) * self.bend_scale if self.deform_axis == 'X': vert.co.y += back_offset elif self.deform_axis == 'Y' or self.deform_axis == 'Z': vert.co.x += back_offset # offset axys move_offset = self.offset_axis * (visual_up_pos / visual_max) if self.deform_axis == 'X': vert.co.x += move_offset elif self.deform_axis == 'Y': vert.co.y += move_offset elif self.deform_axis == 'Z': vert.co.z += move_offset # obj.data.update() #bpy.ops.mesh.normals_make_consistent() # recalculate normals #bpy.ops.object.editmode_toggle() #bpy.ops.object.editmode_toggle() bm.normal_update() bmesh.update_edit_mesh(obj.data)
def main(self, context, chboxexplote, chboxjoin, chboxaxisx, chboxaxisy, chboxaxisz, distance): if chboxexplote: distancia = distance / 10 #almacena caras obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) obj = bpy.context.object cara_activa = bm.faces.active listacaras = [v for v in bm.faces if (v.select and not v.hide)] listacarasdes = [ v for v in bm.faces if (v.select == False and not v.hide) ] contador = len(listacaras) #print(len(listacaras)) if distancia != 0: separarcaras() while contador != 0: contador -= 1 cara = listacaras[contador] posicion = contador * distancia if cara == cara_activa: print("cara eje") for vertice in cara.verts: if chboxaxisx: vertice.co.x = vertice.co.x + posicion if chboxaxisy: vertice.co.y = vertice.co.y + posicion if chboxaxisz: vertice.co.z = vertice.co.z + posicion for cara in listacaras: cara.select = False if len(listacaras) != (len(bm.faces)): bpy.ops.mesh.select_all(action='INVERT') else: bpy.ops.mesh.select_all(action='SELECT') bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001) cara_activa.select = True bmesh.update_edit_mesh(me, True) ######### unir caras elif chboxjoin: #almacena caras obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) listacaras = [] if len(bm.faces) > 1: for face in bm.faces: if face.select: listacaras.append(face) #bmesh.update_edit_mesh(me, True) distanciax = bm.faces.active.verts[0].co.x distanciay = bm.faces.active.verts[0].co.y distanciaz = bm.faces.active.verts[0].co.z contador = len(listacaras) #print(len(listacaras)) listavertices = [bm.faces.active.verts[0]] for cara in listacaras: for vertice in cara.verts: listavertices.append(vertice) if chboxaxisx: vertice.co.x = distanciax if chboxaxisy: vertice.co.y = distanciay if chboxaxisz: vertice.co.z = distanciaz bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001) bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') for vertice in bm.verts: if vertice.co.x == distanciax: vertice.select = True elif vertice.co.y == distanciay: vertice.select = True elif vertice.co.z == distanciaz: vertice.select = True bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') bmesh.update_edit_mesh(me, True)
def updateMesh(self, context): o = context.object material_list = getMaterialList(o) if o.pattern == 'Regular': nplanks = (o.width + o.originy) / o.plankwidth verts, faces, uvs = planks(nplanks, o.length + o.originx, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.minoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Herringbone': # note that there is a lot of extra length and width here to make sure that we create a pattern w.o. gaps at the edges v = o.plankwidth * sqrt(2.0) w = o.planklength * sqrt(2.0) nplanks = int((o.width+o.planklength + o.originy*2) / v)+1 nplanksc = int((o.length + o.originx*2) / w)+1 verts, faces, uvs = herringbone(nplanks, nplanksc, o.planklength, o.plankwidth, o.longgap, o.shortgap, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Square': rows = int((o.width + o.originy)/ o.planklength)+1 cols = int((o.length + o.originx)/ o.planklength)+1 verts, faces, uvs = square(rows, cols, o.planklength, o.nsquare, o.border, o.longgap, o.shortgap, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Versaille': rows = int((o.width + o.originy)/ o.planklength)+2 cols = int((o.length + o.originx)/ o.planklength)+2 verts, faces, uvs = versaille(rows, cols, o.planklength, o.plankwidth, o.longgap, o.shortgap, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy, o.borderswitch) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) # more than one object can refer to the same emesh for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear() # this way the old mesh is marked as used by noone and not saved on exit bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() bpy.context.object.data.use_auto_smooth = 1 bpy.context.object.data.auto_smooth_angle = 1 # add uv-coords and per face random vertex colors rot = Euler((0,0,o.uvrotation)) mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data offset = Vector() # note that the uvs that are returned are shuffled for poly in mesh.polygons: color = [rand(), rand(), rand()] if o.randomuv == 'Random': offset = Vector((rand(), rand(), 0)) if o.randomuv == 'Restricted': offset = Vector((rand()*2-1, rand()*2-1, 0)) for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): co = offset + mesh.vertices[mesh.loops[loop_index].vertex_index].co if co.x > o.length or co.x < 0: offset[0] = 0 if co.y > o.width or co.y < 0: offset[1] = 0 elif o.randomuv == 'Packed': x = [] y = [] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): x.append(uvs[mesh.loops[loop_index].vertex_index].x) y.append(uvs[mesh.loops[loop_index].vertex_index].y) offset = Vector((-min(x), -min(y), 0)) for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): if o.randomuv == 'Shuffle': coords = uvs[mesh.loops[loop_index].vertex_index] elif o.randomuv in ('Random', 'Restricted'): coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co + offset elif o.randomuv == 'Packed': coords = uvs[mesh.loops[loop_index].vertex_index] + offset else: coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co coords = Vector(coords) # copy coords.x *= o.uvscalex coords.y *= o.uvscaley coords.rotate(rot) uv_layer[loop_index].uv = coords.xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len(v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert(v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len(v2.link_edges) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() # remove all modifiers to make sure the boolean will be last & only modifier n = len(o.modifiers) while n > 0: n -= 1 bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name) # add thickness bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(o.data) # extrude to given thickness ret=bmesh.ops.extrude_face_region(bm,geom=bm.faces[:]) # all planks are separate faces, except when subdivided by random twist or hollowness if warped: # we have a extra subdivision Z = Vector((0,0,1)) for el in ret['geom']: if isinstance(el, bmesh.types.BMVert) and len(el.link_edges) == 4 and el.normal.dot(Z) > 0.99 : # we look start at the vertex in the middle of the 4 faces but only on the top d = Vector((0,0,o.thickness + rand() * o.randomthickness)) verts = set(v for f in el.link_faces for v in f.verts) # some vertices are shared, this way we make them unique bmesh.ops.translate(bm, vec=d, verts=list(verts)) else: for el in ret['geom']: if isinstance(el, bmesh.types.BMFace): d = Vector((0,0,o.thickness + rand() * o.randomthickness)) bmesh.ops.translate(bm, vec=d, verts=el.verts) # trim excess flooring ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(o.length,0,0), plane_no=(1,0,0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,0,0), plane_no=(-1,0,0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,o.width,0), plane_no=(0,1,0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,0,0), plane_no=(0,-1,0), clear_outer=True) # fill in holes caused by the trimming open_edges = [e for e in bm.edges if len(e.link_faces)==1] bmesh.ops.edgeloop_fill(bm, edges=open_edges, mat_nr=0, use_smooth=False) creases = bm.edges.layers.crease.active if creases is not None: for edge in open_edges: edge[creases] = 1 bmesh.update_edit_mesh(o.data) bpy.ops.object.mode_set(mode='OBJECT') # intersect with a floorplan. Note the floorplan must be 2D (all z-coords must be identical) and a closed polygon. if self.usefloorplan and self.floorplan != ' None ': # make the floorplan the only active an selected object bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = bpy.data.objects[self.floorplan] bpy.data.objects[self.floorplan].select = True # duplicate the selected geometry into a separate object me = context.scene.objects.active.data selected_faces = [p.index for p in me.polygons if p.select] bpy.ops.object.editmode_toggle() bpy.ops.mesh.duplicate() bpy.ops.mesh.separate() bpy.ops.object.editmode_toggle() me = context.scene.objects.active.data for i in selected_faces: me.polygons[i].select = True # now there will be two selected objects # the one with the new name will be the copy for ob in context.selected_objects: if ob.name != self.floorplan: fpob = ob # make that copy active and selected for ob in context.selected_objects: ob.select = False fpob.select = True context.scene.objects.active = fpob # add thickness # let normals of select faces point in same direction bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # add solidify modifier # NOTE: for some reason bpy.ops.object.modifier_add doesn't work here # even though fpob at this point is verifyable the active and selected object ... mod = fpob.modifiers.new(name='Solidify', type='SOLIDIFY') mod.offset = 1.0 # in the direction of the normals mod.thickness = 2000 # very thick bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() fpob.location -= Vector((0,0,1000)) # actually this should be in the negative direction of the normals not just plain downward... # at this point the floorplan object is the active and selected object if True: # make the floorboards active and selected for ob in context.selected_objects: ob.select = False context.scene.objects.active = o o.select = True # add-and-apply a boolean modifier to get the intersection with the floorplan copy bpy.ops.object.modifier_add(type='BOOLEAN') # default is intersect o.modifiers[-1].object = fpob if True: bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean") # delete the copy bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = fpob fpob.select = True bpy.ops.object.delete() # make the floorboards active and selected context.scene.objects.active = o o.select = True if self.modify: mods = o.modifiers if len(mods) == 0: # always true bpy.ops.object.modifier_add(type='BEVEL') mods[0].use_clamp_overlap = False # clamp overlap causes some issues #bpy.ops.object.modifier_add(type='EDGE_SPLIT') mods = o.modifiers mods[0].show_expanded = False #mods[1].show_expanded = False mods[0].width = self.bevel mods[0].segments = 2 mods[0].limit_method = 'ANGLE' mods[0].angle_limit = (85/90.0)*PI/2 if warped and not ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_add(type='SUBSURF') mods[-1].show_expanded = False mods[-1].show_viewport = False # subsurf in viewport is not necessary and slow things down mods[-1].levels = 2 if not warped and ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_remove(modifier='Subsurf') if self.preservemats and len(material_list)>0: rebuildMaterialList(o, material_list) assignRandomMaterial(len(material_list)) # correct the shading artefacts bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.remove_doubles() bpy.ops.mesh.normals_make_consistent() bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.edges_select_sharp(sharpness=1.4) bpy.ops.mesh.mark_sharp() bpy.ops.mesh.select_face_by_sides(number=5, type='GREATER', extend=False) bpy.ops.mesh.quads_convert_to_tris(quad_method='BEAUTY', ngon_method='BEAUTY') bpy.ops.mesh.tris_convert_to_quads() bpy.ops.object.editmode_toggle()
def execute(self, context): mesh = bpy.context.object.data bm = bmesh.from_edit_mesh(mesh) bm.faces.ensure_lookup_table() uv_layer = bm.loops.layers.uv.active faces = list() #MAKE FACE LIST for face in bm.faces: if face.select: faces.append(face) mirrored = False #check if mirrored: for face in faces: sum_edges = 0 # Only loop 3 verts ignore others: faster! for i in range(3): uv_A = face.loops[i][uv_layer].uv uv_B = face.loops[(i + 1) % 3][uv_layer].uv sum_edges += (uv_B.x - uv_A.x) * (uv_B.y + uv_A.y) if sum_edges > 0: mirrored = True #get original size xmin, xmax = faces[0].loops[0][uv_layer].uv.x, faces[0].loops[0][ uv_layer].uv.x ymin, ymax = faces[0].loops[0][uv_layer].uv.y, faces[0].loops[0][ uv_layer].uv.y for face in faces: for vert in face.loops: xmin = min(xmin, vert[uv_layer].uv.x) xmax = max(xmax, vert[uv_layer].uv.x) ymin = min(ymin, vert[uv_layer].uv.y) ymax = max(ymax, vert[uv_layer].uv.y) xcenter = (xmin + xmax) / 2 ycenter = (ymin + ymax) / 2 #step rotation module_name = __name__.split('.')[0] addon_prefs = bpy.context.preferences.addons[module_name].preferences scale_snap_x = addon_prefs.scale_snap scale_snap_y = addon_prefs.scale_snap if self.direction == "+XY": scale_snap_x = 1 / scale_snap_x scale_snap_y = 1 / scale_snap_y #if self.direction == "-XY": if self.direction == "+X": scale_snap_x = 1 / scale_snap_x scale_snap_y = 1 if self.direction == "-X": scale_snap_x = scale_snap_x scale_snap_y = 1 if self.direction == "+Y": scale_snap_x = 1 scale_snap_y = 1 / scale_snap_y if self.direction == "-Y": scale_snap_x = 1 scale_snap_y = scale_snap_y #PI/4=0.78539816339 #PIdiv=3.14159265359/(180/rotate_snap) #delta = (3.14159265359/180)*rotate_snap #delta = math.floor(delta/PIdiv)*PIdiv #if self.direction == "reverse": # print("reverse") #delta = (3.14159265359/180)-delta # delta = -delta #if mirrored: # delta = -delta #loop through every selected face and scale the uv's using original uv as reference for face in faces: for loop in face.loops: loop[uv_layer].uv.x -= xcenter loop[uv_layer].uv.y -= ycenter #oldx = loop[uv_layer].uv.x #oldy = loop[uv_layer].uv.y loop[uv_layer].uv.x = loop[uv_layer].uv.x * scale_snap_x loop[uv_layer].uv.y = loop[uv_layer].uv.y * scale_snap_y loop[uv_layer].uv.x += xcenter loop[uv_layer].uv.y += ycenter #update mesh bmesh.update_edit_mesh(mesh, False, False) return {'FINISHED'}
def execute(self, context): self.hcol = context.preferences.addons[ 'kekit'].preferences.modal_color_header self.tcol = context.preferences.addons[ 'kekit'].preferences.modal_color_text self.scol = context.preferences.addons[ 'kekit'].preferences.modal_color_subtext if self.ke_fitprim_option == "BOX": self.boxmode, self.world = True, False elif self.ke_fitprim_option == "CYL": self.boxmode, self.world = False, False elif self.ke_fitprim_option == "SPHERE": self.boxmode, self.world, self.sphere = False, False, True elif self.ke_fitprim_option == "QUADSPHERE": self.boxmode, self.world, self.sphere = False, False, True else: self.boxmode, self.world, self.sphere = False, False, False if bpy.context.scene.kekit.fitprim_item: self.itemize = True else: self.itemize = self.ke_fitprim_itemize self.modal = bpy.context.scene.kekit.fitprim_modal self.cyl_sides = bpy.context.scene.kekit.fitprim_sides self.select = bpy.context.scene.kekit.fitprim_select self.unit = round(bpy.context.scene.kekit.fitprim_unit, 4) self.sphere_ring = bpy.context.scene.kekit.fitprim_sphere_ring self.sphere_seg = bpy.context.scene.kekit.fitprim_sphere_seg self.quadsphere_seg = bpy.context.scene.kekit.fitprim_quadsphere_seg self.edit_mode = bpy.context.mode sel_verts = [] sel_verts2 = [] multi_object_mode = False cursor = context.scene.cursor self.og_cloc = cursor.location.copy() self.og_crot = cursor.rotation_euler.copy() og_orientation = str(context.scene.transform_orientation_slots[0].type) if self.itemize or self.edit_mode == "OBJECT" and context.object is not None: # make sure the new object is in the same layer as context object objc = context.object.users_collection[0] layer_collection = context.view_layer.layer_collection layer_coll = get_layer_collection(layer_collection, objc.name) alc = context.view_layer.active_layer_collection if objc.name != alc.name and alc.name != "Master Collection": context.view_layer.active_layer_collection = layer_coll elif objc.name != "Master Collection" and objc.name != alc.name: context.view_layer.active_layer_collection = layer_coll # ----------------------------------------------------------------------------------------- # MULTI OBJECT CHECK & SETUP # ----------------------------------------------------------------------------------------- if self.edit_mode == "EDIT_MESH": sel_mode = [b for b in bpy.context.tool_settings.mesh_select_mode] other_side = [] sel_obj = [ o for o in bpy.context.selected_objects if o.type == "MESH" ] if len(sel_obj) == 2: multi_object_mode = True obj = bpy.context.active_object obj_mtx = obj.matrix_world.copy() second_obj = [] bm = bmesh.from_edit_mesh(obj.data) bm.faces.ensure_lookup_table() bm.verts.ensure_lookup_table() sel_verts = [v for v in bm.verts if v.select] if sel_mode[2]: sel_poly = [p for p in bm.faces if p.select] active_face = bm.faces.active if active_face not in sel_poly: active_face = None if multi_object_mode: second_obj = [o for o in sel_obj if o != obj][0] bm2 = bmesh.from_edit_mesh(second_obj.data) obj_mtx2 = second_obj.matrix_world.copy() sel_poly2 = [p for p in bm2.faces if p.select] if sel_poly2: active_face2 = bm2.faces.active if active_face2 not in sel_poly2: active_face2 = None if active_face2: sel_verts2 = active_face2.verts else: sel_verts2 = sel_poly2[0].verts active_face2 = sel_poly2[0] # haxxfixxx else: sel_verts2 = [v for v in bm2.verts if v.select] if not sel_verts2: multi_object_mode = False elif sel_mode[0]: # Just for 2-vert mode in multiobj mode ole = sel_verts2[0].link_edges[:] other_side = get_shortest(obj_mtx2, ole) side = None distance = 0 vps = [] normal, setpos, setrot, center = None, None, None, None first_island = None island_mode = False # ----------------------------------------------------------------------------------------- # NO SELECTION MODE # ----------------------------------------------------------------------------------------- if not sel_verts or self.edit_mode == "OBJECT": # Check mouse over target if not self.edit_mode == "OBJECT": bpy.ops.object.mode_set(mode="OBJECT") hit_obj, hit_wloc, hit_normal, hit_face = mouse_raycast( context, self.mouse_pos, evaluated=True) if not self.edit_mode == "OBJECT": bpy.ops.object.mode_set(mode="EDIT") if self.edit_mode != "OBJECT" and hit_obj is not None: if len(hit_obj.modifiers) > 0: self.report({ "INFO" }, "FitPrim: Selected elements required in Edit Mode if Modifiers exist" ) return {"CANCELLED"} if hit_obj and hit_face is not None: # mouse over placement on face self.world = False mtx = hit_obj.matrix_world eks = hit_obj.data.polygons[hit_face].edge_keys vecs = [] for vp in eks: vc1 = mtx @ hit_obj.data.vertices[vp[0]].co vc2 = mtx @ hit_obj.data.vertices[vp[1]].co vecs.append(Vector(vc1 - vc2).normalized()) evps = [] for vp in eks: v1, v2 = hit_obj.data.vertices[ vp[0]], hit_obj.data.vertices[vp[1]] evps.append([v1, v2]) side, center, start_vec = get_sides(mtx, vecs, evps) if self.ke_fitprim_option == "PLANE" and self.edit_mode == "OBJECT": setpos = center # setpos = mtx @ hit_obj.data.polygons[hit_face].center side *= 2 else: offset = hit_normal * (side / 2) setpos = center + offset # setpos = mtx @ hit_obj.data.polygons[hit_face].center + offset setrot = rotation_from_vector(hit_normal, start_vec) else: # view placement compensation & Z0 drop view_vec = region_2d_to_vector_3d(context.region, context.space_data.region_3d, self.mouse_pos) view_pos = context.space_data.region_3d.view_matrix.inverted( ).translation if get_view_type() != "ORTHO": ground = ((0, 0, 0), (0, 1, 0), (1, 0, 0)) raypos = intersect_ray_tri(ground[0], ground[1], ground[2], view_vec, view_pos, False) snap_val = str(self.unit).split('.') if int(snap_val[0]) > 0: snap = 0 else: snap = len(snap_val[1]) setpos = Vector((round(raypos[0], snap), round(raypos[1], snap), self.unit / 2)) else: setpos = region_2d_to_location_3d( context.region, context.space_data.region_3d, self.mouse_pos, view_vec) self.world = True side = self.unit if self.ke_fitprim_option == "PLANE" and self.edit_mode == "OBJECT": side *= 2 distance = side sel_mode = (True, False, False) # ----------------------------------------------------------------------------------------- # VERT MODE(s) # ----------------------------------------------------------------------------------------- elif sel_mode[0]: if len(sel_verts) == 1 and not multi_object_mode: # 1-VERT MODE self.world = True side = get_shortest(obj_mtx, sel_verts[0].link_edges[:]) distance = side setpos = obj_mtx @ sel_verts[0].co elif len(sel_verts) == 2 and not multi_object_mode or \ multi_object_mode and len(sel_verts2) == 1 and len(sel_verts) == 1: # 2 Vert mode if multi_object_mode: p1 = obj_mtx @ sel_verts[0].co p2 = obj_mtx2 @ sel_verts2[0].co side = [other_side] con_edges = sel_verts[0].link_edges[:] side.append(get_shortest(obj_mtx, con_edges)) side = sorted(side)[0] else: p1 = obj_mtx @ sel_verts[0].co p2 = obj_mtx @ sel_verts[1].co con_edges = sel_verts[0].link_edges[:] + sel_verts[ 1].link_edges[:] side = get_shortest(obj_mtx, con_edges) v_1 = Vector(p1 - p2).normalized() v_2 = Vector((0, 0, 1)) if abs(v_1.dot(v_2)) == 1: v_2 = Vector((1, 0, 0)) n_v = v_1.cross(v_2).normalized() u_v = n_v.cross(v_1).normalized() t_v = u_v.cross(n_v).normalized() setrot = Matrix((u_v, n_v, t_v)).to_4x4().inverted() distance = get_distance(p1, p2) setpos = Vector(get_midpoint(p1, p2)) elif len(sel_verts) == 4 or multi_object_mode and len( sel_verts2) + len(sel_verts) <= 4: # 4-vert Rectangle mode # holy brute force batman if not second_obj: second_obj = obj tri = tri_order(((obj, sel_verts), (second_obj, sel_verts2))) q = tri[-1] # just placing a unit prim with min side in the center (for this one) so disregarding other vecs v1 = Vector(tri[0][0].matrix_world @ tri[0][1].co - tri[1][0].matrix_world @ tri[1][1].co) v2 = Vector(tri[0][0].matrix_world @ tri[0][1].co - tri[2][0].matrix_world @ tri[2][1].co) # v3 = Vector(q[0].matrix_world @ q[1].co - tri[1][0].matrix_world @ tri[1][1].co) # v4 = Vector(q[0].matrix_world @ q[1].co - tri[2][0].matrix_world @ tri[2][1].co) d1 = get_distance(tri[0][0].matrix_world @ tri[0][1].co, tri[1][0].matrix_world @ tri[1][1].co) # d2 = get_distance(tri[0][0].matrix_world @ tri[0][1].co, tri[2][0].matrix_world @ tri[2][1].co) # d3 = get_distance(q[0].matrix_world @ q[1].co, tri[1][0].matrix_world @ tri[1][1].co) d4 = get_distance(q[0].matrix_world @ q[1].co, tri[2][0].matrix_world @ tri[2][1].co) if d1 < d4: side = d1 else: side = d4 distance = side ap1 = average_vector([obj_mtx @ v.co for v in sel_verts]) if sel_verts2: ap2 = average_vector([obj_mtx2 @ v.co for v in sel_verts2]) setpos = average_vector((ap1, ap2)) else: setpos = ap1 n = v1.normalized().cross(v2.normalized()) u = n.cross(v1.normalized()) t = u.cross(n) setrot = Matrix((u, n, t)).to_4x4().inverted() else: self.report({ "INFO" }, "FitPrim: Invalid Vert Mode Selection: Select 1, 2 or 4 verts" ) return {"CANCELLED"} # ----------------------------------------------------------------------------------------- # EDGE MODE # ----------------------------------------------------------------------------------------- elif sel_mode[1]: one_line, loops, loops2 = False, [], [] sel_edges = [e for e in bm.edges if e.select] vps = [e.verts[:] for e in sel_edges] active_edge = bm.select_history.active if active_edge: active_edge_facenormals = [ correct_normal(obj_mtx, p.normal) for p in active_edge.link_faces ] active_edge_normal = Vector( average_vector(active_edge_facenormals)).normalized() # GET ISLANDS if multi_object_mode and active_edge: # print("multi obj mode") # todo: limited multiobj mode, rework one-for-all? sel_edges2 = [e for e in bm2.edges if e.select] vps2 = [e.verts for e in sel_edges2] p1 = get_loops(vps, legacy=True) p2 = get_loops(vps2, legacy=True) if p1 and p2: a1, a2 = obj_mtx @ p1[0][0].co, obj_mtx @ p1[0][-1].co b1, b2 = obj_mtx2 @ p2[0][0].co, obj_mtx2 @ p2[0][-1].co else: a1, a2 = obj_mtx @ sel_verts[0].co, obj_mtx @ sel_verts[ -1].co b1, b2 = obj_mtx2 @ sel_verts2[ 0].co, obj_mtx2 @ sel_verts2[-1].co b_avg = get_midpoint(b1, b2) spacing, mp = get_closest_midpoint(a1, a2, b_avg) u_v = Vector(a1 - b1).normalized() t_v = Vector(a1 - a2).normalized() n_v = u_v.cross(t_v).normalized() setrot = rotation_from_vector(n_v, t_v, rotate90=True) setpos = mp side = spacing distance = spacing elif active_edge: # same (active) obj island selections if len(sel_edges) > 1: if len(sel_edges) == 2 and not bool( set(sel_edges[0].verts).intersection( sel_edges[1].verts)): a1p, a2p = sel_edges[0].verts, sel_edges[1].verts a1, a2 = obj_mtx @ a1p[0].co, obj_mtx @ a1p[1].co b_avg = average_vector( [obj_mtx @ a2p[0].co, obj_mtx @ a2p[1].co]) lf1 = sel_edges[0].link_faces[:] lf = [ f for f in sel_edges[1].link_faces[:] if f in lf1 ] v1 = Vector((obj_mtx @ a1p[0].co - obj_mtx @ a1p[1].co)).normalized() v2 = Vector((obj_mtx @ a2p[0].co - obj_mtx @ a2p[1].co)).normalized() if not lf: u_v = Vector(a1 - (obj_mtx @ a2p[0].co)).normalized() t_v = Vector(a1 - a2).normalized() n_v = u_v.cross(t_v).normalized() setrot = rotation_from_vector(n_v, t_v, rotate90=True) else: n = correct_normal(obj_mtx, lf[0].normal) # t = average_vector((v1, v2)) # if sum(t) == 0: # print("AVG FAIL") t = v1 setrot = rotation_from_vector(n, t, rotate90=True) spacing, mp = get_closest_midpoint(a1, a2, b_avg) setpos = mp side = spacing distance = spacing else: loops = get_loops(vps, legacy=True) if len(loops) > 1: # print ("single obj - multi loop", len(loops)) # Check for closed loops a_ep1, a_ep2 = loops[0][0], loops[0][-1] b_ep1, b_ep2 = loops[1][0], loops[1][-1] if a_ep1 == a_ep2: a_ep2 = loops[0][-2] if b_ep1 == b_ep2: b_ep2 = loops[1][-2] # get coords & set vals a1, a2 = obj_mtx @ a_ep1.co, obj_mtx @ a_ep2.co b1, b2 = obj_mtx @ b_ep1.co, obj_mtx @ b_ep2.co b_avg = get_midpoint(b1, b2) spacing, mp = get_closest_midpoint(a1, a2, b_avg) u_v = Vector((0, 0, 1)) t_v = Vector(a1 - a2).normalized() if abs(u_v.dot(t_v)) == 1: u_v = Vector((1, 0, 0)) n_v = u_v.cross(t_v).normalized() setrot = rotation_from_vector(n_v, t_v, rotate90=False) setpos = mp side = spacing distance = spacing elif len(loops) == 1 or len(sel_edges) == 1: # print ("single obj - single loop") single_line = False if len(sel_edges) != 1: if loops[0][0] != loops[0][-1]: single_line = True if len(sel_edges) != 1 and not single_line: vecs = [ Vector((obj_mtx @ vp[0].co) - (obj_mtx @ vp[1].co)).normalized() for vp in vps ] normal = average_vector([ correct_normal(obj_mtx, v.normal) for v in flatten(vps) ]) side, center, start_vec = get_sides(obj_mtx, vecs, vps) distance = side setpos = center setrot = rotation_from_vector(normal, start_vec) elif len(sel_edges) == 1 or single_line: # print("1 edge --> one line", one_line) p1, p2 = obj_mtx @ sel_verts[ 0].co, obj_mtx @ sel_verts[1].co t_v = Vector(p1 - p2).normalized() n_v = active_edge_normal setrot = rotation_from_vector(n_v, t_v) distance = get_distance(p1, p2) setpos = get_midpoint(p1, p2) side = distance else: print("Unexpected: Aborting operation.") return {'CANCELLED'} # ----------------------------------------------------------------------------------------- # FACE MODE # ----------------------------------------------------------------------------------------- elif sel_mode[2] and active_face and sel_poly: fail_island = False # GET ISLANDS if multi_object_mode and active_face: first_island = sel_verts point = obj_mtx @ active_face.calc_center_median() firstcos = [obj_mtx @ v.co for v in active_face.verts] secondcos = [obj_mtx2 @ v.co for v in active_face2.verts] if firstcos and secondcos: island_mode = True distance = point_to_plane(point, firstcos, secondcos) if distance: distance = abs(distance) else: # print("Multi obj Point to plane failed for some reason - using single island mode.") # island_mode = False fail_island = True else: # same (active) obj island selections first_island, second_island = get_selection_islands( sel_poly, active_face) # Ofc, needs correct order for point to plane, and I'll just rely on face.verts for that: calc_island_1 = active_face.verts[:] calc_island_2 = [] for p in sel_poly: verts = p.verts[:] for v in verts: if v in second_island: calc_island_2 = verts break if len(first_island) != 0 and len(second_island) != 0: firstcos = [obj_mtx @ v.co for v in calc_island_1] secondcos = [obj_mtx @ v.co for v in calc_island_2] distance = point_to_plane( obj_mtx @ active_face.calc_center_median(), firstcos, secondcos) if distance: distance = abs(distance) island_mode = True else: # print("Point to plane failed for some reason - using single island mode.") fail_island = True # print(distance) else: # Ngon mode first_island = sel_verts # GETVALUES if island_mode or fail_island: bpy.ops.mesh.select_all(action='DESELECT') for v in first_island: bm.verts[v.index].select = True bmesh.update_edit_mesh(obj.data) bpy.ops.mesh.select_mode(type='VERT') bpy.ops.mesh.select_mode(type='FACE') bm.faces.ensure_lookup_table() faces = [f for f in bm.faces if f.select] normal = average_vector( [correct_normal(obj_mtx, f.normal) for f in faces]) bpy.ops.mesh.region_to_loop() sel_edges = [e for e in bm.edges if e.select] vps = [e.verts[:] for e in sel_edges] vecs = [ Vector((obj_mtx @ vp[0].co) - (obj_mtx @ vp[1].co)).normalized() for vp in vps ] side, center, start_vec = get_sides(obj_mtx, vecs, vps) setrot = rotation_from_vector(normal, start_vec) # ----------------------------------------------------------------------------------------- # PROCESS # ----------------------------------------------------------------------------------------- if side: if self.ke_fitprim_option == "PLANE" and self.edit_mode != "OBJECT": if sel_mode[2]: setpos = center elif len(sel_verts) == 0 or sel_mode[0] or sel_mode[1]: side *= .5 distance = distance / 2 if self.sphere and sel_mode[0]: if not len(sel_verts) == 0: side = distance elif sel_mode[2]: if island_mode: side *= .5 offset = normal * distance * .5 distance *= .5 if self.sphere: side = distance else: side *= .5 distance = side offset = normal * side setpos = center + offset if not island_mode and self.sphere: setpos = setpos - offset # SET FINAL ROTATION if self.world: setrot = (0, 0, 0) if self.ke_fitprim_option == "PLANE" and not sel_verts: setpos[2] = 0 else: setrot = setrot.to_euler() # RUN OP if not self.edit_mode == "OBJECT": bpy.ops.mesh.select_mode(type='FACE') if self.itemize: if self.edit_mode != "OBJECT": bpy.ops.object.mode_set(mode="OBJECT") bpy.ops.transform.select_orientation(orientation='GLOBAL') cursor.location = setpos cursor.rotation_euler = setrot # ----------------------------------------------------------------------------------------- # CUBE # ----------------------------------------------------------------------------------------- if self.boxmode: bpy.ops.mesh.primitive_box_add(width=side, depth=side, height=distance, align='WORLD', location=setpos, rotation=setrot) if self.itemize or self.edit_mode == "OBJECT": bpy.ops.object.shade_smooth() bpy.context.object.data.use_auto_smooth = True # ----------------------------------------------------------------------------------------- # PLANE # ----------------------------------------------------------------------------------------- elif self.ke_fitprim_option == "PLANE": # side *= 2 enter = True if self.edit_mode == 'OBJECT' or self.itemize: enter = False bpy.ops.mesh.primitive_plane_add(enter_editmode=enter, align='WORLD', location=setpos, rotation=setrot, size=side, scale=(1, 1, 1)) if self.itemize or self.edit_mode == "OBJECT": bpy.ops.object.shade_smooth() bpy.context.object.data.use_auto_smooth = True # ----------------------------------------------------------------------------------------- # SPHERE # ----------------------------------------------------------------------------------------- elif self.sphere and not self.ke_fitprim_option == "QUADSPHERE": bpy.ops.mesh.primitive_uv_sphere_add( segments=self.sphere_seg, ring_count=self.sphere_ring, radius=side, align='WORLD', location=setpos, rotation=setrot) if self.itemize or self.edit_mode == "OBJECT": bpy.ops.object.shade_smooth() bpy.context.object.data.use_auto_smooth = True # ----------------------------------------------------------------------------------------- # QUADSPHERE # ----------------------------------------------------------------------------------------- elif self.ke_fitprim_option == "QUADSPHERE": cutnr = self.quadsphere_seg # calc compensated subd radius from cube v1_pos = setpos[0] + side, setpos[1] + side, setpos[2] + side rad = sqrt(sum([(a - b)**2 for a, b in zip(setpos, v1_pos)])) diff = side / rad side = (side * diff) distance = side bpy.ops.mesh.primitive_box_add(width=side, depth=side, height=distance, align='WORLD', location=setpos, rotation=setrot, name="QuadSphere") if self.itemize or self.edit_mode == "OBJECT": bpy.ops.object.mode_set(mode="EDIT") bpy.ops.mesh.subdivide(number_cuts=cutnr, smoothness=1) bpy.ops.mesh.faces_shade_smooth() bpy.ops.object.mode_set(mode="OBJECT") else: bpy.ops.mesh.subdivide(number_cuts=cutnr, smoothness=1) bpy.ops.mesh.faces_shade_smooth() bpy.ops.ed.undo_push() # bpy.context.object.data.use_auto_smooth = as_check if self.itemize or self.edit_mode == "OBJECT": bpy.ops.object.shade_smooth() bpy.context.object.data.use_auto_smooth = True # ----------------------------------------------------------------------------------------- # CYLINDER # ----------------------------------------------------------------------------------------- else: bpy.ops.mesh.primitive_cylinder_add(vertices=self.cyl_sides, radius=side, depth=distance * 2, enter_editmode=False, align='WORLD', location=setpos, rotation=setrot) if self.modal: if self.itemize or self.edit_mode == "OBJECT": bpy.ops.object.mode_set(mode="EDIT") self.settings = (side, distance, setpos, setrot) context.window_manager.modal_handler_add(self) self._timer = context.window_manager.event_timer_add( 0.5, window=context.window) args = (self, context, self.screen_x) self._handle = bpy.types.SpaceView3D.draw_handler_add( draw_callback_px, args, 'WINDOW', 'POST_PIXEL') bpy.context.space_data.overlay.show_cursor = False return {'RUNNING_MODAL'} if multi_object_mode and not self.itemize: second_obj.select_set(state=True) obj.select_set(state=True) bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() else: self.report({"INFO"}, "FitPrim: Invalid Selection / No Active Element?") if not self.select and not self.itemize and not self.edit_mode == "OBJECT": bpy.ops.mesh.select_all(action='DESELECT') if self.itemize: bpy.ops.transform.select_orientation(orientation=og_orientation) cursor.location = self.og_cloc cursor.rotation_euler = self.og_crot bpy.context.active_object.select_set(state=True) self.ke_fitprim_itemize = False return {"FINISHED"}
def extend(obj, EXTEND_MODE): import bmesh me = obj.data bm = bmesh.from_edit_mesh(me) faces = [f for f in bm.faces if f.select and len(f.verts) == 4] if not faces: return 0 f_act = bm.faces.active if f_act is None: return STATUS_ERR_ACTIVE_FACE if not f_act.select: return STATUS_ERR_NOT_SELECTED elif len(f_act.verts) != 4: return STATUS_ERR_NOT_QUAD # Script will fail without UVs. if not me.uv_layers: me.uv_layers.new() uv_act = bm.loops.layers.uv.active # our own local walker def walk_face_init(faces, f_act): # first tag all faces True (so we don't uvmap them) for f in bm.faces: f.tag = True # then tag faces arg False for f in faces: f.tag = False # tag the active face True since we begin there f_act.tag = True def walk_face(f): # all faces in this list must be tagged f.tag = True faces_a = [f] faces_b = [] while faces_a: for f in faces_a: for l in f.loops: l_edge = l.edge if (l_edge.is_manifold is True) and (l_edge.seam is False): l_other = l.link_loop_radial_next f_other = l_other.face if not f_other.tag: yield (f, l, f_other) f_other.tag = True faces_b.append(f_other) # swap faces_a, faces_b = faces_b, faces_a faces_b.clear() def walk_edgeloop(l): """ Could make this a generic function """ e_first = l.edge e = None while True: e = l.edge yield e # don't step past non-manifold edges if e.is_manifold: # welk around the quad and then onto the next face l = l.link_loop_radial_next if len(l.face.verts) == 4: l = l.link_loop_next.link_loop_next if l.edge is e_first: break else: break else: break def extrapolate_uv( fac, l_a_outer, l_a_inner, l_b_outer, l_b_inner, ): l_b_inner[:] = l_a_inner l_b_outer[:] = l_a_inner + ((l_a_inner - l_a_outer) * fac) def apply_uv(_f_prev, l_prev, _f_next): l_a = [None, None, None, None] l_b = [None, None, None, None] l_a[0] = l_prev l_a[1] = l_a[0].link_loop_next l_a[2] = l_a[1].link_loop_next l_a[3] = l_a[2].link_loop_next # l_b # +-----------+ # |(3) |(2) # | | # |l_next(0) |(1) # +-----------+ # ^ # l_a | # +-----------+ # |l_prev(0) |(1) # | (f) | # |(3) |(2) # +-----------+ # copy from this face to the one above. # get the other loops l_next = l_prev.link_loop_radial_next if l_next.vert != l_prev.vert: l_b[1] = l_next l_b[0] = l_b[1].link_loop_next l_b[3] = l_b[0].link_loop_next l_b[2] = l_b[3].link_loop_next else: l_b[0] = l_next l_b[1] = l_b[0].link_loop_next l_b[2] = l_b[1].link_loop_next l_b[3] = l_b[2].link_loop_next l_a_uv = [l[uv_act].uv for l in l_a] l_b_uv = [l[uv_act].uv for l in l_b] if EXTEND_MODE == 'LENGTH_AVERAGE': d1 = edge_lengths[l_a[1].edge.index][0] d2 = edge_lengths[l_b[2].edge.index][0] try: fac = d2 / d1 except ZeroDivisionError: fac = 1.0 elif EXTEND_MODE == 'LENGTH': a0, b0, c0 = l_a[3].vert.co, l_a[0].vert.co, l_b[3].vert.co a1, b1, c1 = l_a[2].vert.co, l_a[1].vert.co, l_b[2].vert.co d1 = (a0 - b0).length + (a1 - b1).length d2 = (b0 - c0).length + (b1 - c1).length try: fac = d2 / d1 except ZeroDivisionError: fac = 1.0 else: fac = 1.0 extrapolate_uv(fac, l_a_uv[3], l_a_uv[0], l_b_uv[3], l_b_uv[0]) extrapolate_uv(fac, l_a_uv[2], l_a_uv[1], l_b_uv[2], l_b_uv[1]) # ------------------------------------------- # Calculate average length per loop if needed if EXTEND_MODE == 'LENGTH_AVERAGE': bm.edges.index_update() edge_lengths = [None] * len(bm.edges) for f in faces: # we know its a quad l_quad = f.loops[:] l_pair_a = (l_quad[0], l_quad[2]) l_pair_b = (l_quad[1], l_quad[3]) for l_pair in (l_pair_a, l_pair_b): if edge_lengths[l_pair[0].edge.index] is None: edge_length_store = [-1.0] edge_length_accum = 0.0 edge_length_total = 0 for l in l_pair: if edge_lengths[l.edge.index] is None: for e in walk_edgeloop(l): if edge_lengths[e.index] is None: edge_lengths[e.index] = edge_length_store edge_length_accum += e.calc_length() edge_length_total += 1 edge_length_store[0] = edge_length_accum / edge_length_total # done with average length # ------------------------ walk_face_init(faces, f_act) for f_triple in walk_face(f_act): apply_uv(*f_triple) bmesh.update_edit_mesh(me, False) return STATUS_OK
def main(self, context, chboxVert0, chboxVert1, chboxVert2): finalizar_uniendocaras = True #almacena caras obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) listacaras = [] for face in bm.faces: if face.select and len(face.verts) == 3: listacaras.append(face) #bmesh.update_edit_mesh(me, True) #################### separa caras separarcaras() ########################## #obj = bpy.context.object #me = obj.data #bm = bmesh.from_edit_mesh(me) #vuelve a seleccionar caras for face in listacaras: face.select = True ########################## obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) ### aplicar división for face in listacaras: if face.select: print("cara seleccionada") centro_cara = mathutils.Vector( face.calc_center_median_weighted()) if len(face.verts) == 3: print("es un triangulo") vertices = [v for v in face.verts] print(len(vertices)) vv1, vv2, vv3 = [v for v in vertices] print(vv1, vv2, vv3) v1, v2, v3 = [v.co for v in vertices] print("cordenada vertice " + str(v1)) print("cordenada vertice " + str(v2)) print("cordenada vertice " + str(v3)) #agrupamos todas las aristas seleccionadas y no ocultas de la cara aristas = [ a for a in face.edges if (a.select and not a.hide) ] #las asignamos a variables independientes a1, a2, a3 = [a for a in aristas] #creamos los largos de cada una de las aristas l1, l2, l3 = [a.calc_length() for a in aristas] print(l1, '\n', l2, '\n', l3) #distancia entre vertices segun sus cordinadas c = ((((v1[0]) - (v2[0]) * (v1[0]) - (v2[0]))), (((v1[1]) - (v2[1]) * (v1[1]) - (v2[1]))), (((v1[2]) - (v2[2]) * (v1[2]) - (v2[2])))) print(c) distancia1 = math.sqrt(math.fabs(c[0])) + math.sqrt( math.fabs(c[1])) + math.sqrt(math.fabs(c[2])) print(distancia1) #divide uno de los bordes. #mid_vec1 = v3.lerp(v2, razon_bisectriz1) #bmesh.utils.edge_split(a2, a2.verts[0], 0.5) ##################################### #llamo a la funcion que calcula los angulos: #calcularangulos(l1,l2,l3) #funcionando #calcularbisectrices(l1,l2,l3,v1,v2,v3) #falta por comprobar if chboxVert0: vertice1 = True calcularpuntobisectrices(face, l2, l3, l1, v2, v3, v1, a2, a3, a1, vv2, vv3, vv1, chboxVert0, chboxVert1, chboxVert2) if chboxVert1: calcularpuntobisectrices(face, l1, l2, l3, v1, v2, v3, a1, a2, a3, vv1, vv2, vv3, chboxVert0, chboxVert1, chboxVert2) if chboxVert2: calcularpuntobisectrices(face, l3, l1, l2, v3, v1, v2, a3, a1, a2, vv3, vv1, vv2, chboxVert0, chboxVert1, chboxVert2) else: print("DEBE SER UN TRIANGULO") else: print("cara no seleccionada") ## actualizar toda la malla bmesh.update_edit_mesh(me, True) if finalizar_uniendocaras: bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.remove_doubles() bpy.ops.mesh.select_all(action='DESELECT') return {'FINISHED'}
location_list = [] uv_list = [] uv_list.clear() location_list.clear() obj = bpy.context.active_object for v in obj.data.vertices: vec = copy.copy(v.co) vec.x = random() vec.y = random() vec.z = random() location_list.append(vec) uv_list = [p[:2] for p in location_list] import bmesh mesh = obj.data bm = bmesh.from_edit_mesh(mesh) uv_layer = bm.loops.layers.uv.active for bm_face in bm.faces: id = bm_face.loops[0].vert.index print(id) for v in bm_face.loops: v[uv_layer].uv[0] = v[uv_layer].uv[0] + uv_list[id][0] v[uv_layer].uv[1] = v[uv_layer].uv[1] + uv_list[id][1] bmesh.update_edit_mesh(mesh) bpy.ops.object.editmode_toggle()
def modal(self, context, event): if event.type == 'X': self.xlock = False self.ylock = True if event.type == 'Y': self.xlock = True self.ylock = False #test is middle mouse held down if event.type == 'MIDDLEMOUSE' and event.value == 'PRESS': self.constrainttest = True if event.type == 'MIDDLEMOUSE' and event.value == 'RELEASE': self.constrainttest = False #test if mouse is in the right quadrant for X or Y movement if self.constrainttest: mouseangle = math.atan2(event.mouse_y - self.first_mouse_y, event.mouse_x - self.first_mouse_x) mousetestx = False if (mouseangle < 0.785 and mouseangle > -0.785) or (mouseangle > 2.355 or mouseangle < -2.355): mousetestx = True if mousetestx: self.xlock = True self.ylock = False else: self.xlock = False self.ylock = True if event.type == 'MOUSEMOVE': deltax = self.first_mouse_x - event.mouse_x deltay = self.first_mouse_y - event.mouse_y if event.shift and not event.ctrl: #self.delta*=.1 #reset origin position to shift into precision mode if not self.shiftreset: self.shiftreset = True self.first_mouse_x = event.mouse_x + 1000 / self.s2 self.first_mouse_y = event.mouse_y + 1000 / self.s2 for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv = vert[ self.bm.loops.layers.uv.active].uv deltax = self.first_mouse_x - event.mouse_x deltay = self.first_mouse_y - event.mouse_y deltax *= 0.001 * self.s2 deltay *= 0.001 * self.s2 else: #reset origin position to shift into normal mode if self.shiftreset: self.shiftreset = False self.first_mouse_x = event.mouse_x + 1000 / self.s1 self.first_mouse_y = event.mouse_y + 1000 / self.s1 for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv = vert[ self.bm.loops.layers.uv.active].uv deltax = self.first_mouse_x - event.mouse_x deltay = self.first_mouse_y - event.mouse_y deltax *= 0.001 * self.s1 deltay *= 0.001 * self.s1 if not self.xlock and not self.ylock: delta = (deltax + deltay) * .5 deltax = delta deltay = delta if self.xlock: deltax = 1 if self.ylock: deltay = 1 if event.ctrl and not event.shift: deltax = math.floor(deltax * self.scale_snap) / self.scale_snap deltay = math.floor(deltay * self.scale_snap) / self.scale_snap if event.ctrl and event.shift: deltax = math.floor( deltax * self.scale_snap * self.scale_snap) / (self.scale_snap * self.scale_snap) deltay = math.floor( deltay * self.scale_snap * self.scale_snap) / (self.scale_snap * self.scale_snap) #loop through every selected face and move the uv's using original uv as reference for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): vert[self.bm.loops.layers.uv.active].uv.x = ( (deltax) * self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv.x) + ( (1 - (deltax)) * self.xcenter) vert[self.bm.loops.layers.uv.active].uv.y = ( (deltay) * self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv.y) + ( (1 - (deltay)) * self.ycenter) #update mesh bmesh.update_edit_mesh(self.mesh, False, False) elif event.type == 'LEFTMOUSE': #finish up and make sure changes are locked in place bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} elif event.type in {'RIGHTMOUSE', 'ESC'}: #reset all uvs to reference for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): vert[self.bm.loops.layers.uv. active].uv = self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv #update mesh bmesh.update_edit_mesh(self.mesh, False, False) return {'CANCELLED'} return {'RUNNING_MODAL'}
def modal(self, context, event): #context.area.header_text_set( # "DUV UVTranslate: X/Y - contrain along X/Y Axis, MMB drag - alternative axis contrain method, SHIFT - precision mode, CTRL - stepped mode, CTRL + SHIFT - stepped with smaller increments") #context.area.tag_redraw() # setup constraints first if event.type == 'X': self.stateswitch = True self.xlock = False self.ylock = True if event.type == 'Y': self.stateswitch = True self.xlock = True self.ylock = False # test is middle mouse held down if event.type == 'MIDDLEMOUSE' and event.value == 'PRESS': self.constrainttest = True if event.type == 'MIDDLEMOUSE' and event.value == 'RELEASE': self.constrainttest = False # test if mouse is in the right quadrant for X or Y movement if self.constrainttest: mouseangle = math.atan2(event.mouse_y - self.first_mouse_y, event.mouse_x - self.first_mouse_x) mousetestx = False if (mouseangle < 0.785 and mouseangle > -0.785) or (mouseangle > 2.355 or mouseangle < -2.355): mousetestx = True if mousetestx: self.xlock = False self.ylock = True else: self.xlock = True self.ylock = False if mousetestx is not self.mousetestx: self.stateswitch = True self.mousetestx = not self.mousetestx if self.stateswitch: self.stateswitch = False # reset to start editing from start position for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): reset_uv = self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv vert[self.bm.loops.layers.uv.active].uv = reset_uv if event.type == 'MOUSEMOVE': self.delta = ((self.first_mouse_x - event.mouse_x), (self.first_mouse_y - event.mouse_y)) sensitivity = 0.001 if not self.do_pixel_snap else 0.1 self.delta = Vector(self.delta) * sensitivity if self.do_pixel_snap: self.delta.x = int(round(self.delta.x)) self.delta.y = int(round(self.delta.y)) if event.shift and not event.ctrl: self.delta *= .1 # reset origin position to shift into precision mode if not self.shiftreset: self.shiftreset = True self.first_mouse_x = event.mouse_x self.first_mouse_y = event.mouse_y for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): reset_uv = vert[ self.bm.loops.layers.uv.active].uv self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv. active].uv = reset_uv self.delta = (0, 0) self.delta = Vector(self.delta) else: # reset origin position to shift into normal mode if self.shiftreset: self.shiftreset = False self.first_mouse_x = event.mouse_x self.first_mouse_y = event.mouse_y for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): reset_uv = vert[ self.bm.loops.layers.uv.active].uv self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv. active].uv = reset_uv self.delta = (0, 0) self.delta = Vector(self.delta) if event.ctrl and not event.shift: self.delta.x = math.floor( self.delta.x * self.move_snap) / self.move_snap self.delta.y = math.floor( self.delta.y * self.move_snap) / self.move_snap if event.ctrl and event.shift: self.delta.x = math.floor( self.delta.x * (self.move_snap * self.move_snap)) / (self.move_snap * self.move_snap) self.delta.y = math.floor( self.delta.y * (self.move_snap * self.move_snap)) / (self.move_snap * self.move_snap) # loop through every selected face and move the uv's using original uv as reference for i, face in enumerate(self.bm.faces): if face.select is False: continue local_delta = self.delta.copy() if self.do_pixel_snap and face.index in self.pixel_steps.keys( ): pixel_step = self.pixel_steps[face.index] local_delta.x *= pixel_step.x local_delta.y *= pixel_step.y uv_x_axis = Vector((1.0, 0.0)) uv_y_axis = Vector((0.0, 1.0)) if self.xlock: uv_x_axis = Vector((0, 0)) if self.ylock: uv_y_axis = Vector((0, 0)) for o, vert in enumerate(face.loops): origin_uv = self.bm2.faces[i].loops[o][ self.bm2.loops.layers.uv.active].uv uv_offset = local_delta.x * uv_x_axis + local_delta.y * uv_y_axis vert[self.bm.loops.layers.uv. active].uv = origin_uv + uv_offset # update mesh bmesh.update_edit_mesh(self.mesh, False, False) elif event.type == 'LEFTMOUSE': # finish up and make sure changes are locked in place bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} elif event.type in {'RIGHTMOUSE', 'ESC'}: # reset all uvs to reference for i, face in enumerate(self.bm.faces): if face.select: for o, vert in enumerate(face.loops): reset_uv = self.bm_orig.faces[i].loops[o][ self.bm_orig.loops.layers.uv.active].uv vert[self.bm.loops.layers.uv.active].uv = reset_uv # update mesh bmesh.update_edit_mesh(self.mesh, False, False) return {'CANCELLED'} return {'RUNNING_MODAL'}
def expand_vert(self, context, event): addon_prefs = context.preferences.addons[__name__].preferences ob = context.active_object obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) region = context.region region_3d = context.space_data.region_3d rv3d = context.space_data.region_3d for v in bm.verts: if v.select: v_active = v try: depth_location = v_active.co except: return {'CANCELLED'} # create vert in mouse cursor location mouse_pos = Vector((event.mouse_region_x, event.mouse_region_y)) location_3d = view3d_utils.region_2d_to_location_3d(region, rv3d, mouse_pos, depth_location) c_verts = [] # find and select linked edges that are open (<2 faces connected) add those edge verts to c_verts list linked = v_active.link_edges for edges in linked: if len(edges.link_faces) < 2: edges.select = True for v in edges.verts: if v is not v_active: c_verts.append(v) # Compare distance in 2d between mouse and edges middle points screen_pos_va = view3d_utils.location_3d_to_region_2d(region, region_3d, ob.matrix_world @ v_active.co) screen_pos_v1 = view3d_utils.location_3d_to_region_2d(region, region_3d, ob.matrix_world @ c_verts[0].co) screen_pos_v2 = view3d_utils.location_3d_to_region_2d(region, region_3d, ob.matrix_world @ c_verts[1].co) mid_pos_v1 = Vector(((screen_pos_va[0] + screen_pos_v1[0]) / 2, (screen_pos_va[1] + screen_pos_v1[1]) / 2)) mid_pos_V2 = Vector(((screen_pos_va[0] + screen_pos_v2[0]) / 2, (screen_pos_va[1] + screen_pos_v2[1]) / 2)) dist1 = math.log10(pow((mid_pos_v1[0] - mouse_pos[0]), 2) + pow((mid_pos_v1[1] - mouse_pos[1]), 2)) dist2 = math.log10(pow((mid_pos_V2[0] - mouse_pos[0]), 2) + pow((mid_pos_V2[1] - mouse_pos[1]), 2)) bm.normal_update() bm.verts.ensure_lookup_table() # Deselect not needed point and create new face if dist1 < dist2: c_verts[1].select = False lleft = c_verts[0].link_faces else: c_verts[0].select = False lleft = c_verts[1].link_faces lactive = v_active.link_faces # lverts = lactive[0].verts mat_index = lactive[0].material_index smooth = lactive[0].smooth for faces in lactive: if faces in lleft: cface = faces if len(faces.verts) == 3: bm.normal_update() bmesh.update_edit_mesh(obj.data) bpy.ops.mesh.select_all(action='DESELECT') v_active.select = True bpy.ops.mesh.rip_edge_move('INVOKE_DEFAULT') return {'FINISHED'} lverts = cface.verts # create triangle with correct normal orientation # if You looking at that part - yeah... I know. I still dont get how blender calculates normals... # from L to R if dist1 < dist2: if (lverts[0] == v_active and lverts[3] == c_verts[0]) \ or (lverts[2] == v_active and lverts[1] == c_verts[0]) \ or (lverts[1] == v_active and lverts[0] == c_verts[0]) \ or (lverts[3] == v_active and lverts[2] == c_verts[0]): v_new = bm.verts.new(v_active.co) face_new = bm.faces.new((c_verts[0], v_new, v_active)) elif (lverts[1] == v_active and lverts[2] == c_verts[0]) \ or (lverts[0] == v_active and lverts[1] == c_verts[0]) \ or (lverts[3] == v_active and lverts[0] == c_verts[0]) \ or (lverts[2] == v_active and lverts[3] == c_verts[0]): v_new = bm.verts.new(v_active.co) face_new = bm.faces.new((v_active, v_new, c_verts[0])) else: pass # from R to L else: if (lverts[2] == v_active and lverts[3] == c_verts[1]) \ or (lverts[0] == v_active and lverts[1] == c_verts[1]) \ or (lverts[1] == v_active and lverts[2] == c_verts[1]) \ or (lverts[3] == v_active and lverts[0] == c_verts[1]): v_new = bm.verts.new(v_active.co) face_new = bm.faces.new((v_active, v_new, c_verts[1])) elif (lverts[0] == v_active and lverts[3] == c_verts[1]) \ or (lverts[2] == v_active and lverts[1] == c_verts[1]) \ or (lverts[1] == v_active and lverts[0] == c_verts[1]) \ or (lverts[3] == v_active and lverts[2] == c_verts[1]): v_new = bm.verts.new(v_active.co) face_new = bm.faces.new((c_verts[1], v_new, v_active)) else: pass # set smooth and mat based on starting face if addon_prefs.tris_from_v_mat: face_new.material_index = bpy.context.object.active_material_index else: face_new.material_index = mat_index face_new.smooth = smooth # update normals bpy.ops.mesh.select_all(action='DESELECT') v_new.select = True bm.select_history.add(v_new) bm.normal_update() bmesh.update_edit_mesh(obj.data) bpy.ops.transform.translate('INVOKE_DEFAULT')