#!BPY
"""
Name: '_Analytics'
Blender: 248
Group: 'Misc'
Tooltip: 'Analyses a mesh'
"""
__author__ = "Fabian Fricke"
__url__ = ("frigi.designdevil.de")
__version__ = "1.0"
__email__= ["frigi.f@googlemail.com"]
__bpydoc__ = """\
General information:

- Please only use this script on one object at a time, so don't change objects while the script is

runing. Otherwise the materials that are created will probably not get removed correctly and you will

have to do it by hand.

- In case the script crashed for some reason you will also have to manually remove the materials.

- For this script to run it's necessary that there are at least 9 empty material slots in the object's

material list. (Every object can have a maximum of 16 materials at a time.)

- The colorpickers on the left apply for all functions.


-----------------------------------------------------------------
The functions explained:
-----------------------------------------------------------------


"Torsion angle":
This check determines the torsion of quads (triangles will just be skipped as they are always planar) by

calculating the angles between the triangles in which the quad could possibly be split up. This is

especially useful for lowpoly objects where no subsurf modifier will be used.

Parameters:
The number buttons beneath represent the angles for the respective color.

-----------------------------------------------------------------

"Stretch":
This will calculate the stretching of faces.

Parameters:
The number buttons beneath represent the stretching values, starting at 1.0.
The smaller the value, the stronger the stretching. 

-----------------------------------------------------------------

"Silhouette":
Displays how much each face contributes to the silhouette of the model.

Parameters:
Inv: Displays colors in reversed order
The number buttons beneath represent the angles for the respective color.

-----------------------------------------------------------------

"Average area":
This function will visualize the difference in the face areas regarding a source area:

- If no faces are selected in Edit Mode the source area is the average area of all faces contained in the

mesh.

- As soon as one or more faces are selected the average of those is the source area. Selected faces will

be displayed in a different color which you are able to pick yourself through the color picker next to

the button. (default is white)


"""

# -------------------------------------------------------------------------- 
# Analytics.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 *
from Blender.Material import *
from Blender.Mathutils import *
from Blender.Mesh import *

import math


####################################################################
# vars
####################################################################
#CritVal = Draw.Create(30)

mat1_rgb = Draw.Create(0.0, 0.0, 0.4)
mat2_rgb = Draw.Create(0.0, 0.5, 0.6)
mat3_rgb = Draw.Create(0.0, 0.5, 0.4)
mat4_rgb = Draw.Create(0.0, 0.6, 0.0)
mat5_rgb = Draw.Create(0.6, 0.7, 0.0)
mat6_rgb = Draw.Create(0.8, 0.8, 0.0)
mat7_rgb = Draw.Create(0.7, 0.4, 0.0)
mat8_rgb = Draw.Create(0.8, 0.0, 0.0)

mat_ref_rgb = Draw.Create(1, 1, 1)

# torsion
a1 = Draw.Create(0)
a2 = Draw.Create(5)
a3 = Draw.Create(20)
a4 = Draw.Create(30)
a5 = Draw.Create(40)
a6 = Draw.Create(50)
a7 = Draw.Create(60)
a8 = Draw.Create(70)

# stretch
s1 = Draw.Create(1.0)
s2 = Draw.Create(0.7)
s3 = Draw.Create(0.6)
s4 = Draw.Create(0.5)
s5 = Draw.Create(0.4)
s6 = Draw.Create(0.3)
s7 = Draw.Create(0.2)
s8 = Draw.Create(0.1)

# silhouette
a21 = Draw.Create(0)
a22 = Draw.Create(10)
a23 = Draw.Create(20)
a24 = Draw.Create(30)
a25 = Draw.Create(40)
a26 = Draw.Create(50)
a27 = Draw.Create(60)
a28 = Draw.Create(70)

inv = Draw.Create(1)

matset1 = 0
matset2 = 0
matset3 = 0
matset4 = 0
matset5 = 0
matset6 = 0
matset7 = 0
matset8 = 0

matset_ref = 0

matass1 = 0
matass2 = 0
matass3 = 0
matass4 = 0
matass5 = 0
matass6 = 0
matass7 = 0
matass8 = 0

matass_ref = 0

matlist_set = 0

state_idle = "idle"
state = state_idle

fcount = 0
progout = 0

time0 = sys.time()

####################################################################
# lists
####################################################################
vectorlist = []
first_tri = []
edges = []
edges_v = []
deletei = []

####################################################################
# functions
####################################################################
def CountFaces(me):
	totalcount = 0
	
	for f in me.faces:
		totalcount = totalcount +1
	
	return totalcount


##################################################################################################
def Progress(tc,c): # outputs 10% steps if executing the whole function is not fasten than redrawing
	global p,progout
	global time0
	
	prog = int(c / float(tc) * 100)
	if prog - p >= p:
		p = p + 5
		progout = prog
		if sys.time() - time0 > 0.02:
			Draw.Draw()
		
		time0 = sys.time()


##################################################################################################
def CreateMats():
	global mat1,mat2,mat3,mat4,mat5,mat6,mat7,mat8
	global matset1,matset2,matset3,matset4,matset5,matset6,matset7,matset8
	
	global mat_ref
	global matset_ref
	
	
	matlist = Material.get()
	
	for m in matlist:
		if m.getName() == "Ana_Mat_1":
			matset1 = 1
		if m.getName() == "Ana_Mat_2":
			matset2 = 1
		if m.getName() == "Ana_Mat_3":
			matset3 = 1
		if m.getName() == "Ana_Mat_4":
			matset4 = 1
		if m.getName() == "Ana_Mat_5":
			matset5 = 1
		if m.getName() == "Ana_Mat_6":
			matset6 = 1
		if m.getName() == "Ana_Mat_7":
			matset7 = 1
		if m.getName() == "Ana_Mat_8":
			matset8 = 1
			
		if m.getName() == "Ana_Mat_ref":
			matset_ref = 1
	
	if not matset1:
		mat1 = Material.New("Ana_Mat_1")
	else:
		mat1 = Material.get("Ana_Mat_1")
	if not matset2:
		mat2 = Material.New("Ana_Mat_2")
	else:
		mat2 = Material.get("Ana_Mat_2")
	if not matset3:
		mat3 = Material.New("Ana_Mat_3")
	else:
		mat3 = Material.get("Ana_Mat_3")
	if not matset4:
		mat4 = Material.New("Ana_Mat_4")
	else:
		mat4 = Material.get("Ana_Mat_4")
	if not matset5:
		mat5 = Material.New("Ana_Mat_5")
	else:
		mat5 = Material.get("Ana_Mat_5")
	if not matset6:
		mat6 = Material.New("Ana_Mat_6")
	else:
		mat6 = Material.get("Ana_Mat_6")
	if not matset7:
		mat7 = Material.New("Ana_Mat_7")
	else:
		mat7 = Material.get("Ana_Mat_7")
	if not matset8:
		mat8 = Material.New("Ana_Mat_8")
	else:
		mat8 = Material.get("Ana_Mat_8")
	
	if not matset_ref:
		mat_ref = Material.New("Ana_Mat_ref")
	else:
		mat_ref = Material.get("Ana_Mat_ref")
	
	mat1.rgbCol = mat1_rgb.val
	mat2.rgbCol = mat2_rgb.val
	mat3.rgbCol = mat3_rgb.val
	mat4.rgbCol = mat4_rgb.val
	mat5.rgbCol = mat5_rgb.val
	mat6.rgbCol = mat6_rgb.val
	mat7.rgbCol = mat7_rgb.val
	mat8.rgbCol = mat8_rgb.val
	
	mat_ref.rgbCol = mat_ref_rgb.val
	
	
	mat1.spec = 0
	mat2.spec = 0
	mat3.spec = 0
	mat4.spec = 0
	mat5.spec = 0
	mat6.spec = 0
	mat7.spec = 0
	mat8.spec = 0
	
	mat_ref.spec = 0
	
	
##################################################################################################
def AssignMatsToMesh(mesh):
	global matass1,matass2,matass3,matass4,matass5,matass6,matass6,matass7,matass8
	global matlist_set,mesh_matlist,mesh_matlist_len
	
	global matass_ref
	
	if not matlist_set:
		mesh_matlist = mesh.materials
		mesh_matlist_len = len(mesh_matlist)
		matlist_set = 1
	
	if not matass1:
		mesh.materials += [mat1]
		matass1 = 1
	if not matass2:
		mesh.materials += [mat2]
		matass2 = 1
	if not matass3:
		mesh.materials += [mat3]
		matass3 = 1
	if not matass4:
		mesh.materials += [mat4]
		matass4 = 1
	if not matass5:
		mesh.materials += [mat5]
		matass5 = 1
	if not matass6:
		mesh.materials += [mat6]
		matass6 = 1
	if not matass7:
		mesh.materials += [mat7]
		matass7 = 1
	if not matass8:
		mesh.materials += [mat8]
		matass8 = 1
		
	if not matass_ref:
		mesh.materials += [mat_ref]
		matass_ref = 1


##################################################################################################
def AssignMatToFace(f,mat):
	if mat == mat1:
		mindex = 0 + mesh_matlist_len
	if mat == mat2:
		mindex = 1 + mesh_matlist_len
	if mat == mat3:
		mindex = 2 + mesh_matlist_len
	if mat == mat4:
		mindex = 3 + mesh_matlist_len
	if mat == mat5:
		mindex = 4 + mesh_matlist_len
	if mat == mat6:
		mindex = 5 + mesh_matlist_len
	if mat == mat7:
		mindex = 6 + mesh_matlist_len
	if mat == mat8:
		mindex = 7 + mesh_matlist_len
		
	if mat == mat_ref:
		mindex = 8 + mesh_matlist_len
		
	f.mat = mindex
	
	
##################################################################################################	
def RemoveMats(mesh):
	mesh.materials = mesh_matlist
	
		
##################################################################################################
def CheckTorsionAngles():
	global me,state,p

	t = sys.time()
	
	scn = Scene.GetCurrent()
	ob = scn.objects.active
	
	if ob == None or ob.getType() != 'Mesh':
		Draw.PupMenu("ERROR%t|Select a mesh object.")
		return
	
	Window.WaitCursor(1)
	
	is_editmode = Window.EditMode()
	if is_editmode: Window.EditMode(0)
	
	me = ob.getData(mesh=1)
	
	print "checking torsion..."
	state = "busy..."
	
	#create mats and assign them to the mesh
	CreateMats()
	AssignMatsToMesh(me)
	Window.RedrawAll()
	
	totalcount = CountFaces(me)
	fcount = 0
	p = 0
	
	for f in me.faces:
		fcount = fcount +1
		Progress(totalcount,fcount)
		
		if f.__len__() == 4: # only operates on quads
			
			first_v = f.verts[0]
			second_v = f.verts[1]
			third_v = f.verts[2]
			fourth_v = f.verts[3]
			
			edges = list(f.edge_keys)
			
			####################################################################
			# finding the first triangle
			####################################################################
			first_tri = []
			first_tri.append(first_v)
			
			if me.findEdges(first_v,second_v) != None:
				everts = []
				first_tri.append(second_v)
				everts.append(first_v.index)
				everts.append(second_v.index)
				edges_v.append(tuple(everts))
				everts = []
			else:
				startvert2 = second_v
					
			if me.findEdges(first_v,third_v) != None:
				everts =[]
				first_tri.append(third_v)
				everts.append(first_v.index)
				everts.append(third_v.index)
				edges_v.append(tuple(everts))
				everts = []
			else:
				startvert2 = third_v
					
			if me.findEdges(first_v,fourth_v) != None:
				everts = []
				first_tri.append(fourth_v)
				everts.append(first_v.index)
				everts.append(fourth_v.index)
				edges_v.append(tuple(everts))
				everts = []
			else:
				startvert2 = fourth_v
				
				
			####################################################################
			# finding the second triangle
			####################################################################
			second_tri = []
			
			second_tri.append(startvert2)
			if startvert2 != second_v:
				second_tri.append(second_v)
			if startvert2 != third_v:
				second_tri.append(thrid_v)
			if startvert2 != fourth_v:
				second_tri.append(fourth_v)	
			
			
			####################################################################
			# finding the third and fourth triangle
			####################################################################
			third_tri = []
			fourth_tri = []
			alltrifound = 0
			if second_v != startvert2:
				third_tri.append(second_v)
				third_tri.append(first_v)
				third_tri.append(startvert2)

				if third_v != startvert2:
					fourth_tri.append(third_v)
				else:
					fourth_tri.append(fourth_v)
				fourth_tri.append(first_v)
				fourth_tri.append(startvert2)
			
				alltrifound = 1
		
			if third_v != startvert2 and not alltrifound:
				third_tri.append(third_v)
				third_tri.append(first_v)
				third_tri.append(startvert2)	
	
				if third_v != startvert2:
					fourth_tri.append(third_v)
				else:
					fourth_tri.append(fourth_v)
				fourth_tri.append(first_v)
				fourth_tri.append(startvert2)
				
				alltrifound = 1
	
			if fourth_v != startvert2 and not alltrifound:
				third_tri.append(fourth_v)
				third_tri.append(first_v)
				third_tri.append(startvert2)	

				if third_v != startvert2:
					fourth_tri.append(third_v)
				else:
					fourth_tri.append(fourth_v)
				fourth_tri.append(first_v)
				fourth_tri.append(startvert2)
				
				alltrifound = 1
			
		
			####################################################################
			# calculating the angles
			####################################################################
			
			########## first angle #############################################
			v1 = Vector(first_tri[0].co.x-first_tri[1].co.x, first_tri[0].co.y-first_tri[1].co.y, first_tri[0].co.z-first_tri[1].co.z)
			v2 = Vector(first_tri[0].co.x-first_tri[2].co.x, first_tri[0].co.y-first_tri[2].co.y, first_tri[0].co.z-first_tri[2].co.z)
			
			normal1 = CrossVecs(v1,v2)
			normal1.normalize()
		
			v3 = Vector(second_tri[0].co.x-second_tri[1].co.x, second_tri[0].co.y-second_tri[1].co.y, second_tri[0].co.z-second_tri[1].co.z)
			v4 = Vector(second_tri[0].co.x-second_tri[2].co.x, second_tri[0].co.y-second_tri[2].co.y, second_tri[0].co.z-second_tri[2].co.z)
			
			normal2 = CrossVecs(v3,v4)
			normal2.normalize()
			
			cropangle = AngleBetweenVecs(normal1,normal2)
			if cropangle > 180:
				angle1 = 0.0
			else:
				angle1 = 180 - cropangle
			
			########## second angle #############################################
			v1 = Vector(third_tri[0].co.x-third_tri[1].co.x, third_tri[0].co.y-third_tri[1].co.y, third_tri[0].co.z-third_tri[1].co.z)
			v2 = Vector(third_tri[0].co.x-third_tri[2].co.x, third_tri[0].co.y-third_tri[2].co.y, third_tri[0].co.z-third_tri[2].co.z)
				
			normal1 = CrossVecs(v1,v2)
			normal1.normalize()
			
			v3 = Vector(fourth_tri[0].co.x-fourth_tri[1].co.x, fourth_tri[0].co.y-fourth_tri[1].co.y, fourth_tri[0].co.z-fourth_tri[1].co.z)
			v4 = Vector(fourth_tri[0].co.x-fourth_tri[2].co.x, fourth_tri[0].co.y-fourth_tri[2].co.y, fourth_tri[0].co.z-fourth_tri[2].co.z)
			
			normal2 = CrossVecs(v3,v4)
			normal2.normalize()
			
			cropangle = AngleBetweenVecs(normal1,normal2)
			if cropangle > 180:
					angle2 = 0.0
			else:
				angle2 = 180 - cropangle
			
			
			########## visual output #############################################
			if angle1 >= a1.val or angle2 >= a1.val:
				AssignMatToFace(f,mat1)
			if angle1 >= a2.val or angle2 >= a2.val:
				AssignMatToFace(f,mat2)
			if angle1 >= a3.val or angle2 >= a3.val:
				AssignMatToFace(f,mat3)
			if angle1 >= a4.val or angle2 >= a4.val:
				AssignMatToFace(f,mat4)
			if angle1 >= a5.val or angle2 >= a5.val:
				AssignMatToFace(f,mat5)
			if angle1 >= a6.val or angle2 >= a6.val:
				AssignMatToFace(f,mat6)
			if angle1 >= a7.val or angle2 >= a7.val:
				AssignMatToFace(f,mat7)
			if angle1 >= a8.val or angle2 >= a8.val:
				AssignMatToFace(f,mat8)
		
			
		# assign mat1 to all tris
		else:
			AssignMatToFace(f,mat1)
	
	if is_editmode: Window.EditMode(1)
	Window.WaitCursor(0)
	
	Window.RedrawAll()
	
	print "done (",sys.time() - t,"sec.)"
	state = "done"


##################################################################################################
def CheckSilhouette(inverse):
	global me,state,p
	
	t = sys.time()
	
	scn = Scene.GetCurrent()
	ob = scn.objects.active
	
	if ob == None or ob.getType() != 'Mesh':
		Draw.PopMenu('ERROR%t|Select a mesh object.')
		return
	
	Window.WaitCursor(1)
	
	is_editmode = Window.EditMode()
	if is_editmode: Window.EditMode(0)
	
	me = ob.getData(mesh=1)
	
	print "checking silhouette..."
	state = "busy..."
	
	#create mats and assign them to the mesh
	CreateMats()
	AssignMatsToMesh(me)
	Window.RedrawAll()
	
	#one-off exeption: need edges instead of faces here, so won't use CountFaces() and fcount here
	totalcount = 0
	for e in me.edges:
		totalcount = totalcount + 1
	
	ecount = 0
	p = 0
	
	# code from API Doc:
	# a dictionary where the edge is the key, and a list of faces that use it are the value
	edge_faces = dict([(ed.key, []) for ed in me.edges])
	
	#dict of all faces; face index is the key, angle is the value
	facedict = {}
	
	# Add the faces to the dict
	for f in me.faces:	
		for key in f.edge_keys:
			edge_faces[key].append(f) # add this face to the edge as a user
		
		#fill dict with 0° angles
		facedict[f.index] = 0
	
	for key, face_users in edge_faces.iteritems():
		ecount = ecount + 1
		Progress(totalcount,ecount)
		
		if len(face_users) is 2:
			f1 = face_users[0]
			f2 = face_users[1]
			angle = AngleBetweenVecs(f1.no, f2.no)
			
			#only save the biggest angle in the dict
			if facedict[f1.index] < angle:
				facedict[f1.index] = angle
			if facedict[f2.index] < angle:
				facedict[f2.index] = angle
				
	
	for f, angle in facedict.iteritems():
		
		if angle >= a21.val:
			AssignMatToFace(me.faces[f],mat1)
			if inverse:
				AssignMatToFace(me.faces[f],mat8)
		if angle >= a22.val:
			AssignMatToFace(me.faces[f],mat2)
			if inverse:
				AssignMatToFace(me.faces[f],mat7)
		if angle >= a23.val:
			AssignMatToFace(me.faces[f],mat3)
			if inverse:
				AssignMatToFace(me.faces[f],mat6)
		if angle >= a24.val:
			AssignMatToFace(me.faces[f],mat4)
			if inverse:
				AssignMatToFace(me.faces[f],mat5)
		if angle >= a25.val:
			AssignMatToFace(me.faces[f],mat5)
			if inverse:
				AssignMatToFace(me.faces[f],mat4)
		if angle >= a26.val:
			AssignMatToFace(me.faces[f],mat6)
			if inverse:
				AssignMatToFace(me.faces[f],mat3)
		if angle >= a27.val:
			AssignMatToFace(me.faces[f],mat7)
			if inverse:
				AssignMatToFace(me.faces[f],mat2)
		if angle >= a28.val:
			AssignMatToFace(me.faces[f],mat8)
			if inverse:
				AssignMatToFace(me.faces[f],mat1)
	
			
	if is_editmode: Window.EditMode(1)
	Window.WaitCursor(0)
	
	Window.RedrawAll()
	
	print "done (",sys.time() - t,"sec.)"
	state = "done"
	
	
##################################################################################################
def CheckEvenArea():
	global me,state,p
	
	t = sys.time()
	
	AreaList = []
	aSum = 0
	SelList = []
	
	scn = Scene.GetCurrent()
	ob = scn.objects.active
	
	if ob == None or ob.getType() != 'Mesh':
		Draw.PopMenu('ERROR%t|Select a mesh object.')
		return
	
	Window.WaitCursor(1)
	
	is_editmode = Window.EditMode()
	if is_editmode: Window.EditMode(0)
	
	me = ob.getData(mesh=1)
	
	print "checking area..."
	state = "busy..."
	
	#create mats and assign them to the mesh
	CreateMats()
	AssignMatsToMesh(me)
	Window.RedrawAll()
	
	totalcount = CountFaces(me)
	fcount = 0
	p = 0
	
	for f in me.faces:
		if f.sel:
			SelList.append(f)
			AreaList.append(f.area)

	#calculate the average area
	if len(AreaList) != 0:
		for a in AreaList:
			aSum = aSum + a
		aAverage = aSum / len(AreaList)
	elif len(AreaList) == len(SelList):
		for f in me.faces:
			AreaList.append(f.area)
			
		for a in AreaList:
			aSum = aSum + a
				
		aAverage = aSum / len(AreaList)
	
	#difference between actual and average area
	for f in me.faces:
		fcount = fcount +1
		Progress(totalcount,fcount)
		
		#calculate difference in range 0 - 1
		if f.area < aAverage:
			diff = f.area / aAverage
		elif f.area == aAverage:
			diff = 1
		elif f.area > aAverage:
			diff = aAverage / f.area
		
		#assing mats accordingly
		if diff <= 1:
			AssignMatToFace(f,mat1)
		if diff <= 0.875:
			AssignMatToFace(f,mat2)
		if diff <= 0.75:
			AssignMatToFace(f,mat3)
		if diff <= 0.626:
			AssignMatToFace(f,mat4)
		if diff <= 0.5:
			AssignMatToFace(f,mat5)
		if diff <= 0.375:
			AssignMatToFace(f,mat6)
		if diff <= 0.25:
			AssignMatToFace(f,mat7)
		if diff <= 0.125:
			AssignMatToFace(f,mat8)
			
	#assign mat_ref to reference faces if necessary
	if len(SelList):
		for f in SelList:
			AssignMatToFace(f,mat_ref)
	
	if is_editmode: Window.EditMode(1)
	Window.WaitCursor(0)	

	Window.RedrawAll()
	
	print "done (",sys.time() - t,"sec.)"
	state = "done"
	
	
##################################################################################################
def CheckStretching():
	global me,state,p
	
	t = sys.time()
	
	scn = Scene.GetCurrent()
	ob = scn.objects.active
	
	if ob == None or ob.getType() != 'Mesh':
		Draw.PopMenu('ERROR%t|Select a mesh object.')
		return
	
	Window.WaitCursor(1)
	
	is_editmode = Window.EditMode()
	if is_editmode: Window.EditMode(0)
	
	me = ob.getData(mesh=1)
	
	print "checking stretching..."
	state = "busy..."
	
	#create mats and assign them to the mesh
	CreateMats()
	AssignMatsToMesh(me)
	Window.RedrawAll()
	
	totalcount = CountFaces(me)
	fcount = 0
	p = 0
	
	for f in me.faces:
		fcount = fcount +1
		Progress(totalcount,fcount)
		
		edge1 = []
		edge2 = []
		edge3 = []
		edge4 = []
		diag1 = [] 
		diag2 = []
		
		if f.__len__() == 4: # operates on quads
			
			vert1 = f.verts[0]
			vert2 = f.verts[1]
			vert3 = f.verts[2]
			vert4 = f.verts[3]
			

			if me.findEdges(vert1,vert2) != None:
				edge1.append(vert1)
				edge1.append(vert2)
				diag1.append(vert1)
				diag2.append(vert2)
				if me.findEdges(vert1,vert3):
					edge2.append(vert3)
					edge2.append(vert4)
					edge3.append(vert1)
					edge3.append(vert3)
					edge4.append(vert2)
					edge4.append(vert4)
					diag1.append(vert4)
					diag2.append(vert3)
				else:
					edge2.append(vert4)
					edge2.append(vert3)
					edge3.append(vert1)
					edge3.append(vert4)
					edge4.append(vert3)
					edge4.append(vert2)
					diag1.append(vert3)
					diag2.append(vert4)
			else:
			
				if me.findEdges(vert1,vert3) != None:
					edge1.append(vert1)
					edge1.append(vert3)
					diag1.append(vert1)
					diag2.append(vert3)
					if me.findEdges(vert1,vert4):
						edge2.append(vert4)
						edge2.append(vert2)
						edge3.append(vert1)
						edge3.append(vert4)
						edge4.append(vert2)
						edge4.append(vert3)
						diag1.append(vert2)
						diag2.append(vert4)
					else:
						edge2.append(vert2)
						edge2.append(vert4)
						edge3.append(vert1)
						edge3.append(vert2)
						edge4.append(vert4)
						edge4.append(vert3)
						diag1.append(vert4)
						diag2.append(vert2)
				else:

					if me.findEdges(vert1,vert4) != None:
						edge1.append(vert1)
						edge1.append(vert4)
						diag1.append(vert1)
						diag2.append(vert4)
						if me.findEdges(vert1,vert2):
							edge2.append(vert2)
							edge2.append(vert3)
							edge3.append(vert1)
							edge3.append(vert2)
							edge4.append(vert3)
							edge4.append(vert4)
							diag1.append(vert3)
							diag2.append(vert2)
						else:
							edge2.append(vert3)
							edge2.append(vert2)
							edge3.append(vert1)
							edge3.append(vert3)
							edge4.append(vert2)
							edge4.append(vert4)
							diag1.append(vert2)
							diag2.append(vert3)
	
				
			#acquiring Medges
			for ed in f.edge_keys:
				if edge1[0].index == ed[0] or edge1[1].index == ed[0]:
					if edge1[1].index == ed[1] or edge1[0].index == ed[1]:
						e1 = me.findEdges(edge1[0],edge1[1])
						Medge1 = me.edges[e1]
				
				if edge2[0].index == ed[0] or edge2[1].index == ed[0]:
					if edge2[1].index == ed[1] or edge2[0].index == ed[1]:
						e2 = me.findEdges(edge2[0],edge2[1])
						Medge2 = me.edges[e2]
			
				if edge3[0].index == ed[0] or edge3[1].index == ed[0]:
					if edge3[1].index == ed[1] or edge3[0].index == ed[1]:
						e3 = me.findEdges(edge3[0],edge3[1])
						Medge3 = me.edges[e3]
			
				if edge4[0].index == ed[0] or edge4[1].index == ed[0]:
					if edge4[1].index == ed[1] or edge4[0].index == ed[1]:
						e4 = me.findEdges(edge4[0],edge4[1])
						Medge4 = me.edges[e4]


			# edges
			av1 = (Medge1.length + Medge2.length) / 2
			av2 = (Medge3.length + Medge4.length) / 2
			
			if av1 <= av2:
				stretch = av1 / av2 
			else:
				stretch = av2 / av1
			
			# diags
			d1_v1 = diag1[0]
			d1_v2 = diag1[1]
			diag_vec1 = Vector(d1_v1.co.x-d1_v2.co.x,d1_v1.co.y-d1_v2.co.y,d1_v1.co.z-d1_v2.co.z)
			
			d2_v1 = diag2[0]
			d2_v2 = diag2[1]
			diag_vec2 = Vector(d2_v1.co.x-d2_v2.co.x,d2_v1.co.y-d2_v2.co.y,d2_v1.co.z-d2_v2.co.z)
			
			d1L = diag_vec1.length
			d2L = diag_vec2.length

			if d1L <= d2L:
				stretchd = d1L / d2L
			else:
				stretchd = d2L / d1L

			
			# edges or diags more important?
			if stretchd < stretch:
				stretch = stretchd
			
		else: # operates on tris
			a = f.area
			e_len = me.edges[me.findEdges(f.verts[0],f.verts[1])].length
			h = (2 * a) / e_len
			
			if h <= e_len:
				stretch = h / e_len
			else:
				stretch = e_len / h
			
			
		#assign mats	
		if stretch <= s1.val:
			AssignMatToFace(f,mat1)
		if stretch <= s2.val:
			AssignMatToFace(f,mat2)
		if stretch <= s3.val:
			AssignMatToFace(f,mat3)
		if stretch <= s4.val:
			AssignMatToFace(f,mat4)
		if stretch <= s5.val:
			AssignMatToFace(f,mat5)
		if stretch <= s6.val:
			AssignMatToFace(f,mat6)
		if stretch <= s7.val:
			AssignMatToFace(f,mat7)
		if stretch <= s8.val:
			AssignMatToFace(f,mat8)
			
	if is_editmode: Window.EditMode(1)
	Window.WaitCursor(0)	
	
	Window.RedrawAll()
	
	print "done (",sys.time() - t,"sec.)"
	state = "done"
		
####################################################################
# GUI
####################################################################

#EV_NU_CritVal = 1
EV_BT_CheckTorsionA = 2

EV_CP_col1 = 3
EV_CP_col2 = 4
EV_CP_col3 = 5
EV_CP_col4 = 6
EV_CP_col5 = 7
EV_CP_col6 = 8
EV_CP_col7 = 9
EV_CP_col8 = 10

EV_NU_angle1 = 11
EV_NU_angle2 = 12
EV_NU_angle3 = 13
EV_NU_angle4 = 14
EV_NU_angle5 = 15
EV_NU_angle6 = 16
EV_NU_angle7 = 17
EV_NU_angle8 = 18

EV_BT_CheckAverageArea = 19

EV_CP_colref = 20

EV_BT_CheckStretch = 21

EV_NU_stretch1 = 22
EV_NU_stretch2 = 23
EV_NU_stretch3 = 24
EV_NU_stretch4 = 25
EV_NU_stretch5 = 26
EV_NU_stretch6 = 27
EV_NU_stretch7 = 28
EV_NU_stretch8 = 29

EV_BT_sil = 30

EV_NU_angle21 = 31
EV_NU_angle22 = 32
EV_NU_angle23 = 33
EV_NU_angle24 = 34
EV_NU_angle25 = 35
EV_NU_angle26 = 36
EV_NU_angle27 = 37
EV_NU_angle28 = 38

EV_TG_inverse = 39

#EV_TG_count = 40

EV_BT_exit = 41

##################################################################################################
def gui():
	global gui_pb_CheckTorsionA, gui_nu_CheckTorsionA
	global gui_cp_col1,gui_cp_col2,gui_cp_col3,gui_cp_col4,gui_cp_col5,gui_cp_col6,gui_cp_col7,gui_cp_col8
	global gui_nu_angle1,gui_nu_angle2,gui_nu_angle3,gui_nu_angle4,gui_nu_angle5,gui_nu_angle6,gui_nu_angle7,gui_nu_angle8
	global gui_cp_colref
	global gui_nu_stretch1,gui_nu_stretch2,gui_nu_stretch3,gui_nu_stretch4,gui_nu_stretch5,gui_nu_stretch6,gui_nu_stretch7,gui_nu_stretch8
	global gui_tg_inverse, gui_pb_CheckSilhouette
	global gui_nu_angle21,gui_nu_angle22,gui_nu_angle23,gui_nu_angle24,gui_nu_angle25,gui_nu_angle26,gui_nu_angle27,gui_nu_angle28
	global gui_tg_count
	global gui_pb_exit
	global state
	
	gui_cp_col1 = Draw.ColorPicker(EV_CP_col1,10,150,35,20,mat1_rgb.val)
	gui_cp_col2 = Draw.ColorPicker(EV_CP_col2,10,130,35,20,mat2_rgb.val)
	gui_cp_col3 = Draw.ColorPicker(EV_CP_col3,10,110,35,20,mat3_rgb.val)
	gui_cp_col4 = Draw.ColorPicker(EV_CP_col4,10,90,35,20,mat4_rgb.val)
	gui_cp_col5 = Draw.ColorPicker(EV_CP_col5,10,70,35,20,mat5_rgb.val)
	gui_cp_col6 = Draw.ColorPicker(EV_CP_col6,10,50,35,20,mat6_rgb.val)
	gui_cp_col7 = Draw.ColorPicker(EV_CP_col7,10,30,35,20,mat7_rgb.val)
	gui_cp_col8 = Draw.ColorPicker(EV_CP_col8,10,10,35,20,mat8_rgb.val)
	
	# torison
	gui_pb_CheckTorsionA = Draw.PushButton("Torsion angle",EV_BT_CheckTorsionA,50,175,90,20,"Runs a torsion angle check")
	#gui_nu_CheckTorsionA = Draw.Number("Crit val",EV_NU_CritVal,50,175,90,20,CritVal.val,0,180,"selects affected faces")
	
	gui_nu_angle1 = Draw.Number("",EV_NU_angle1,50,150,90,20,a1.val,0,180,"critical value for this color")
	gui_nu_angle2 = Draw.Number("",EV_NU_angle2,50,130,90,20,a2.val,0,180,"critical value for this color")
	gui_nu_angle3 = Draw.Number("",EV_NU_angle3,50,110,90,20,a3.val,0,180,"critical value for this color")
	gui_nu_angle4 = Draw.Number("",EV_NU_angle4,50,90,90,20,a4.val,0,180,"critical value for this color")
	gui_nu_angle5 = Draw.Number("",EV_NU_angle5,50,70,90,20,a5.val,0,180,"critical value for this color")
	gui_nu_angle6 = Draw.Number("",EV_NU_angle6,50,50,90,20,a6.val,0,180,"critical value for this color")
	gui_nu_angle7 = Draw.Number("",EV_NU_angle7,50,30,90,20,a7.val,0,180,"critical value for this color")
	gui_nu_angle8 = Draw.Number("",EV_NU_angle8,50,10,90,20,a8.val,0,180,"critical value for this color")
	
	# area
	gui_pb_CheckAverageArea = Draw.PushButton("Average area",EV_BT_CheckAverageArea,350,175,90,20,"Checks faces for their difference to the average area")
	gui_cp_colref = Draw.ColorPicker(EV_CP_colref,350,150,90,20,mat_ref_rgb.val)
	
	# stretch
	gui_pb_CheckTorsionA = Draw.PushButton("Stretch",EV_BT_CheckStretch,150,175,90,20,"Runs a stretch check")
	
	gui_nu_stretch1 = Draw.Number("",EV_NU_stretch1,150,150,90,20,s1.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch2 = Draw.Number("",EV_NU_stretch2,150,130,90,20,s2.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch3 = Draw.Number("",EV_NU_stretch3,150,110,90,20,s3.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch4 = Draw.Number("",EV_NU_stretch4,150,90,90,20,s4.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch5 = Draw.Number("",EV_NU_stretch5,150,70,90,20,s5.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch6 = Draw.Number("",EV_NU_stretch6,150,50,90,20,s6.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch7 = Draw.Number("",EV_NU_stretch7,150,30,90,20,s7.val,0.0,1.0,"critical value for this color")
	gui_nu_stretch8 = Draw.Number("",EV_NU_stretch8,150,10,90,20,s8.val,0.0,1.0,"critical value for this color")
	
	# silhouette
	gui_pb_CheckSilhouette = Draw.PushButton("Silhouette",EV_BT_sil,250,175,70,20,"")
	
	gui_nu_angle21 = Draw.Number("",EV_NU_angle21,250,150,90,20,a21.val,0,180,"critical value for this color")
	gui_nu_angle22 = Draw.Number("",EV_NU_angle22,250,130,90,20,a22.val,0,180,"critical value for this color")
	gui_nu_angle23 = Draw.Number("",EV_NU_angle23,250,110,90,20,a23.val,0,180,"critical value for this color")
	gui_nu_angle24 = Draw.Number("",EV_NU_angle24,250,90,90,20,a24.val,0,180,"critical value for this color")
	gui_nu_angle25 = Draw.Number("",EV_NU_angle25,250,70,90,20,a25.val,0,180,"critical value for this color")
	gui_nu_angle26 = Draw.Number("",EV_NU_angle26,250,50,90,20,a26.val,0,180,"critical value for this color")
	gui_nu_angle27 = Draw.Number("",EV_NU_angle27,250,30,90,20,a27.val,0,180,"critical value for this color")
	gui_nu_angle28 = Draw.Number("",EV_NU_angle28,250,10,90,20,a28.val,0,180,"critical value for this color")
	
	gui_tg_inverse = Draw.Toggle("Invert",EV_TG_inverse,320,175,20,20,inv.val,"Displays colors in reversed order")
	
	
	# count
	#name = "count"
	#gui_tg_count = Draw.Toggle(name,EV_TG_count,10,175,35,40,count.val,"outputs face-/edgecount in the console (slow!)")
	
	# exit
	gui_pb_exit = Draw.PushButton("Exit",EV_BT_exit,350,20,90,30,"")
	
	# copyright
	BGL.glColor3f(.4,.4,.4)
	BGL.glRasterPos2i(342, 10)
	Draw.Text("©2009, Fabian Fricke", "small")
	
	# info output
	BGL.glColor3f(0,0,0)
	BGL.glRasterPos2i(350, 68)
	Draw.Text("State: %s" % state, "small")
	
	BGL.glRasterPos2i(350, 55)
	if state is not state_idle:
		Draw.Text("Progress: %s" % progout +"%", "small")
	else:
		Draw.Text("Progress: -", "small")
	
	
##################################################################################################
def event(evt, val):
	if evt == Draw.ESCKEY or evt == Draw.QKEY:
		if matlist_set:
			RemoveMats(me)
		
		Draw.Exit()


##################################################################################################  
def button_event(evt):
	#if evt == 1:
	#	CritVal.val = gui_nu_CheckTorsionA.val
	if evt == 2:
		CheckTorsionAngles()
		Draw.Redraw()
	
	if evt == 3:
		mat1_rgb.val = gui_cp_col1.val
		mat1.rgbCol = mat1_rgb.val
		Draw.Redraw()
	if evt == 4:
		mat2_rgb.val = gui_cp_col2.val
		mat2.rgbCol = mat2_rgb.val
		Draw.Redraw()
	if evt == 5:
		mat3_rgb.val = gui_cp_col3.val
		mat3.rgbCol = mat3_rgb.val
		Draw.Redraw()
	if evt == 6:
		mat4_rgb.val = gui_cp_col4.val
		mat4.rgbCol = mat4_rgb.val
		Draw.Redraw()
	if evt == 7:
		mat5_rgb.val = gui_cp_col5.val
		mat5.rgbCol = mat5_rgb.val
		Draw.Redraw()
	if evt == 8:
		mat6_rgb.val = gui_cp_col6.val
		mat6.rgbCol = mat6_rgb.val
		Draw.Redraw()
	if evt == 9:
		mat7_rgb.val = gui_cp_col7.val
		mat7.rgbCol = mat7_rgb.val
		Draw.Redraw()
	if evt == 10:
		mat8_rgb.val = gui_cp_col8.val
		mat8.rgbCol = mat8_rgb.val
		Draw.Redraw()
	
	if evt == 11:
		a1.val = gui_nu_angle1.val
	if evt == 12:
		a2.val = gui_nu_angle2.val
	if evt == 13:
		a3.val = gui_nu_angle3.val
	if evt == 14:
		a4.val = gui_nu_angle4.val
	if evt == 15:
		a5.val = gui_nu_angle5.val
	if evt == 16:
		a6.val = gui_nu_angle6.val
	if evt == 17:
		a7.val = gui_nu_angle7.val
	if evt == 18:
		a8.val = gui_nu_angle8.val
		
	if evt == 19:
		CheckEvenArea()
		Draw.Redraw()
	
	if evt == 20:
		mat_ref_rgb.val = gui_cp_colref.val
		mat_ref.rgbCol = mat_ref_rgb.val
		Draw.Redraw()
	
	if evt == 21:
		CheckStretching()
		Draw.Redraw()
		
	if evt == 22:
		s1.val = gui_nu_stretch1.val
	if evt == 23:
		s2.val = gui_nu_stretch2.val
	if evt == 24:
		s3.val = gui_nu_stretch3.val
	if evt == 25:
		s4.val = gui_nu_stretch4.val
	if evt == 26:
		s5.val = gui_nu_stretch5.val
	if evt == 27:
		s6.val = gui_nu_stretch6.val
	if evt == 28:
		s7.val = gui_nu_stretch7.val
	if evt == 29:
		s8.val = gui_nu_stretch8.val
	
	if evt == 30:
		CheckSilhouette(inv.val)
		Draw.Redraw()
	if evt == 31:
		a21.val = gui_nu_angle21.val
	if evt == 32:
		a22.val = gui_nu_angle22.val
	if evt == 33:
		a23.val = gui_nu_angle23.val
	if evt == 34:
		a24.val = gui_nu_angle24.val
	if evt == 35:
		a25.val = gui_nu_angle25.val
	if evt == 36:
		a26.val = gui_nu_angle26.val
	if evt == 37:
		a27.val = gui_nu_angle27.val
	if evt == 38:
		a28.val = gui_nu_angle28.val
	
	if evt == 39:
		inv.val = gui_tg_inverse.val
		
	if evt == 40:
		count.val = gui_tg_count.val
		
	if evt == 41:
		if matlist_set:
			RemoveMats(me)
		Draw.Exit()

Draw.Register(gui,event,button_event)
CreateMats()