# -*- coding: utf-8 -*-

"""
authors:    Filip Šimić, Corvin Navarro, Annika Nassal, Paula Bauer, Adrian Krauss
project:    simple Starmap
"""

#==============================================================================
# MODULE
#==============================================================================
import numpy as np
import matplotlib.collections as mc
import matplotlib.pyplot as plt
import matplotlib.colors
from astropy.io.votable import parse
from astropy.io.votable import parse_single_table
import re
import matplotlib.image as mpimg
import math
from scipy import ndimage

#==============================================================================
# PLOT SETTINGS
#==============================================================================
showAxes = False
showColorbar = False
showConst = True
showConstImage = True
showGrid = True
constLinewidth = 0.2
constColor = "w"
constAlpha = 0.8
countStars = 600
transparence = 0.3
StarSize = 1
SaveFig = True

data_name1 = "data/vizier_votable_final.vot"
data_name2 = "data/vizier_votable1000.vot"       # 1000 hellsten Sterne
                                            # "Hellste Sterne.vot" 200 hell. S.

latitude = 50.0
min_declination = latitude - 90
min_magnitude = 6.0

mag_size = np.array([0.8, 0.4, 0.1, 0.08, 0.06, 0.03]) * 3

hip_filename = "data/vizier_votable.vot"
const_filename = "data/constellationship.fab"
constname_filename = "data/constellation_names.txt"

hip = parse(hip_filename)
hip_tab = hip.get_first_table()
hip_field = np.ma.filled(hip_tab.array)

#==============================================================================
# CREATE MAP
#==============================================================================
ax = plt.axes(xlim=(-1.6, 1.6), ylim=(-1.6, 1.6))
ax.set_xticks(np.arange(-1.0, 1.5, 0.5))
ax.set_yticks(np.arange(-1.0, 1.5, 0.5))
ax.set_facecolor('w')
ax.scatter(0, 0, s = 20000, color = 'k')
circle = plt.Circle((0,0),1.4,color='w',linewidth=48,fill=False)
equator = plt.Circle((0,0),0.69,color='r',fill=False, linewidth = 0.3)
ecliptic = plt.Circle((-0.18,0),0.69,color='y',fill=False, linewidth = 0.3)
ax.add_artist(circle)
ax.add_artist(equator)
ax.add_artist(ecliptic)

#==============================================================================
# COLORMAP
#==============================================================================
cdict = {
         'red':   ((0.0, 0.2, 0.2),
                    (0.2, 1.0, 1.0),
                    (0.4, 1.0, 1.0),
                    (0.8, 1.0, 1.0),
                    (1.0, 0.6, 0.6)),

         'green': ((0.0, 0.2, 0.2),
                    (0.2, 1.0, 1.0),
                    (0.4, 1.0, 1.0),
                    (0.8, 1.0, 1.0),
                    (1.0, 0, 0)),

         'blue':  ((0.0, 0.4, 0.4),
                    (0.2, 1.0, 1.0),
                    (0.4, 1, 1),
                    (0.6, 1, 1),
                    (0.8, 1, 1),
                    (1.0, 0.1, 0.1)),
                  
         'alpha': ((0.0, 1.0, 1.0),
                    (0.2, 1.0, 1.0),
                    (0.4, 1.0, 1.0),
                    (1.0, 1.0, 1.0))
        
}
colormap = matplotlib.colors.LinearSegmentedColormap('colormap', cdict)

#==============================================================================
# FUNCTIONS
#==============================================================================
""" hexToDecimal """
def hexToDecimal(hoursdegrees,minutes,seconds,unit):
    hoursdegrees = float(hoursdegrees)
    minutes = float(minutes)
    seconds = float(seconds)
    
    if unit == "deg":
        h = hoursdegrees + minutes/60 + seconds/3600
    elif unit == "hours":
        h = 15*hoursdegrees + 15*minutes/60 + 15*seconds/3600
    else:
        print "unit needs to be either \"hours\" or \"deg\""
        h = 0
    return h

""" polarToCartesian """
def polarToCartesian(ra,de):
    d = (90-de)/130
    x = math.cos(np.radians(90-ra)) * d
    y = math.sin(np.radians(90-ra)) * d
    return x,y

""" DrawStar """ 
def DrawStar( x, y, c, s):
    plt.scatter( x, y, c = c, s = s, cmap = colormap)
    
""" DrawLine """
def DrawLinePoints( x0, y0, x1, y1 ):
    x = [ x0, x1 ]
    y = [ y0, y1 ]
    plt.plot( x, y, color = constColor, linewidth = constLinewidth )
    
def DrawLineList( x, y ):
    plt.plot( x, y, color = constColor, linewidth = constLinewidth )
    
""" CalcColor """
def CalcColor( bv ):
    color = ( bv + 0.3 ) / 2.4
    return color   

""" CalcSize """
def CalcSize(vmag):   
    sizes = []
    for i in range(countStars):
        if (vmag[i] <= 0):
            sizes.append(mag_size[0])
        elif (vmag[i] >= 6):
            sizes.append(mag_size[5])
        elif (vmag[i] < 6 and vmag[i] > 0 ):
            if (vmag[i] > 0 and vmag[i] < 2 ):
                sizes.append(mag_size[1])
            elif (vmag[i] > 1 and vmag[i] < 3):
                sizes.append(mag_size[2])
            elif (vmag[i] > 2 and vmag[i] < 4):
                sizes.append(mag_size[3])
            elif (vmag[i] > 3 and vmag[i] < 5):
                sizes.append(mag_size[4])
                
    return sizes

""" drawConstellations """
def drawConstellations():
    constnamelist = []
    const_lines = []
    with open(const_filename, 'rt') as fin:
        for line in fin:
            line = line.strip()
            if line:
                word = re.split('\s+', line)
                num = int(word[1])
                xc, yc = 0, 0
                for i in range(num):
                    idx_0 = int(word[2+2*i+0])
                    idx_1 = int(word[2+2*i+1])
                    hip_idx_0 = np.searchsorted(hip_field['HIP'], idx_0)
                    hip_idx_1 = np.searchsorted(hip_field['HIP'], idx_1)

                    ra_0  = hip_field['RArad'][hip_idx_0]
                    dec_0 = hip_field['DErad'][hip_idx_0]
                    x0, y0 = polarToCartesian(ra_0, dec_0)

                    ra_1  = hip_field['RArad'][hip_idx_1]
                    dec_1 = hip_field['DErad'][hip_idx_1]
                    x1, y1 = polarToCartesian(ra_1, dec_1)

                    xc += 0.5 * (x0 + x1)
                    yc += 0.5 * (y0 + y1)

                    if (dec_0 > min_declination and dec_1 > min_declination):
                        const_lines.append([[x0, y0], [x1, y1]])

                xc /= num
                yc /= num
                
                constnamelist.append([word[0], [xc,yc]])

    constellation_coll = mc.LineCollection(const_lines, color=constColor,
                                           linewidth=constLinewidth)
    constellation_coll.set_zorder(55)
    ax.add_collection(constellation_coll)
    
#==============================================================================
# MAIN
#==============================================================================

""" star data """    
print "Load hipparcos data ..."
HIPbright = parse_single_table(data_name2)
HIPbdata = HIPbright.array
vmag = []
rade = []
bv = []
radec = []
for star in range(countStars):
    if (HIPbdata[star]["DEdms"] > -40):
        vmag.append(HIPbdata[star]["Vmag"])
        rade.append(HIPbdata[star]["RAhms"])
        rade.append(HIPbdata[star]["DEdms"])
        bv.append(HIPbdata[star]["B-V"])
        radec.append(rade)
        rade = []

""" calculate correct color """
bv = np.array( bv )
bv = CalcColor( bv )

""" calculate size """
vmag = np.array(vmag)
vmag = CalcSize(vmag)

""" convert ra and de in x and y """
xs = []
ys = []

for star_coords in radec:
    ra = star_coords[0]
    de = star_coords[1]

    ra_h, ra_m, ra_s = ra.split(" ")

    ra_degrees = hexToDecimal(ra_h,ra_m,ra_s,"hours")
    
    de_d, de_m, de_s = de.split(" ")
    
    de_degrees = hexToDecimal(de_d,de_m,de_s,"deg")
    
    x,y = polarToCartesian(ra_degrees,de_degrees)
    xs.append(x)
    ys.append(y)
    
""" draw stars """
print "Load stars ..."
DrawStar( xs, ys, bv, vmag )
 
""" load constellations """
print "Load constellations ..."
if (showConst == True):   
    drawConstellations()   
    
""" load constellation images """
allImages = 18
if (showConstImage == True):
    print "Load constellation images ..."
    einhorn = mpimg.imread( "image\Einhorn.png" )                       # check
    becher = mpimg.imread("image\Becher.png") 
    delphin = mpimg.imread("image\Delphin.png")                         # check                
    drache = mpimg.imread("image\Drache.png")                           # check               
    dreieck = mpimg.imread("image\Dreieck.png") 
    fische = mpimg.imread("image\Fische.png")                           # check
    krebs = mpimg.imread("image\Krebs.png")
    krone = mpimg.imread("image\Krone.png")                             # check              
    skorpion = mpimg.imread("image\Skorpion.png")                       # check     
    waage = mpimg.imread("image\Waage.png")
    adler = mpimg.imread("image\Adler.png")                             # check             
    baerenhueter = mpimg.imread("image\Baerenhueter_fertig.png")        # check  
    hase = mpimg.imread("image\Hase.png")                               # check          
    jungfrau = mpimg.imread("image\Jungfrau.png")
    pegasus = mpimg.imread("image\Pegasus.png")                         # check    
    steinbock = mpimg.imread("image\Steinbock_fertig.png")
    stier = mpimg.imread("image\Stier.png")                             
    widder = mpimg.imread("image\Widder.png")
    grosseBaerin = mpimg.imread("image\GrosseBaerin.png")               # check
    loewe = mpimg.imread("image\loewe3.png")                            # check
    perseus = mpimg.imread("image\Perseus_fertig.png")                  # check
    walfisch = mpimg.imread("image\Walfisch_fertig.png")                # check
    cassiopeia = mpimg.imread("image\Cassiopeia.png")
    fuellen = mpimg.imread("image\Fuellen.png")
    giraffe = mpimg.imread("image\Giraffe.png")
    jadghunde = mpimg.imread("image\Jagdhunde.png")
    kompass = mpimg.imread("image\Kompass.png")
    leier = mpimg.imread("image\Leier.png")                             # check               
    rabe = mpimg.imread("image\Rabe.png")
    schwan = mpimg.imread("image\Schwan copy.png")                      # check
    stopp = mpimg.imread("image\stopp.png")
    zwillinge = mpimg.imread("image\Zwillinge copy.png")
    
    print "Initialize constellation images ..."
    
    skorpion = ndimage.rotate(skorpion, 65, reshape = False)
    plt.imshow(skorpion, extent = [-1.17, -0.32, -0.2, -0.56], alpha = constAlpha,
               zorder = 5)
    print "\t1 /", allImages
    
    drache = ndimage.rotate(drache, 95, reshape = False)
    plt.imshow(drache, extent = [-0.85, 0.5, -0.6, 0.5], alpha = constAlpha,
               zorder = 6)
    print "\t2 /", allImages
    
    krone = ndimage.rotate(krone, 340, reshape = False)
    plt.imshow(krone, extent = [-0.53, -0.25, -0.37, -0.01], alpha = constAlpha,
               zorder = 7)
    print "\t3 /", allImages
    
    pegasus = ndimage.rotate(pegasus, 345, reshape = False)
    plt.imshow(pegasus, extent = [0.7, -1, 0.1, 0.95], alpha = constAlpha,
               zorder = 8)
    print "\t4 /", allImages
    
    fische = ndimage.rotate(fische, 20, reshape = False)
    plt.imshow(fische, extent = [-0.1, 0.6, 0.425, 0.74], alpha = constAlpha,
               zorder = 9)
    print "\t5 /", allImages
    
    plt.imshow(baerenhueter, extent = [-0.39, -0.2, -0.52, -0.22], alpha = constAlpha,
               zorder = 10)
    print "\t6 /", allImages
    
    delphin = ndimage.rotate(delphin, 250, reshape = False)
    plt.imshow(delphin, extent = [-0.56, -0.35, 0.33, 0.45], alpha = constAlpha,
               zorder = 11)
    print "\t7 /", allImages
    
    hase = ndimage.rotate(hase, 264)
    plt.imshow(hase, extent = [0.9, 0.7, -0.05, 0.24], alpha = constAlpha,
               zorder = 12)
    print "\t8 /", allImages
    
    grosseBaerin = ndimage.rotate(grosseBaerin, 35)
    plt.imshow(grosseBaerin, extent = [-0.25, 0.35, -0.45, -0.05], alpha = constAlpha,
               zorder = 13)
    print "\t9 /", allImages
    
    adler = ndimage.rotate(adler, 70)
    plt.imshow(adler, extent = [-0.40, -0.83, 0.395, 0.12], alpha = constAlpha,
               zorder = 14)
    print "\t10 /", allImages
     
    einhorn = ndimage.rotate(einhorn, 70, reshape = False)
    plt.imshow(einhorn, extent = [0.8, 1.1, 0.1, -0.1], alpha = constAlpha,
               zorder = 15)
    print "\t11 /", allImages
    
    loewe = ndimage.rotate(loewe, 185, reshape = False)
    plt.imshow(loewe, extent = [0.35, 0, -0.38, -0.62], alpha = constAlpha,
               zorder = 16)
    print "\t12 /", allImages
    
    perseus = ndimage.rotate(perseus, 160, reshape = False)
    plt.imshow(perseus, extent = [0.15, 0.4, 0.1, 0.35], alpha = constAlpha,
               zorder = 17)
    print "\t13 /", allImages
    
    walfisch = ndimage.rotate(walfisch, 110, reshape = False)
    plt.imshow(walfisch, extent = [0, 0.65, 0.45, 0.84], alpha = constAlpha,
               zorder = 18)
    print "\t14 /", allImages

    leier = ndimage.rotate(leier, 250, reshape = False)
    plt.imshow(leier, extent = [-0.4525, -0.3525, -0.01, 0.18], alpha = constAlpha,
               zorder = 19)
    print "\t15 /", allImages
    
    schwan = ndimage.rotate(schwan, 180, reshape = False)
    plt.imshow(schwan, extent = [-0.72, 0.05, -0.07, 0.42], alpha = constAlpha,
               zorder = 20)
    print "\t16 /", allImages

    stier = ndimage.rotate(stier, 150)
    plt.imshow(stier, extent = [0.2, 0.79, -0.1, 0.4], alpha = constAlpha,
               zorder = 21)
    print "\t17 /", allImages

    zwillinge = ndimage.rotate(zwillinge, 115)
    plt.imshow(zwillinge, extent = [0.3, 0.7, -0.6, 0.37], alpha = constAlpha,
               zorder = 22)
    print "\t18 /", allImages

elif (showConstImage == False):
    adler = mpimg.imread("image\Adler.png")  
    plt.imshow(adler, alpha = 0, zorder = 5, cmap = colormap)

""" show composition """
if ( showAxes == False ):
    plt.axis( "off" )
if showColorbar == True:
    plt.colorbar()
if showGrid == True:
    plt.grid(True,linewidth=0.5,linestyle='-',color='w')
if SaveFig == True:
    plt.savefig('Sternkarte.png',format='png',dpi=1000)
plt.show()