# Adapted from symetry.py by vnd@seznam.cz
# This is stripped down to help with target creation...NO UV or coloring done here
# Use the original for a more robust symetry app
#
# Craig Smith

import Blender
from Blender import NMesh
from Blender.Draw import *
from Blender.BGL import *

adjustVertexCoords = Create(1)
delta = 0.001
delta2 = delta * delta

def MHdist2sym (verts, v1, v2):
	
	x1, y1, z1 = verts[v1].co
	x2, y2, z2 = verts[v2].co

	x2 = -x2

	dx = x1 - x2
	dy = y1 - y2
	dz = z1 - z2

	return dx * dx + dy * dy + dz * dz

def MHmakeSymetry (verts, faces, left, right, centr, corresp):

	moved = [0] * len(verts)
	for i in range(0, len(right)):
		vi = right[i]
		cvi = corresp[vi]
		if (cvi == -1):
			continue

		if (MHdist2sym(verts, vi, cvi) >= delta2):
			moved[vi] = 1
		
		x, y, z = verts[cvi].co
		
		verts[vi].co[0] = -x
		verts[vi].co[1] = y
		verts[vi].co[2] = z
		
	for i in range(0, len(corresp)):
		if (i == corresp[i]):
			x = verts[i].co[0]
			if (x < -delta or x > delta):
				moved[i] = 2
			verts[i].co[0] = 0
	return moved

def MHcreateEdgeDict(faces):

	edges = {}
	for i in range(0, len(faces)):
		numf = len(faces[i].v)
		for vi in range(0, numf):
			v1 = faces[i].v[vi].index
			v2 = faces[i].v[(vi + 1) % numf].index
			if ((v1,v2) in edges and edges[(v1,v2)] != (i, vi)):
				print "edge in 2 faces, this should not happen"
			edges[(v1,v2)] = (i, vi)

	return edges
	

def MHcheckCorrespFace(faces, corresp, correspfaces, f1, f2, offset):
	
	numf = len(faces[f1].v)

	if (numf != len(faces[f2].v)):
		return 0

	for vi in range(0, numf): 
		v1 = faces[f1].v[vi].index
		vi2 = (numf - vi + offset) % numf

		v2 = faces[f2].v[vi2].index
		
		c1 = corresp[v1]

		if (c1 != -1 and c1 != v2):
			return 0
	return 1
	
def MHsetCorrespFace(faces, corresp, correspfaces, f1, f2, offset):

	if (correspfaces[f1] != -1 and correspfaces[f1] != f2 or correspfaces[f2] != -1 and correspfaces[f2] != f1):
		print "corresp face already set", f1, f2
		return 0

	correspfaces[f1] = f2;
	correspfaces[f2] = f1;
	numf = len(faces[f1].v)

	for vi in range(0, numf): 
		v1 = faces[f1].v[vi].index
		vi2 = (numf - vi + offset) % numf
		v2 = faces[f2].v[vi2].index
		
		if (corresp[v1] != -1 and corresp[v1] != v2 or corresp[v2] != -1 and corresp[v2] != v1):
			print "corresp face already set", f1, f2, v1, v2
			return 0
		
		corresp[v1] = v2
		corresp[v2] = v1
	return 1

def MHfindCorresp(verts, left, right, ylist, corresp):

	for i in range(0, len(ylist)):
		y0, vi0, side0 = ylist[i]
		
		if (corresp[vi0] != -1):
			continue
		
		i2 = i + 1
		
		while (i2 < len(ylist) and ylist[i2][0] - y0 <= delta):
			y, vi, side = ylist[i2]
			
			
			i2 = i2 + 1
			
			if (side == side0):
				continue
			
			if (MHdist2sym(verts, vi0, vi) < delta2):
				corresp[vi0] = vi
				corresp[vi] = vi0
				break
	
def MHfindCorrespFaces(faces, left, right, corresp, correspfaces):

	notchanged = 1
	
	edges = MHcreateEdgeDict(faces)
	
	for i in range(0, len(faces)):
		if (correspfaces[i] != -1):
			continue
		
		numf = len(faces[i].v)
		for vi in range(0, numf):
			c1 = corresp[faces[i].v[vi].index]
			c2 = corresp[faces[i].v[(vi + 1) % numf].index]
			if (c1 != -1 and c2 != -1):
			
			        if ((c2,c1) not in edges):
					continue
				cf, offset = edges[(c2,c1)]
				offset = offset - vi + 1
			
				if (not MHcheckCorrespFace(faces, corresp, correspfaces, i, cf, offset)):
					continue
				if (not MHsetCorrespFace(faces, corresp, correspfaces, i, cf, offset)):
					continue
				notchanged = 0
				break
	return notchanged

def MHfindSymetry (verts, faces):

	left = []
	right = []
	centr = []
	corresp = []
	correspfaces = []
	
	ylist = []
	
	for i in range(0, len(verts)):
		corresp.append(-1)
		x, y, z = verts[i].co
		if (x <= -delta):
			left.append(i)
			ylist.append([y,i,'l'])
		elif (x >= delta):
			right.append(i)
			ylist.append([y,i,'r'])
		else:
			centr.append(i)
			corresp[i] = i

	ylist.sort()
	MHfindCorresp(verts, left, right, ylist, corresp)
	correspVerts = corresp[:]

	for i in range(0, len(faces)):
		correspfaces.append(-1)



	res = 0
	while (res == 0):
		res = MHfindCorrespFaces(faces, left, right, corresp, correspfaces)

	return (left, right, centr, corresp, correspVerts, correspfaces)
	

def MHsym():
	"""
	DESCRIPTION:
	Attempts to make the both sides of the mesh symmetrical.
	This code has been adapted from the original symetry.py
	from vnd@seznam.cz.  The homepage is http://sweb.cz/vnd/symetry/
	
	SYNOPSIS:
	MHsym()
	
	PARAMETERS:
	None

	RETURN VALUES:
	None
	"""

	global adjustVertexCoords
	Objects = Blender.Object.GetSelected()
	
	mesh = Objects[0].data

	left = []
	right = []
	centr = []
	corresp = []

	left, right, centr, corresp, correspVerts, correspFaces = MHfindSymetry (mesh.verts, mesh.faces)

	if (adjustVertexCoords.val):
		moved = MHmakeSymetry (mesh.verts, mesh.faces, left, right, centr, corresp)

	mesh.update()
	Objects[0].makeDisplayList()		# added
	Blender.Redraw()