wizard_curve2tree.py - didnt work with no bevel object Curve.py - ext1, ext2 didnt reference the interface names.
		
			
				
	
	
		
			291 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!BPY
 | 
						|
"""
 | 
						|
Name: 'Solid Wireframe'
 | 
						|
Blender: 243
 | 
						|
Group: 'Mesh'
 | 
						|
Tooltip: 'Make a solid wireframe copy of this mesh'
 | 
						|
"""
 | 
						|
 | 
						|
# -------------------------------------------------------------------------- 
 | 
						|
# Solid Wireframe1.0 by Campbell Barton (AKA Ideasman42) 
 | 
						|
# -------------------------------------------------------------------------- 
 | 
						|
# ***** 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, sys
 | 
						|
from Blender.Mathutils import AngleBetweenVecs, TriangleNormal
 | 
						|
from BPyMesh import faceAngles # get angles for face cornders
 | 
						|
#import BPyMesh
 | 
						|
#reload(BPyMesh)
 | 
						|
#faceAngles = BPyMesh.faceAngles
 | 
						|
 | 
						|
# works out the distanbce to inset the corners based on angles
 | 
						|
from BPyMathutils import angleToLength
 | 
						|
#import BPyMathutils 
 | 
						|
#reload(BPyMathutils)
 | 
						|
#angleToLength = BPyMathutils.angleToLength
 | 
						|
 | 
						|
import mesh_solidify
 | 
						|
 | 
						|
import BPyMessages
 | 
						|
reload(BPyMessages)
 | 
						|
import bpy
 | 
						|
 | 
						|
 | 
						|
def solid_wire(ob_orig, me_orig, sce, PREF_THICKNESS, PREF_SOLID, PREF_SHARP, PREF_XSHARP):
 | 
						|
	if not PREF_SHARP and PREF_XSHARP:
 | 
						|
		PREF_XSHARP = False
 | 
						|
	
 | 
						|
	# This function runs out of editmode with a mesh
 | 
						|
	# error cases are alredy checked for
 | 
						|
	
 | 
						|
	inset_half = PREF_THICKNESS / 2
 | 
						|
	del PREF_THICKNESS
 | 
						|
	
 | 
						|
	ob = ob_orig.copy()
 | 
						|
	me = me_orig.copy()
 | 
						|
	ob.link(me)
 | 
						|
	sce.objects.selected = []
 | 
						|
	sce.objects.link(ob)
 | 
						|
	ob.sel = True
 | 
						|
	sce.objects.active = ob
 | 
						|
	
 | 
						|
	# Modify the object, should be a set
 | 
						|
	FGON= Mesh.EdgeFlags.FGON
 | 
						|
	edges_fgon = dict([(ed.key,None) for ed in me.edges if ed.flag & FGON])
 | 
						|
	# edges_fgon.fromkeys([ed.key for ed in me.edges if ed.flag & FGON])
 | 
						|
	
 | 
						|
	del FGON
 | 
						|
 | 
						|
	
 | 
						|
	
 | 
						|
	# each face needs its own verts
 | 
						|
	# orig_vert_count =len(me.verts)
 | 
						|
	new_vert_count = len(me.faces) * 4
 | 
						|
	for f in me.faces:
 | 
						|
		if len(f) == 3:
 | 
						|
			new_vert_count -= 1
 | 
						|
	
 | 
						|
	if PREF_SHARP == 0:
 | 
						|
		new_faces_edge= {}
 | 
						|
		
 | 
						|
		def add_edge(i1,i2, ni1, ni2):
 | 
						|
			
 | 
						|
			if i1>i2:
 | 
						|
				i1,i2 = i2,i1
 | 
						|
				flip = True
 | 
						|
			else:
 | 
						|
				flip = False
 | 
						|
			new_faces_edge.setdefault((i1,i2), []).append((ni1, ni2, flip))
 | 
						|
		
 | 
						|
	
 | 
						|
	new_verts = []
 | 
						|
	new_faces = []
 | 
						|
	vert_index = len(me.verts)
 | 
						|
	
 | 
						|
	for f in me.faces:
 | 
						|
		f_v_co = [v.co for v in f]
 | 
						|
		angles = faceAngles(f_v_co)
 | 
						|
		f_v_idx = [v.index for v in f]
 | 
						|
		
 | 
						|
		def new_vert(fi):
 | 
						|
			co = f_v_co[fi]
 | 
						|
			a = angles[fi]
 | 
						|
			if a > 180:
 | 
						|
				vert_inset = 1 * inset_half
 | 
						|
			else:
 | 
						|
				vert_inset = inset_half * angleToLength( abs((180-a) / 2) )
 | 
						|
			
 | 
						|
			# Calculate the inset direction
 | 
						|
			co1 = f_v_co[fi-1]
 | 
						|
			co2 = fi+1 # Wrap this index back to the start
 | 
						|
			if co2 == len(f_v_co): co2 = 0
 | 
						|
			co2 = f_v_co[co2]
 | 
						|
			
 | 
						|
			co1 = co1 - co
 | 
						|
			co2 = co2 - co
 | 
						|
			co1.normalize()
 | 
						|
			co2.normalize()
 | 
						|
			d = co1+co2
 | 
						|
			# Done with inset direction
 | 
						|
			
 | 
						|
			d.length = vert_inset
 | 
						|
			return co+d
 | 
						|
		
 | 
						|
		new_verts.extend([new_vert(i) for i in xrange(len(f_v_co))])
 | 
						|
		
 | 
						|
		if len(f_v_idx) == 4:
 | 
						|
			faces = [\
 | 
						|
			(f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\
 | 
						|
			(f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\
 | 
						|
			(f_v_idx[3], f_v_idx[2], vert_index+2, vert_index+3),\
 | 
						|
			(f_v_idx[0], f_v_idx[3], vert_index+3, vert_index),\
 | 
						|
			]
 | 
						|
		else:
 | 
						|
			faces = [\
 | 
						|
			(f_v_idx[1], f_v_idx[0], vert_index, vert_index+1),\
 | 
						|
			(f_v_idx[2], f_v_idx[1], vert_index+1, vert_index+2),\
 | 
						|
			(f_v_idx[0], f_v_idx[2], vert_index+2, vert_index),\
 | 
						|
			]
 | 
						|
		
 | 
						|
		
 | 
						|
		if PREF_SHARP == 1:
 | 
						|
			if not edges_fgon:
 | 
						|
				new_faces.extend(faces)
 | 
						|
			else:
 | 
						|
				for nf in faces:
 | 
						|
					i1,i2 = nf[0], nf[1]
 | 
						|
					if i1>i2: i1,i2 = i2,i1
 | 
						|
					
 | 
						|
					if edges_fgon and (i1,i2) not in edges_fgon:
 | 
						|
						new_faces.append(nf)
 | 
						|
			
 | 
						|
			
 | 
						|
		
 | 
						|
		elif PREF_SHARP == 0:
 | 
						|
			for nf in faces:
 | 
						|
				add_edge(*nf)
 | 
						|
			
 | 
						|
		vert_index += len(f_v_co)
 | 
						|
	
 | 
						|
	me.verts.extend(new_verts)
 | 
						|
	
 | 
						|
	if PREF_SHARP == 0:
 | 
						|
		def add_tri_flipped(i1,i2,i3):
 | 
						|
			try:
 | 
						|
				if AngleBetweenVecs(me.verts[i1].no, TriangleNormal(me.verts[i1].co, me.verts[i2].co, me.verts[i3].co)) < 90:
 | 
						|
					return i3,i2,i1
 | 
						|
				else:
 | 
						|
					return i1,i2,i3
 | 
						|
			except:
 | 
						|
				return i1,i2,i3
 | 
						|
		
 | 
						|
		# This stores new verts that use this vert
 | 
						|
		# used for re-averaging this verts location
 | 
						|
		# based on surrounding verts. looks better but not needed.
 | 
						|
		vert_users = [set() for i in xrange(vert_index)]
 | 
						|
		
 | 
						|
		for (i1,i2), nf in new_faces_edge.iteritems():
 | 
						|
			
 | 
						|
			if len(nf) == 2:
 | 
						|
				# Add the main face
 | 
						|
				if edges_fgon and (i1,i2) not in edges_fgon:
 | 
						|
					new_faces.append((nf[0][0], nf[0][1], nf[1][0], nf[1][1]))
 | 
						|
				
 | 
						|
				
 | 
						|
				if nf[0][2]:	key1 = nf[0][1],nf[0][0]
 | 
						|
				else:			key1 = nf[0][0],nf[0][1]
 | 
						|
				if nf[1][2]:	key2 = nf[1][1],nf[1][0]
 | 
						|
				else:			key2 = nf[1][0],nf[1][1]
 | 
						|
				
 | 
						|
				# CRAP, cont work out which way to flip so make it oppisite the verts normal.
 | 
						|
				
 | 
						|
				###new_faces.append((i2, key1[0], key2[0])) # NO FLIPPING, WORKS THOUGH
 | 
						|
				###new_faces.append((i1, key1[1], key2[1]))
 | 
						|
				new_faces.append(add_tri_flipped(i2, key1[0], key2[0]))
 | 
						|
				new_faces.append(add_tri_flipped(i1, key1[1], key2[1]))
 | 
						|
				
 | 
						|
				# Average vert loction so its not tooo pointy
 | 
						|
				# not realy needed but looks better
 | 
						|
				vert_users[i2].update((key1[0], key2[0]))
 | 
						|
				vert_users[i1].update((key1[1], key2[1]))
 | 
						|
			
 | 
						|
			if len(nf) == 1:
 | 
						|
				if nf[0][2]:	new_faces.append((nf[0][0], nf[0][1], i2, i1)) # flipped
 | 
						|
				else:			new_faces.append((i1,i2, nf[0][0], nf[0][1]))
 | 
						|
				
 | 
						|
		
 | 
						|
		# average points now.
 | 
						|
		for i, vusers in enumerate(vert_users):
 | 
						|
			if vusers:
 | 
						|
				co = me.verts[i].co
 | 
						|
				co.zero()
 | 
						|
				
 | 
						|
				for ii in vusers:
 | 
						|
					co += me.verts[ii].co
 | 
						|
				co /= len(vusers)
 | 
						|
	
 | 
						|
	me.faces.delete(1, range(len(me.faces)))
 | 
						|
	
 | 
						|
	me.faces.extend(new_faces)
 | 
						|
 | 
						|
	# External function, solidify
 | 
						|
	me.sel = True
 | 
						|
	if PREF_SOLID:
 | 
						|
		mesh_solidify.solidify(me, -inset_half*2, True, False, PREF_XSHARP)
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
	
 | 
						|
	# Gets the current scene, there can be many scenes in 1 blend file.
 | 
						|
	sce = bpy.data.scenes.active
 | 
						|
	
 | 
						|
	# Get the active object, there can only ever be 1
 | 
						|
	# and the active object is always the editmode object.
 | 
						|
	ob_act = sce.objects.active
 | 
						|
	
 | 
						|
	if not ob_act or ob_act.type != 'Mesh':
 | 
						|
		BPyMessages.Error_NoMeshActive()
 | 
						|
		return 
 | 
						|
	
 | 
						|
	# Saves the editmode state and go's out of 
 | 
						|
	# editmode if its enabled, we cant make
 | 
						|
	# changes to the mesh data while in editmode.
 | 
						|
	is_editmode = Window.EditMode()
 | 
						|
	Window.EditMode(0)
 | 
						|
	
 | 
						|
	me = ob_act.getData(mesh=1) # old NMesh api is default
 | 
						|
	if len(me.faces)==0:
 | 
						|
		BPyMessages.Error_NoMeshFaces()
 | 
						|
		if is_editmode: Window.EditMode(1)
 | 
						|
		return
 | 
						|
	
 | 
						|
	# Create the variables.
 | 
						|
	PREF_THICK = Blender.Draw.Create(0.005)
 | 
						|
	PREF_SOLID = Blender.Draw.Create(1)
 | 
						|
	PREF_SHARP = Blender.Draw.Create(1)
 | 
						|
	PREF_XSHARP = Blender.Draw.Create(0)
 | 
						|
	
 | 
						|
	pup_block = [\
 | 
						|
	('Thick:', PREF_THICK, 0.0001, 2.0, 'Skin thickness in mesh space.'),\
 | 
						|
	('Solid Wire', PREF_SOLID, 'If Disabled, will use 6 sided wire segments'),\
 | 
						|
	('Sharp Wire', PREF_SHARP, 'Use the original mesh topology for more accurate sharp wire.'),\
 | 
						|
	('Extra Sharp', PREF_XSHARP, 'Use less geometry to create a sharper looking wire'),\
 | 
						|
	]
 | 
						|
	
 | 
						|
	if not Blender.Draw.PupBlock('Solid Wireframe', pup_block):
 | 
						|
		if is_editmode: Window.EditMode(1)
 | 
						|
		return
 | 
						|
	
 | 
						|
	Window.WaitCursor(1)
 | 
						|
	t = sys.time()
 | 
						|
	
 | 
						|
	# Run the mesh editing function
 | 
						|
	solid_wire(ob_act, me, sce, PREF_THICK.val, PREF_SOLID.val, PREF_SHARP.val, PREF_XSHARP.val)
 | 
						|
	
 | 
						|
	# Timing the script is a good way to be aware on any speed hits when scripting
 | 
						|
	print 'Solid Wireframe finished in %.2f seconds' % (sys.time()-t)
 | 
						|
	Window.WaitCursor(0)
 | 
						|
	if is_editmode: Window.EditMode(1)
 | 
						|
	
 | 
						|
	
 | 
						|
# This lets you can import the script without running it
 | 
						|
if __name__ == '__main__':
 | 
						|
	main()
 |