Instantly share code, notes, and snippets.

Embed
What would you like to do?
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
bl_info = {
'name': 'Index Visualiser (BMesh)',
'author': 'Bartius Crouch, CoDEmanX, zeffii',
'version': (2, 6, 14),
'blender': (2, 65, 0),
'location': 'View3D > Properties panel > Mesh Display tab (edit-mode)',
'warning': '', # used for warning icon and text in addons panel
'description': 'Display the indices of vertices, edges and faces '\
'in the 3d-view',
'wiki_url': 'http://wiki.blender.org/index.php/Extensions:2.5/Py/'\
'Scripts/3D_interaction/Index_Visualiser',
'tracker_url': 'http://projects.blender.org/tracker/index.php?'\
'func=detail&aid=21557',
'category': '3D View'}
"""
Display the indices of vertices, edges and faces in the 3d-view.
How to use:
- Select a mesh and go into editmode
- Display the properties panel (N-key)
- Go to the Mesh Display tab, it helps to fold the tabs above it
- Press the 'Visualise indices button'
"""
import bpy
import bgl
import blf
import mathutils
import bmesh
import math
def adjust_list(in_list, x, y):
return [[old_x + x , old_y + y] for (old_x, old_y) in in_list]
def get_points(amp, center, index):
'''
amp: radius of rounded edges
center: location on screen
index: string representation of the index number
returns: rounded rect point_list used for background.
'''
cx, cy = center
width, height = blf.dimensions(0, index)
width += 2
height += 4
width -= (2*amp)
height -= (2*amp)
pos_list, final_list = [], []
n_points = 12
seg_angle = 2*math.pi / n_points
for i in range(n_points+1):
angle = i * seg_angle
x = math.cos(angle) * amp + cx
y = -math.sin(angle) * amp + cy
pos_list.append([x, y])
w_list, h_list = [1,-1,-1,1], [-1,-1,1,1]
slice_list = [[i,i+4] for i in range(0, n_points, 3)]
for idx, (start, end) in enumerate(slice_list):
point_array = pos_list[start:end]
w = width * w_list[idx]
h = height * h_list[idx]
final_list += adjust_list(point_array, w, h)
return final_list
# calculate locations and store them as ID property in the mesh
def draw_callback_px(self, context):
# polling
if context.mode != "EDIT_MESH":
return
# get screen information
region = context.region
mid_x = region.width / 2
mid_y = region.height / 2
width = region.width
height = region.height
# get matrices
view_mat = context.space_data.region_3d.perspective_matrix
ob_mat = context.active_object.matrix_world
total_mat = view_mat * ob_mat
text_height = 13
blf.size(0, text_height, 72)
def draw_index(rgb, index, center):
vec = total_mat * center # order is important
# dehomogenise
vec = mathutils.Vector((vec[0] / vec[3], vec[1] / vec[3], vec[2] / vec[3]))
x = int(mid_x + vec[0] * width / 2)
y = int(mid_y + vec[1] * height / 2)
index = str(index)
polyline = get_points(amp=5, center=(x,y), index=index)
''' draw polygon '''
bgl.glColor4f(0.103, 0.2, 0.2, 0.2)
bgl.glBegin(bgl.GL_POLYGON)
for segment in polyline:
bgl.glVertex2f(*segment)
bgl.glEnd()
txt_width, txt_height = blf.dimensions(0, index)
''' draw text '''
bgl.glColor3f(*rgb)
blf.position(0, x-(txt_width/2), y-(txt_height/2), 0)
blf.draw(0, index)
vert_idx_color = (1.0, 1.0, 1.0)
edge_idx_color = (1.0, 1.0, 0.0)
face_idx_color = (1.0, 0.8, 0.8)
scene = context.scene
me = context.active_object.data
bm = bmesh.from_edit_mesh(me)
if scene.live_mode:
me.update()
if scene.display_vert_index:
for v in bm.verts:
if not v.hide and \
(v.select or not scene.display_sel_only):
## CoDEmanx: bm.verts.index_update()?
draw_index(vert_idx_color, v.index, v.co.to_4d())
if scene.display_edge_index:
for e in bm.edges:
if not e.hide and \
(e.select or not scene.display_sel_only):
v1 = e.verts[0].co
v2 = e.verts[1].co
loc = v1 + ((v2 - v1) / 2)
draw_index(edge_idx_color, e.index, loc.to_4d())
if scene.display_face_index:
for f in bm.faces:
if not f.hide and \
(f.select or not scene.display_sel_only):
draw_index(face_idx_color, f.index, f.calc_center_median().to_4d())
# operator
class IndexVisualiser(bpy.types.Operator):
bl_idname = "view3d.index_visualiser"
bl_label = "Index Visualiser"
bl_description = "Toggle the visualisation of indices"
_handle = None
@classmethod
def poll(cls, context):
return context.mode=="EDIT_MESH"
def modal(self, context, event):
if context.area:
context.area.tag_redraw()
# removal of callbacks when operator is called again
if context.scene.display_indices == -1:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
context.scene.display_indices = 0
return {"CANCELLED"}
return {"PASS_THROUGH"}
def invoke(self, context, event):
if context.area.type == "VIEW_3D":
if context.scene.display_indices < 1:
# operator is called for the first time, start everything
context.scene.display_indices = 1
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px,
(self, context), 'WINDOW', 'POST_PIXEL')
context.window_manager.modal_handler_add(self)
return {"RUNNING_MODAL"}
else:
# operator is called again, stop displaying
context.scene.display_indices = -1
return {'RUNNING_MODAL'}
else:
self.report({"WARNING"}, "View3D not found, can't run operator")
return {"CANCELLED"}
# defining the panel
def menu_func(self, context):
self.layout.separator()
col = self.layout.column(align=True)
col.operator(IndexVisualiser.bl_idname, text="Visualize indices")
row = col.row(align=True)
row.active = (context.mode=="EDIT_MESH" and \
context.scene.display_indices==1)
row.prop(context.scene, "display_vert_index", toggle=True)
row.prop(context.scene, "display_edge_index", toggle=True)
row.prop(context.scene, "display_face_index", toggle=True)
row = col.row(align=True)
row.active = context.mode == "EDIT_MESH" and \
context.scene.display_indices == 1
row.prop(context.scene, "display_sel_only")
#row.prop(context.scene, "live_mode")
def register_properties():
bpy.types.Scene.display_indices = bpy.props.IntProperty(
name="Display indices",
default=0)
#context.scene.display_indices = 0
bpy.types.Scene.display_sel_only = bpy.props.BoolProperty(
name="Selected only",
description="Only display indices of selected vertices/edges/faces",
default=True)
bpy.types.Scene.display_vert_index = bpy.props.BoolProperty(
name="Vertices",
description="Display vertex indices", default=True)
bpy.types.Scene.display_edge_index = bpy.props.BoolProperty(
name="Edges",
description="Display edge indices")
bpy.types.Scene.display_face_index = bpy.props.BoolProperty(
name="Faces",
description="Display face indices")
bpy.types.Scene.live_mode = bpy.props.BoolProperty(
name="Live",
description="Toggle live update of the selection, can be slow",
default=False)
def unregister_properties():
del bpy.types.Scene.display_indices
del bpy.types.Scene.display_sel_only
del bpy.types.Scene.display_vert_index
del bpy.types.Scene.display_edge_index
del bpy.types.Scene.display_face_index
del bpy.types.Scene.live_mode
def register():
register_properties()
bpy.utils.register_class(IndexVisualiser)
bpy.types.VIEW3D_PT_view3d_meshdisplay.append(menu_func)
def unregister():
bpy.utils.unregister_class(IndexVisualiser)
unregister_properties()
bpy.types.VIEW3D_PT_view3d_meshdisplay.remove(menu_func)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment