import bgl, bpy, bmesh, mathutils
from mathutils import Vector
"""Functions for Project and UnProject"""
def get_viewport():
view = bgl.Buffer(bgl.GL_INT, 4)
bgl.glGetIntegerv(bgl.GL_VIEWPORT, view)
return view
def get_modelview_matrix():
model_matrix = bgl.Buffer(bgl.GL_DOUBLE, [4, 4])
bgl.glGetDoublev(bgl.GL_MODELVIEW_MATRIX, model_matrix)
return model_matrix
def get_projection_matrix():
proj_matrix = bgl.Buffer(bgl.GL_DOUBLE, [4, 4])
bgl.glGetDoublev(bgl.GL_PROJECTION_MATRIX, proj_matrix)
return proj_matrix
def get_depth(x, y):
depth = bgl.Buffer(bgl.GL_FLOAT, [0.0])
bgl.glReadPixels(x, y, 1, 1, bgl.GL_DEPTH_COMPONENT, bgl.GL_FLOAT, depth)
return depth
#mouse_coords_to_3D_view
def UnProject(x, y):
depth = get_depth(x, y)
#if (depth[0] != 1.0):
world_x = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
world_y = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
world_z = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
view1 = get_viewport()
model = get_modelview_matrix()
proj = get_projection_matrix ()
bgl.gluUnProject(x, y, depth[0],
model, proj,
view1,
world_x, world_y, world_z)
return (world_x[0], world_y[0], world_z[0])
"""Other Functions"""
def Project(x, y, z):
world_x = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
world_y = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
world_z = bgl.Buffer(bgl.GL_DOUBLE, 1, [0.0])
view3 = get_viewport()
model1 = get_modelview_matrix()
proj1 = get_projection_matrix ()
bgl.gluProject(x, y, z, model1, proj1, view3, world_x, world_y, world_z)
return (int(world_x[0]), int(world_y[0]))
def close_point_range(mcursor, vertices, location):
obj = bpy.context.active_object
if isinstance(vertices, bmesh.types.BMVert):
bgl.glColor4f(1.0, 0.0, 0.0, 1.0)
vert = obj.matrix_world * vertices.co
return vert
elif isinstance(vertices, bmesh.types.BMEdge):
#length = vertices.calc_length()
vert0 = obj.matrix_world * vertices.verts[0].co
vert1 = obj.matrix_world * vertices.verts[1].co
Pvert0 = Project(*vert0)
Pvert1 = Project(*vert1)
Lv0 = (Vector(Pvert0) - Vector(mcursor))
Lv1 = (Vector(Pvert1) - Vector(mcursor))
Lvv = (Vector(Pvert1) - Vector(Pvert0))
Lx0 = Lv0[0]**2+Lv0[1]**2
Lx1 = Lv1[0]**2+Lv1[1]**2
Lxv = Lvv[0]**2+Lvv[1]**2
factor = (0.5*(Lx0-Lx1)/Lxv)+0.5
if abs(Lx0-Lx1) < 500:
bgl.glColor4f(1.0, 0.0, 1.0, 1.0)
return (vert0+vert1)/2
else:
bgl.glColor4f(0.0, 0.5, 1.0, 1.0)
return vert0 + (vert1-vert0)*factor
else:
return location
"""drawing point OpenGL in mouse_coords_to_3D_view"""
def draw_callback_px(self, context):
# mouse coordinates relative to 3d view
x, y = self.mouse_path
vertices = self.geom
# mouse coordinates relative to Blender interface
view = get_viewport()
gmx = view[0] + x
gmy = view[1] + y
depth1 = get_depth(gmx, gmy)
mouse3d = UnProject(gmx, gmy)
# draw 3d point OpenGL in the 3D View
bgl.glEnable(bgl.GL_BLEND)
bgl.glColor4f(1.0, 0.8, 0.0, 1.0)
self.snap3d = close_point_range((gmx, gmy),vertices, Vector(mouse3d))
#print(snap3d)
bgl.glDepthRange(0,0)
bgl.glPointSize(10)
bgl.glBegin(bgl.GL_POINTS)
bgl.glVertex3f(*self.snap3d)
bgl.glEnd()
bgl.glDisable(bgl.GL_BLEND)
# draw 3d line OpenGL in the 3D View
bgl.glEnable(bgl.GL_BLEND)
bgl.glDepthRange(0,0.9999)
bgl.glColor4f(1.0, 0.8, 0.0, 1.0)
bgl.glLineWidth(2)
bgl.glBegin(bgl.GL_LINE_STRIP)
self.mouse_line = (self.lpoints, self.snap3d)
#print(self.snap3d)
for [a, b, c] in self.lpoints:
bgl.glVertex3f(a, b, c)
bgl.glVertex3f(*self.snap3d)
bgl.glEnd()
# restore opengl defaults
bgl.glDepthRange(0,1)
bgl.glPointSize(1)
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
context.area.header_text_set("hit: %.3f %.3f %.3f" % tuple(self.snap3d))
class PanelSnapUtilities(bpy.types.Panel) :
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_context = "mesh_edit"
bl_category = "Mano-Addons"
bl_label = "snap utilities"
@classmethod
def poll(cls, context):
return (context.object is not None and
context.object.type == 'MESH' and
context.object.data.is_editmode)
def draw(self, context) :
layout = self.layout
TheCol = layout.column(align = True)
TheCol.operator("action.snaputilities", text = "snaputilities")
class ModalDrawOperator(bpy.types.Operator):
"""Draw a point with the mouse"""
bl_idname = "action.snaputilities"
bl_label = "Simple Modal View3D Operator"
def modal(self, context, event):
context.area.tag_redraw()
if event.type == 'MOUSEMOVE':
self.mouse_path = (event.mouse_region_x, event.mouse_region_y)
if self.lshift:
bpy.ops.view3d.select(extend=False, location=(self.mouse_path))
try:
self.geom = self.bm.select_history[0]
except IndexError:
self.geom = None
elif event.type == 'LEFTMOUSE':
self.geom2 = self.bm.select_history[0]
self.lpoints.append((self.snap3d))
print(self.geom2)
#bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
#context.area.header_text_set()
return {'PASS_THROUGH'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
self.lpoints[:] = []
context.area.header_text_set()
return {'CANCELLED'}
if event.type == 'MIDDLEMOUSE':
bpy.ops.view3d.ndof_orbit()
#bpy.ops.view3d.view_pan(type='PANLEFT')
#bpy.ops.view3d.ndof_pan()
elif event.type in {'RIGHT_SHIFT', 'LEFT_SHIFT'}:
self.lshift = event.value != 'PRESS'
elif event.type == 'X':
self.kX = event.value == 'RELEASE'
return {'RUNNING_MODAL'}
def invoke(self, context, event):
self.lshift = True
self.kX = False
# the arguments we pass the the callback
args = (self, context)
# Add the region OpenGL drawing callback
# 'POST_PIXEL', 'POST_VIEW' or 'PRE_VIEW'
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_VIEW')
self.lpoints = []
obj = bpy.context.active_object
self.bm = bmesh.from_edit_mesh(obj.data)
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
#def execute(self, context):
#bmesh.ops.extrude_vert_indiv(self.bm, verts=[self.geom])
#return {"FINISHED"}
def register():
bpy.utils.register_class(PanelSnapUtilities)
bpy.utils.register_class(ModalDrawOperator)
bpy.types.Action.snaputilities = bpy.props.StringProperty(name="")
def unregister():
bpy.utils.register_class(PanelSnapUtilities)
bpy.utils.unregister_class(ModalDrawOperator)
del bpy.types.Action.snaputilities
if __name__ == "__main__":
register()