Page MenuHome

Vert_pin.py

File Metadata

Author
Fabian Fricke (frigi)
Created
Nov 13 2013, 2:01 PM

Vert_pin.py

#!BPY
"""
Name: 'Vertex pin'
Blender: 248a
Group: 'Mesh'
Tooltip: 'Pins vertices while editing'
"""
__author__ = "Fabian Fricke"
__url__ = ("frigi.designdevil.de")
__version__ = "0.9"
__email__= ["frigi.f@googlemail.com"]
__bpydoc__ = """\
Important:
This script has potential to completely crash Blender (especially on more complex meshes)!
Always save your work before using it!
General information:
You have to enable Script Links in order to be able to use this script.
The script uses a vertex group called "PinGroup" to determine which vertices are pinned.
This vertex group is completely handeled by the script itself and the interface provides all
necessary tools to modify it. It's not advised to use Blender's own vertex group panel.
The script supports vertex weights.
A value of 1 means completely static vertices; 0 means no pinning at all.
If your mesh is too heavy to allow the script to rum smoothly you can disable the realtime mode
by toggling the "rt" button off. You then need to exit editmode to apply the pinning.
By default the Vertex group "PinGroup" will not be deleted when exiting the script in order to
preserve your modifications. If you still want the script to automatically delete the group upon
quitting you have to enable the "d" button in the lower right corner.
"""
# --------------------------------------------------------------------------
# Vert pin.py
# Copyright Fabian Fricke 2009
# --------------------------------------------------------------------------
# ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import Blender
from Blender import Scene, Mesh, Window, Draw, Text
import bpy
import BPyMessages
import string
######################################################
# Vars
######################################################
scriptName = "Vert pin.py"
activeMesh = 0
save = 0
groupSave = 0
clear = 0
pin = Draw.Create(0)
realtime = Draw.Create(1)
weight = Draw.Create(1.0)
delete = Draw.Create(0)
floatPrec = 5 #decimal places used to check if old and new vert coordinates are different
######################################################
# Functions
######################################################
#________________________________________________________________________________________________
def avoidEmptyCrash(): # avoids crashes caused by empty/not existing vert group/Blender Text
# if somebody manually deleted the vert group while script is running a new one is created to avoid a crash
HandleGroup()
if not groupSave:
me.addVertGroup("PinGroup")
# avoid crash if nothing was assigned to the group yet
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
me.assignVertsToGroup("PinGroup", [], 0 , Mesh.AssignModes.REPLACE) # basically does nothing except avoiding the crash
is_editmode = Window.EditMode(1)
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def HandleText():
global VDict, save
if save == 0 :
VDict = Text.New("VertDict")
SaveVertPos()
print "VertDict text created"
save = 1
else:
Text.unlink(VDict)
VDict = Text.New("VertDict")
SaveVertPos()
print "VertDict text updated"
if pin.val:
if realtime.val:
ob_act.addScriptLink(scriptName,"ObDataUpdate")
else:
ob_act.addScriptLink(scriptName,"ObjectUpdate")
else:
ob_act.clearScriptLinks()
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def HandleGroup():
global groupSave
groupSave = 0
for g in me.getVertGroupNames():
if g == "PinGroup":
groupSave = 1
break
else:
groupSave = 0
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def SaveVertPos():
global clear
HandleGroup()
if not groupSave:
me.addVertGroup("PinGroup")
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
for vi in me.getVertsFromGroup("PinGroup"):
VDict.write( str( vi ) + "\n")
VDict.write( str( me.verts[vi].co.x ) + "\n")
VDict.write( str( me.verts[vi].co.y ) + "\n")
VDict.write( str( me.verts[vi].co.z ) + "\n")
if is_editmode: Window.EditMode(1)
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def CheckVertPos():
global floatPrec
VDict = Text.Get("VertDict")
VertDict = {}
for i in range(0,VDict.getNLines()-1, 4 ): # -1 to cancel out the last line which is empty and using step 4 to only get the vert indices
Vindex = int( string.join( VDict.asLines(i,i+1),'' ) )
Vcoords = []
Vcoords.append(float( string.join( VDict.asLines(i+1,i+2),'' ) )) # x
Vcoords.append(float( string.join( VDict.asLines(i+2,i+3),'' ) )) # y
Vcoords.append(float( string.join( VDict.asLines(i+3,i+4),'' ) )) # z
VertDict[Vindex] = Vcoords
for vt in me.getVertsFromGroup("PinGroup",1):
for i in VertDict:
if vt[0] == i:
for v in me.verts:
if i == v.index:
if round(VertDict[i][0], floatPrec) - round(v.co.x, floatPrec) != 0:
v.co.x = ( round(VertDict[i][0], floatPrec) * vt[1] ) + ( round(v.co.x, floatPrec) * ( 1.0 - vt[1] ) )
if round(VertDict[i][1], floatPrec) - round(v.co.y, floatPrec) != 0:
v.co.y = ( round(VertDict[i][1], floatPrec) * vt[1] ) + ( round(v.co.y, floatPrec) * ( 1.0 - vt[1] ) )
if round(VertDict[i][2], floatPrec) - round(v.co.z, floatPrec) != 0:
v.co.z = ( round(VertDict[i][2], floatPrec) * vt[1] ) + ( round(v.co.z, floatPrec) * ( 1.0 - vt[1] ) )
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def Assign():
if not groupSave:
me.addVertGroup("PinGroup")
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
vertList = []
for v in me.verts:
if v.sel:
vertList.append(v.index)
me.assignVertsToGroup("PinGroup", vertList, weight.val , Mesh.AssignModes.REPLACE)
is_editmode = Window.EditMode(1)
if vertList != []:
HandleText()
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def Remove():
HandleGroup()
if groupSave:
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
vertList = []
for v in me.verts:
if v.sel:
vertList.append(v.index)
me.removeVertsFromGroup("PinGroup", vertList)
is_editmode = Window.EditMode(1)
if vertList != []:
HandleText()
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def Select():
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
for vi in me.getVertsFromGroup("PinGroup"):
me.verts[vi].sel = 1
is_editmode = Window.EditMode(1)
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def Deselect():
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
for vi in me.getVertsFromGroup("PinGroup"):
me.verts[vi].sel = 0
is_editmode = Window.EditMode(1)
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def Clear():
global clear
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
me.removeVertGroup("PinGroup")
me.addVertGroup("PinGroup")
is_editmode = Window.EditMode(1)
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def Delete():
HandleGroup()
if groupSave and delete.val:
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
me.removeVertGroup("PinGroup")
is_editmode = Window.EditMode(1)
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def main():
global me, ob_act, activeMesh
sce = bpy.data.scenes.active
ob_act = sce.objects.active
if not ob_act or ob_act.type != 'Mesh':
BPyMessages.Error_NoMeshActive()
return
else:
activeMesh = 1
is_editmode = Window.EditMode()
if is_editmode: Window.EditMode(0)
me = ob_act.getData(mesh=1)
if Blender.bylink:
CheckVertPos()
else:
Draw.Register(gui, event, button_event)
if is_editmode: Window.EditMode(1)
#________________________________________________________________________________________________
######################################################
# GUI
######################################################
EV_BT_Pin = 1
EV_TG_Realtime = 2
EV_NU_Weight = 3
EV_BT_Assign = 4
EV_BT_Remove = 5
EV_BT_Select = 6
EV_BT_Deselect = 7
EV_BT_Clear = 8
EV_BT_Quit = 9
EV_TG_Delete = 10
#________________________________________________________________________________________________
def gui():
global gui_tg_pin, gui_tg_realtime, gui_nu_weight, gui_tg_delete
gui_tg_pin = Draw.Toggle("Pin", EV_BT_Pin, 5, 85, 100, 25, pin.val, "Toggle pin/unpin")
gui_tg_realtime = Draw.Toggle("rt",EV_TG_Realtime, 105, 85, 20, 25, realtime.val, "update in realtime (disable for larger meshes)")
gui_nu_weight = Draw.Number("Weight:",EV_NU_Weight,5,65,120,20,weight.val,0,1,"Vertex weight used when assigning")
gui_bt_assign = Draw.PushButton("Assign", EV_BT_Assign, 5, 45, 60,20, "Assigns selected vertices to \"PinGroup\"")
gui_bt_remove = Draw.PushButton("Remove", EV_BT_Remove, 65, 45, 60,20, "Removes selected vertices from \"PinGroup\"")
gui_bt_select = Draw.PushButton("Select", EV_BT_Select, 5, 25, 60,20, "Selects vertices belonging to \"PinGroup\"")
gui_bt_deselect = Draw.PushButton("Desel.", EV_BT_Deselect, 65, 25, 60,20, "Deselects vertices belonging to \"PinGroup\"")
gui_bt_clear = Draw.PushButton("Clear", EV_BT_Clear, 5, 5, 60,20, "Clears \"PinGroup\" and deletes weights")
gui_pb_quit = Draw.PushButton("Quit", EV_BT_Quit, 75, 5, 35, 15, "Exits the script")
gui_tg_delete = Draw.Toggle("d", EV_TG_Delete, 110, 5, 15, 15, delete.val, "Delete \"PinGroup\" upon exit")
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def event(evt, val):
if evt in [Draw.QKEY, Draw.ESCKEY, Draw.XKEY]:
if save == 1:
Text.unlink(VDict)
print "VertDict text deleted"
ob_act.clearScriptLinks()
Delete()
Draw.Exit()
#________________________________________________________________________________________________
#________________________________________________________________________________________________
def button_event(evt):
if evt == EV_BT_Pin:
pin.val = gui_tg_pin.val
if pin.val:
avoidEmptyCrash()
# enable pinning
HandleText()
else:
ob_act.clearScriptLinks() # no scriptlink -> no pinning
#----------------------------------------------------
if evt == EV_TG_Realtime:
if gui_tg_realtime.val != realtime.val:
realtime.val = gui_tg_realtime.val
ob_act.clearScriptLinks()
if realtime.val:
ob_act.addScriptLink(scriptName,"ObDataUpdate")
else:
ob_act.addScriptLink(scriptName,"ObjectUpdate")
#----------------------------------------------------
if evt == EV_NU_Weight:
weight.val = gui_nu_weight.val
#----------------------------------------------------
if evt == EV_BT_Assign:
avoidEmptyCrash()
Assign()
#----------------------------------------------------
if evt == EV_BT_Remove:
avoidEmptyCrash()
Remove()
#----------------------------------------------------
if evt == EV_BT_Select:
avoidEmptyCrash()
Select()
#----------------------------------------------------
if evt == EV_BT_Deselect:
avoidEmptyCrash()
Deselect()
#----------------------------------------------------
if evt == EV_BT_Clear:
avoidEmptyCrash()
Clear()
#----------------------------------------------------
if evt == EV_BT_Quit:
if save == 1:
Text.unlink(VDict)
print "VertDict text deleted"
ob_act.clearScriptLinks()
Delete()
Draw.Exit()
#----------------------------------------------------
if evt == EV_TG_Delete:
delete.val = gui_tg_delete.val
#________________________________________________________________________________________________
######################################################
# Execution
######################################################
if __name__ == '__main__':
main()
if activeMesh: # avoid crash is no mesh is active
HandleGroup()
if not groupSave:
me.addVertGroup("PinGroup")

Event Timeline