#!/usr/bin/env python3
"""Transfer UV mappings from one mesh onto another

Textures work by giving each vertex x and y values (normally between 
0 and 1) representing the point on the texture image file which that vertex 
is located at. (For example, 0.4 means it's four tenths of the way 
across/down.) This script will assign such values to one submesh based 
on what it finds on another submesh. If vertices from each are in precisely 
the same location, the mesh you're modifying will receive the same values 
as on the mesh you're taking values from, otherwise the script will try 
to project the equivalent location from the closest vertex, edge or face.
This is mostly useful when you have two closely overlaying meshes and you 
want to take textures from the other.

The first argument is the mesh you are modifying - giving textures to.

The second argument should be a modified version of that mesh in which 
any vertices which you don't want to change have been removed or moved 
far away from their original locations, so the script knows what to skip.
If you're modifying the whole thing, it can just be the same as the first 
argument.

If run without any further arguments, the script will print the distance from 
each vertex to the closest thing it can find on the modified version, to help 
with choosing a threshhold. Otherwise, the other arguments should be supplied.

The third argument is a number, any vertex which is further away from anything 
in the modified version than this number will be left unchanged.
if you're modifying the whole thing, it can just be 1, assuming you're 
supplying the same mesh as the first two arguments, as you should be.

The fourth argument is the mesh you are copying texture points from.

The fifth argument is where to write the result.
"""

This script will assign x and y values representing the place the me

import sys

import vb
import distance

def give_tex(v, target):
	if len(target) == 1:
		provide = target[0].tex()
	elif len(target) == 3:
		a = target[0].tex()
		pb = target[1]
		b = target[2].tex()
		provide = [pb * b[i] + (1-pb) * a[i] for i in range(2)]
	else:
		a = target[0].tex()
		pb = target[1]
		b = target[2].tex()
		pc = target[3]
		c = target[4].tex()
		provide = [pb * b[i] + pc * c[i] + (1-pb-pc) * a[i] for i in range(2)]
	provide[0] += 33/64
	provide[1] += 2/64
	v.settex(provide)

def main(modpath, signalpath, thresh=None, copypath=None, outpath=None):
	modmesh = vb.Mesh(modpath)
	signalmesh = vb.Mesh(signalpath)
	if thresh is None:
		for v in modmesh.vertices:
			print (v.difference(signalmesh.most_similar_to(v)))
		sys.exit(0)
	copymesh = vb.Mesh(copypath)
	for v in modmesh.vertices:
		if v.difference(signalmesh.most_similar_to(v)) > thresh:
			continue
		distances = []
		for w in copymesh.vertices:
			distances.append((v.distance(w), w))
		for f in copymesh.faces:
			for x, y in [(f[0], f[1]), (f[0], f[2]), (f[1], f[2])]:
				a = copymesh.vertices[x]
				b = copymesh.vertices[y]
				res = distance.l_distance(a.pos(), b.pos(), v.pos())
				if res is not None:
					distances.append((res[1], a, res[0], b))
			a = copymesh.vertices[f[0]]
			b = copymesh.vertices[f[1]]
			c = copymesh.vertices[f[2]]
			res = distance.t_distance(a.pos(), b.pos(), c.pos(), v.pos())
			if res is not None:
				distances.append((res[2], a, res[0], b, res[1], c))
		distances.sort(key=lambda x:x[0])
		give_tex(v, distances[0][1:])
	modmesh.write(outpath)

if __name__ == '__main__':
	if len(sys.argv) == 3:
		main(sys.argv[1], sys.argv[2])
	else:
		main(sys.argv[1], sys.argv[2], float(sys.argv[3]), sys.argv[4], sys.argv[5])

