"""
CC BY-SA, (http://www.creativecommons.org/licenses/)
September 2012, Lukas Treyer, Information Architecture, ETH Zurich
Course: http://www.ia.arch.ethz.ch/category/teaching/hs2012-complexcity/
"""

import bpy, math, sys, random
from mathutils import Color, Vector

# define lists and variables
blocks = [o for o in bpy.data.objects if "ColorPoly" in o.name]
all_blocks = [o for o in bpy.data.objects if "ColorPoly" in o.name]
points = bpy.data.objects['Points_dense']
treshold = 300

# linear interpolation:
def linterpolate(val, lmin, lmax, rmin, rmax):
    return (val - lmin)/(lmax-lmin)*(rmax-rmin)+rmin

# iterate through all meshes
def calc(blocks,points):
    vmin = 10000
    vmax = 0.000001
    for i,block in enumerate(blocks):
        mesh = block.data
        proxy = []
        angle = []
        count = []
        
        for j,face in enumerate(mesh.polygons):
            normal = face.normal
            sys.stdout.write("\r Block "+str(i+1)+" of "+str(len(blocks))+"; Face "+str(j+1)+" of "+str(len(mesh.polygons)))
            pr = an = 0
            cnt = 1
            
            x = sum([mesh.vertices[v].co[0] for v in face.vertices])/len(face.vertices)
            y = sum([mesh.vertices[v].co[1] for v in face.vertices])/len(face.vertices)
            z = sum([mesh.vertices[v].co[2] for v in face.vertices])/len(face.vertices)
            v = Vector((x,y,z))
            vco = v+block.location

            pts = [points.data.vertices[25],points.data.vertices[19],points.data.vertices[20]]

            for p in points.data.vertices:
                visible = True
                pco = p.co + points.location
                
                for b in all_blocks:
                    bpco = pco - b.location
                    
                    if b.name != block.name:
                        bvco = vco - b.location
                        #if b.name == "ColorPoly.032": print(bvco)
                        pos, n, index = b.ray_cast(bvco,bpco)
                        # ray_cast returns -1 for polygon index i, if it didn't find an intersection
                        if index != -1:
                            visible = False
                            break
                    else:
                        pos, n, index = b.ray_cast(v+(0.01*face.normal),bpco)
                        if index != -1:
                            visible = False
                            break
                if visible:
                    
                    ray = pco-vco
                    length = ray.length/treshold
                    length = (1-length if length < 1 else 0)
                    
                    # angle between ray and normal. no good if == 0 because of ***rating***
                    a = abs(ray.angle(normal))

                    #                                           normalization to 0....1
                    a = (a if a > 0 else 0.000001)/(math.pi/2)

                    cnt += 1
                    # per point visibility in a range of 0....1 (***rating***)
                    # 1 = very visible; 0 = visible but not noticeable
                    pr += length
                    an += 1-a
 
            # viz max = 1
            # viz min = 0
            proxy.append(pr/cnt)  # proximity
            angle.append(an/cnt)  # angle
            count.append(cnt)     # amount of viewpoints

        block['v_proximity'] = proxy
        block['v_angle'] = angle
        block['v_count'] = count

# colorize the vertices in a new vertex color map
def colorize(blocks):
    cmax = 0
    for block in blocks:
        m = max(block['v_count'])
        if m > cmax: cmax = m
    print(cmax)
    for block in blocks:
        if "v_proximity" in block.keys() and "v_angle" in block.keys() and "v_count" in block.keys():
            mesh = block.data
            proxy = block['v_proximity']
            angle = block['v_angle']
            count = block['v_count']            
            
            # add a new vertex color map
            if "Viz" not in mesh.vertex_colors.keys():
                viz = mesh.vertex_colors.new('Viz')
            
            j = 0
            for i,face in enumerate(mesh.polygons):
                c = linterpolate(count[i],1,cmax,0,1)
                rgb = (c,proxy[i],angle[i])
                if i == 1520: print(rgb)
                col = Color(rgb)
                    
                for i in face.vertices:
                    mesh.vertex_colors['Viz'].data[j].color = col
                    j += 1

#calc(blocks,points)
#colorize(blocks)