
######## DM2
######## iam@richdank.com and agruber@tugraz.at
######## http://iam.tugraz.at/dm2/
######## library



################
######## basic library data and functions
################

######## credits
lib_cc = "DM2 LIBRARY\n    version "
lib_cc += "2021-01-06 13:31:00"
lib_cc += "\n    CC by-nc-sa "
lib_cc += "diag / richdank" 

######## import
import rhinoscriptsyntax as rs
import scriptcontext as sc
import RhinoPython.Host as _host
from datetime import datetime
import random
import time
import math
from itertools import combinations
from itertools import permutations
import System, System.DateTime



################
######## functions 4kepler
################

######## calc regular dodecahedron coordinates
def getDodecaCoords( radius=10.0, verbose=0, floating=0 ):
    radVec = rs.VectorRotate( [radius, 0, 0], -36, [0,0,1] )
    angBeta = math.degrees(math.acos( 5**0.5/-5 ))
    coordsP = []
    for i in range(3,6):
        cor = rs.VectorAdd( rs.VectorRotate( radVec, 72.0*i, [0,0,1] ), [-math.cos(math.radians(36.0))*radius, 0,0])
        cor = rs.VectorRotate(cor, angBeta, [0,1,0])
        cor = rs.VectorSubtract(cor, [-math.cos(math.radians(36.0))*radius, 0,0])
        coordsP.append(cor)
    coordsP.reverse()
    cor = coordsP[0:1][0]
    cor = [coordsP[0][0],coordsP[0][1], coordsP[1][2]+coordsP[2][2]]
    cor = rs.VectorRotate( cor, 36.0, [0,0,1] )
    coordsP.append(cor)
    coords=[]
    coords.extend( [rs.VectorRotate(cor, 72.0*i, [0,0,1]) for cor in coordsP for i in range(0,5)] )
    if verbose:
        print "def getDodecaCoords() returns", len(coords), " coords .. bingo !"
        for i,cor in enumerate(coords[0:3]):
            print "    ",i,"[",cor,"]"
        print "    ",i+1,"etc"
    if floating:
        cnt = pntCentroid( coords )
        rand_axis = [ random.uniform(-1,1), random.uniform(-1,1), random.uniform(-1,1) ]
        rand_angle = random.uniform(-180,180)
        for c,coord in enumerate(coords) :
            coord = rs.VectorSubtract( coord, cnt )
            coord = rs.VectorRotate( coord, rand_angle, rand_axis )
            coords[c] = coord
    return coords

######## get the indices of each pentagon
def getPentaIndices(verbose=0):
    indicesOfPentagons = [[4,3,2,1,0]] # dixi 201030
    for i in range(10):
        indi = [i, i+1, i+6, i+10, i+5, i]
        if i == 4:
            indi[1]=0
            indi[2]=5
        if i > 4:
            indi = [i, i+5, i+10, i+14, i+9, i]
        if i > 5:
            indi[3]=i+9
            indi[4]=i+4
        indicesOfPentagons.append( indi[0:-1] )
    indicesOfPentagons.append([15,16,17,18, 19])
    #print len(indicesOfPentagons)
    if verbose:
        print "def getPentaIndices() returns", len(indicesOfPentagons), " index_lists 4 single pentagons .. bingo !"
        for i, indis in enumerate(indicesOfPentagons[0:3]):
            print "    penta_"+str(i),":", indis
        print "    penta_"+str(i+1),": etc"
    return indicesOfPentagons
### USAge in script
#pentaCoords  = dm2.getDodecaCoords()
#pentaIndices = dm2.getPentaIndices()



################
######## functions 4unitednations
################

def getUnoGridCoords(L=11, D=4, H=40, fH = 4.0):
    baseCoords = rs.CurveEditPoints(rs.ObjectsByName("_bldg3D_crv_137989966")[0])
    baseXYZ = baseCoords[14]
    dirY = rs.VectorSubtract( baseCoords[10], baseCoords[14] )
    dirX = [dirY[1], dirY[0]*-1.0,0] # normal vec
    lenY = rs.VectorLength( dirY ) 
    lenX = rs.VectorLength( rs.VectorSubtract( baseCoords[15], baseCoords[14] ) )
    uniX = rs.VectorUnitize(dirX)
    uniY = rs.VectorUnitize(dirY)
    D += D<2
    slab_spacing = lenY/(L-1)
    UnoGridCoords = []
    for z in range(H):
        for x in range(D):
            for y in range(L):
                cor = baseXYZ
                cor = rs.VectorAdd( cor, rs.VectorScale(uniX, lenX*x/(D-1)))
                cor = rs.VectorAdd( cor, rs.VectorScale(uniY, slab_spacing*y))
                cor = rs.VectorAdd( cor, [0,0, fH*z])
                UnoGridCoords.append( cor )
    print "*** len UnoGridCoords =",L,"*",D,"*", H,"=", len(UnoGridCoords),"   by getUnoGridCoords() @ dm2_lib"
    return UnoGridCoords

def getUnoCoord( l, d, h ):
    if l >= L or d >= D or h >= H:
        print "*** getUnoCoord: any parameter too big:",l,d,h,"? ______________***"
        #return UnoGridCoords[ 0 ]
        return [0,0,0]
    else:
        return UnoGridCoords[ l + d*L + h*D*L ]

UnoGridCoords = []  # just 4 check in hu_05_basic_script_structure
                    # diag 201107_00:00

##############
def makeRelief(spine=" ", dir="len", num=8, startRad=1, endRad=5, verbose=0 ):
    rs.UnselectAllObjects()
    rs.UnitAbsoluteTolerance( 0.10001 )
    newEmptyLayer("UNO::relief::"+dir, [100,110,110])
    depthVec  = rs.VectorUnitize(rs.VectorSubtract( getUnoCoord(0, 0, 0), getUnoCoord(0, 2, 0) ))
    lengthVec = rs.VectorUnitize(rs.VectorSubtract( getUnoCoord(0, 0, 0), getUnoCoord(1, 0, 0) ))
    p0 = getUnoCoord(0,0,0)
    if dir == "len":
        p1 = getUnoCoord(10,0,0)
        normVec = depthVec
    if dir == "dep":
        p1 = getUnoCoord(0,3,0)
        normVec = lengthVec
    if dir == "hig":
        p1 = getUnoCoord(0,0,39)
        normVec = depthVec
    lenXcrv = rs.AddCurve( [p0, p1] )
    rs.ObjectColor( lenXcrv, [200,0,0] )
    if 1:
        for p in range(0, num+1):
            esc()
            p = float(p)
            fac = p / num
            planeX = plnCurvePerp(lenXcrv, fac)
            if verbose: rs.AddPoint( planeX[0] )
            intersections = rs.PlaneCurveIntersection(planeX, spine)
            centers = []
            if intersections:
                for intersection in intersections:
                    if 0 or verbose: rs.ObjectColor( rs.AddPoint(intersection[1]), [0,200,0] )
                    centers.append( intersection[1] )
            radius = startRad + (endRad-startRad)*p/(num-0)
            if verbose: print radius, "-", p/(num-0)
            if 1:
                circles = []
                for cen in centers:
                    planeX = rs.PlaneFromPoints(cen, rs.VectorAdd(cen, normVec),rs.VectorAdd(cen,[0,0,1]))
                    if dir == "hig":
                        planeX = rs.PlaneFromPoints(cen, rs.VectorAdd(cen, [1,0,0]),rs.VectorAdd(cen,[0,1,0]))
                    circ = rs.AddCircle(planeX, radius)
                    rs.ObjectName( circ, "tstShape")
                    circles.append(circ)
                # slab
                if dir == "len":
                    p0 = pntCurvePerp(lenXcrv, fac)
                    p1 = rs.VectorAdd( p0, [0,0,(H-1)*fH] )
                    p2 = rs.VectorAdd( p1, rs.VectorSubtract( getUnoCoord(0, 3, 0), getUnoCoord(0, 0, 0) ) )
                    p3 = rs.VectorAdd( p0, rs.VectorSubtract( getUnoCoord(0, 3, 0), getUnoCoord(0, 0, 0) ) )
                if dir == "dep":
                    p0 = pntCurvePerp(lenXcrv, fac)
                    p1 = rs.VectorAdd( p0, [0,0,(H-1)*fH] )
                    p2 = rs.VectorAdd( p1, rs.VectorSubtract( getUnoCoord(10, 0, 0), getUnoCoord(0, 0, 0) ) )
                    p3 = rs.VectorAdd( p0, rs.VectorSubtract( getUnoCoord(10, 0, 0), getUnoCoord(0, 0, 0) ) )
                if dir == "hig":
                    p0 = pntCurvePerp(lenXcrv, fac)
                    p1 = rs.VectorAdd( p0, rs.VectorSubtract( getUnoCoord(10, 0, 0), getUnoCoord(0, 0, 0) ) )
                    p2 = rs.VectorAdd( p1, rs.VectorSubtract( getUnoCoord(0, 3, 0), getUnoCoord(0, 0, 0) ) )
                    p3 = rs.VectorAdd( p0, rs.VectorSubtract( getUnoCoord(0, 3, 0), getUnoCoord(0, 0, 0) ) )
                reliefCrv = rs.AddCurve( [p0, p1, p2, p3, p0] , 1)
                rs.Command("cplane object selID "+str(reliefCrv), 0)
                rs.ObjectName(reliefCrv, "reliefCrv")
                fullRelief = rs.AddCurve( [p0, p1, p2, p3, p0] , 1)
                rs.ObjectName(fullRelief, "fullRelief")
                #rs.HideObject( fullRelief )
                tstShapes = rs.ObjectsByName("tstShape*")
                for i, shp in enumerate(tstShapes):
                    if pntCurveDist( centers[i], fullRelief ) >= radius:
                        #rs.DeleteObject( shp )
                        tstShapes.remove( shp )
                if verbose:
                    print "distFromFrame =", pntCurveDist( centers[i], fullRelief )
                    rs.ObjectColor( rs.AddPoint(centers[i]), [100,0,100] )
                #tstShapes = rs.ObjectsByName("tstShape*")
                if 1 and len(tstShapes):
                    if len(tstShapes) >  1:
                        rs.ObjectName( rs.CurveBooleanUnion( rs.ObjectsByName("tstShape") ), "booled" )
                        rs.DeleteObjects( rs.ObjectsByName("tstShape") )
                    else:
                        pass
                        rs.ObjectName(rs.ObjectsByName("tstShape*"), "booled")
                    rs.Command("-split -selName  \"reliefCrv\" enter -selName \"booled\" enter", 0)
                    if 1:
                        reliefCrv2kill=[]
                        for crv in rs.ObjectsByName("reliefCrv"):
                            mid = rs.CurveMidPoint( crv )
                            if verbose: rs.AddPoint( mid )
                            for shp in rs.ObjectsByName("booled"):
                                if 1 == rs.PointInPlanarClosedCurve( mid, shp, plane=planeX, tolerance=None):
                                    rs.ObjectColor( crv, [0,200,0]) 
                                    reliefCrv2kill.append(crv )
                                    break
                        rs.DeleteObjects( reliefCrv2kill )
                    rs.Command("-split -selName  \"booled\" enter -selName \"reliefCrv\" enter", 0)
                    if 1:
                        booled2kill=[]
                        for crv in rs.ObjectsByName("booled"):
                            if rs.IsCurveClosed( crv ):
                                rs.ObjectColor( crv, [200,200,200]) 
                            mid = rs.CurveMidPoint( crv )
                            #rs.AddPoint( mid )
                            if 0 == rs.PointInPlanarClosedCurve( mid, fullRelief, plane=planeX, tolerance=None):
                                rs.ObjectColor( crv, [0,200,0]) 
                                rs.DeleteObject( crv )
                    if 1:
                        joined=[]
                        rs.ObjectName( rs.ObjectsByName("booled"), "reliefCrv")
                        if len(rs.ObjectsByName("reliefCrv")) > 1:
                            joined = rs.JoinCurves(rs.ObjectsByName("reliefCrv"), delete_input=1)
                            rs.ObjectName( joined, "joined" )
                        else: rs.ObjectName( rs.ObjectsByName("reliefCrv"), "joined" )
                        rs.DeleteObject( fullRelief )
                        lenx = radius*2*3.1415
                        if 1:
                            for crv in joined:
                                pass
                                if rs.CurveLength( crv ) < lenx*0.1:
                                    rs.ObjectColor( crv, [100,200,200])
                                if rs.CurveLength( crv ) < 20.0:
                                    rs.ObjectColor( crv, [100,200,100])
                rs.Redraw()
    rs.CurrentLayer("UNO::relief")
    rs.UnitAbsoluteTolerance( 0.0001 )
    rs.DeleteObject( lenXcrv )
    rs.Command("cplane W T", 0)
#USAge:
#spine = crv1
#dm2.makeRelief(spine, dir="len",  num=11*6, startRad = 8, endRad=8, verbose=0 )    
#dm2.makeRelief(spine, dir="dep",  num= 3*6, startRad = 4, endRad=8, verbose=0 )    
#dm2.makeRelief(spine, dir="hig",  num=10*6, startRad = 8, endRad=10, verbose=0 )    



################
######## functions 4duerer
################

def getLodge( p_width=1.2, l_dist=10, d_dist=8, h_dist=6, pos_x=0, pos_y=0, d_grid=0, d_distord=1, demo=0, verbose=100 ) :
    """
    Generate a small archetypal house, distorted along perspective algorithms
    A setup for the development of individual panels
    Inspired by
      Albrecht Duerer's "Underweysung" (1525)
      https://de.wikipedia.org/wiki/Perspektive#Geschichte
      https://en.wikipedia.org/wiki/Albrecht_Duerer
    And
      MVRDVs "Porterlodges for the National Park De Hoge Veluwe" (1996)
      https://mvrdv.com/projects/167/hoenderloo-lodge?photo=15877
      https://www.miesarch.com/work/2994
    Parameters:
      p_width (float, optional): Approx. panel width in units
      l_dist (float, optional): Approx. length of the lodge in units
      d_dist (float, optional): Approx. depth of the lodge in units
      h_dist (float, optional): Approx. height of the lodge in units
      x_pos (float, optional): Move origin of the lodge in x
      y_pos (float, optional): Move origin of the lodge in y
      d_grid (boolean, optional): Fixed depth grid on the the small sides
      d_distord (boolean, optional): Distord basic section of the house
      demo (boolean, optional): Run demo to get an object
      verbose (int, optional): Print and depict generation of the lodge
    Returns:
      list(float): list[][][] of all panels, containing groups of 4 points
      list(float): list[][][] of just the sleeve's panels
      list(float): list[][][] of just the right section's panels
      list(float): list[][][] of just the left section's panels
      list(float): list[][][] of the sections, containing groups of 5 points
      list(float): list[][] of all the cvs on the sleeve
      list(float): list[][] of all the cvs on the right section
      list(float): list[][] of all the cvs on the left section
    Example:
      import dm2_lib as dm2
      all_data = dm2.getLodge( verbose=1000, demo=1 )
      panels = all_data[0]
      panels_sleeve = all_data[1]
      panels_right = all_data[2]
      panels_left = all_data[3]
      sections = all_data[4]
      cvs_sleeve= all_data[5]
      cvs_right= all_data[6]
      cvs_left= all_data[7]
    """
    print "^^^ generating a LODGE"
    if verbose==0 : rs.EnableRedraw( 0 )
    if verbose:
        rs.ObjectColor( rs.AddCurve( [[0,0,0], [pos_x, pos_y, 0]] ), [200,0,200] )
        #rs.ZoomExtents()
    ######## focal point
    focus = [ 
        (-1)**random.randint(0,1) * random.uniform( l_dist*4, l_dist*6 )
        , random.uniform( -d_dist*2, d_dist*2 )
        , 0 
        ]
    ######## planes to project on
    plane0 = rs.PlaneFromNormal(
        [ random.uniform(l_dist/2,l_dist/3), 0, 0 ]
        , [ 3, random.uniform(-1,1), random.uniform(-1,1) ]
        )
    plane1 = rs.PlaneFromNormal(
        [ -random.uniform(l_dist/2,l_dist/3), 0, 0 ]
        , [ 3, random.uniform(-1,1), random.uniform(-1,1) ]
        )

    ######## standard section
    section0 = []
    section1 = []
    if d_distord :
        a = [ 0, random.uniform(-d_dist/2,-d_dist/3), 0 ]
        b = [ 0, random.uniform(-d_dist/2,-d_dist/3), random.uniform(h_dist/3,h_dist/2) ]
        c = [ 0, random.uniform(-d_dist/6,d_dist/6), random.uniform(h_dist/2,h_dist) ]
        d = [ 0, random.uniform(d_dist/3,d_dist/2), random.uniform(h_dist/3,h_dist/2) ]
        e = [ 0, random.uniform(d_dist/3,d_dist/2), 0 ]
    else :
        a = [ 0, -d_dist/2, 0 ]
        b = [ 0, -d_dist/2, random.uniform(h_dist/3,h_dist/2) ]
        c = [ 0, 0, random.uniform(h_dist/2,h_dist) ]
        d = [ 0, d_dist/2, random.uniform(h_dist/3,h_dist/2) ]
        e = [ 0, d_dist/2, 0 ]
    section = [ a, b, c, d, e ]
    section_id = rs.AddCurve( section, 1 );
    if verbose : rs.Sleep( verbose )
    ######## get all the cvs alongside (sleeve)
    cvs_sleeve = []
    subdiv_l = int( rs.Distance(plane0[0],plane1[0]) / p_width )
    if verbose : print "the long sides / the sleeve will be separated in", subdiv_l, "segments."

    for pnt in section :
        ######## optic rays
        vec = rs.VectorSubtract( pnt, focus )
        end = rs.VectorAdd( pnt, vec )
        crv_id = rs.AddLine( focus, end )
        ######## projected on the planes
        pierce0 = rs.PlaneCurveIntersection( plane0, crv_id )[0][1]
        pierce1 = rs.PlaneCurveIntersection( plane1, crv_id )[0][1]
        section0.append( pierce0 )
        section1.append( pierce1 )
        #if verbose : rs.ZoomExtents()
        if verbose :
            foc_id = rs.AddPoint( focus )
            pnt_id = rs.AddPoint( pnt )
            ##rs.AddCircle( plane0, max(d_dist,l_dist,h_dist) )
            ##rs.AddCircle( plane1, max(d_dist,l_dist,h_dist) )
            section0_ids = rs.AddPoints( section0 )
            section1_ids = rs.AddPoints( section1 )
            rs.Sleep( verbose )
            rs.DeleteObjects( section0_ids )
            rs.DeleteObjects( section1_ids )
            rs.DeleteObject( foc_id )
            rs.DeleteObject( pnt_id )
            #rs.ZoomExtents() ###
        #if verbose : rs.ZoomExtents() ###
        rs.DeleteObject( crv_id )
        ######## subdivide the edges alongside (sleeve)
        for s in range(subdiv_l+1):
            fac = float(s) / subdiv_l
            coord = pntInbetween( pierce0, pierce1, fac )
            cvs_sleeve.append( coord )
    #if verbose : rs.ZoomExtents() ###
    sections = [ section0, section1 ]
    ######## get the sections alongside (sleeve)
    sections = []
    for u in range( subdiv_l+1 ) :
        pnts = []
        for v in range( 5 ) :
            pnts.append( cvs_sleeve[(v+0)*(subdiv_l+1)+(u+0)] )
        sections.append( pnts )
    ######## get the panels alongside (sleeve)
    panels_sleeve = []
    for u in range( subdiv_l ) :
        for v in range( 5-1 ) :
            pnt0 = cvs_sleeve[ (v+0)*(subdiv_l+1)+(u+0) ]
            pnt1 = cvs_sleeve[ (v+0)*(subdiv_l+1)+(u+1) ]
            pnt2 = cvs_sleeve[ (v+1)*(subdiv_l+1)+(u+1) ]
            pnt3 = cvs_sleeve[ (v+1)*(subdiv_l+1)+(u+0) ]
            panel = [ pnt0, pnt1, pnt2, pnt3 ]
            panels_sleeve.append( panel )
    ######## general subdivision for the sections
    subdiv_d = int(round( rs.Distance(a,e) / p_width / 2 )) * 2
    ######## end section right cvs
    cvs_right = []
    subdiv_d0 = int( rs.Distance(section0[0],section0[4]) / p_width )
    fac_d0a = rs.Distance(section0[1],section0[2])/(rs.Distance(section0[1],section0[2])+rs.Distance(section0[3],section0[2]))
    subdiv_d0a = int(round( subdiv_d0 * fac_d0a ))
    subdiv_d0b = subdiv_d0 - subdiv_d0a
    if d_grid :
        subdiv_d0 = subdiv_d
        subdiv_d0a = int( subdiv_d/2 )
        subdiv_d0b = int( subdiv_d/2 )
    if verbose : print "the section on the right is devided in", subdiv_d0a, "and", subdiv_d0b, "panels."
    for p in range(subdiv_d0+1) :
        fac = float(p) / subdiv_d0
        coord = pntInbetween( section0[4], section0[0], fac )
        cvs_right.append( coord )
    for p in range(subdiv_d0+1) :
        if ( p<subdiv_d0b ) :
            fac = float(p) / subdiv_d0b
            coord = pntInbetween( section0[3], section0[2], fac )
            cvs_right.append( coord )
        else :
            fac = (float(p)-subdiv_d0b) / subdiv_d0a
            coord = pntInbetween( section0[2], section0[1], fac )
            cvs_right.append( coord )
    ######## get the panels on end section right
    panels_right = []
    for p in range(subdiv_d0) :
        pnt0 = cvs_right[ (p+0) ]
        pnt1 = cvs_right[ (p+1) ]
        pnt2 = cvs_right[ (p+1)+(subdiv_d0+1) ]
        pnt3 = cvs_right[ (p+0)+(subdiv_d0+1) ]
        panel = [ pnt0, pnt1, pnt2, pnt3 ]
        panels_right.append( panel )
    ######## end section left cvs
    cvs_left = []
    subdiv_d1 = int( rs.Distance(section1[0],section1[4]) / p_width )
    fac_d1a = rs.Distance(section1[3],section1[2])/(rs.Distance(section1[1],section1[2])+rs.Distance(section1[3],section1[2]))
    subdiv_d1a = int(round( subdiv_d1 * fac_d1a ))
    subdiv_d1b = subdiv_d1 - subdiv_d1a
    if d_grid :
        subdiv_d1 = subdiv_d
        subdiv_d1a = int( subdiv_d/2 )
        subdiv_d1b = int( subdiv_d/2 )
    if verbose : print "the section on the other end is split in", subdiv_d1a, "and", subdiv_d1b, "panels."
    for p in range(subdiv_d1+1) :
        fac = float(p) / subdiv_d1
        coord = pntInbetween( section1[0], section1[4], fac )
        cvs_left.append( coord )
    for p in range(subdiv_d1+1) :
        if ( p<subdiv_d1b ) :
            fac = float(p) / subdiv_d1b
            coord = pntInbetween( section1[1], section1[2], fac )
            cvs_left.append( coord )
        else :
            fac = (float(p)-subdiv_d1b) / subdiv_d1a
            coord = pntInbetween( section1[2], section1[3], fac )
            cvs_left.append( coord )
    ######## get the panels on end section right
    panels_left = []
    for p in range(subdiv_d1) :
        pnt0 = cvs_left[ (p+0) ]
        pnt1 = cvs_left[ (p+1) ]
        pnt2 = cvs_left[ (p+1)+(subdiv_d1+1) ]
        pnt3 = cvs_left[ (p+0)+(subdiv_d1+1) ]
        panel = [ pnt0, pnt1, pnt2, pnt3 ]
        panels_left.append( panel )
    ######## all the panels
    panels = []
    panels.extend( panels_sleeve )
    panels.extend( panels_right )
    panels.extend( panels_left )
    ######## display features
    section0_id = rs.AddCurve( section0, 1 );
    section1_id = rs.AddCurve( section1, 1 );
    
    #if verbose : rs.ZoomExtents() ###
    rs.ObjectColor( rs.AllObjects()[:2], [100,200,100])
    rs.DeleteObject( section_id )
    if verbose : 
        rs.Sleep( verbose )
        cvs_ids = rs.AddPoints( cvs_sleeve )
        rs.Sleep( verbose*1 ) ## was *2 ag
        rs.DeleteObjects( cvs_ids )
        cvs_ids = rs.AddPoints( cvs_right )
        rs.Sleep( verbose*1 ) ## was *2 ag
        rs.DeleteObjects( cvs_ids )
        cvs_ids = rs.AddPoints( cvs_left )
        rs.Sleep( verbose*1 ) ## was *2 ag
        rs.DeleteObjects( cvs_ids )
    rs.DeleteObjects( [section0_id,section1_id] )
    ######## move lodge, if desired
    if pos_x or pos_y:
        movVec = [pos_x, pos_y, 0]
        if verbose :
            print "new origin position =", movVec
            rs.ObjectColor(rs.AddCurve( [[0,0,0],movVec] ), [200,0,200]) 
        for i,panel in enumerate(panels):        panels[i]        = [ rs.VectorAdd(cor, movVec) for cor in panel ]
        for i,panel in enumerate(panels_sleeve): panels_sleeve[i] = [ rs.VectorAdd(cor, movVec) for cor in panel ]
        for i,panel in enumerate(panels_right):  panels_right[i]  = [ rs.VectorAdd(cor, movVec) for cor in panel ]
        for i,panel in enumerate(panels_left):   panels_left[i]   = [ rs.VectorAdd(cor, movVec) for cor in panel ]
        for i,section in enumerate(sections):    sections[i]      = [ rs.VectorAdd(cor, movVec) for cor in section ]
        cvs_sleeve = [rs.VectorAdd(crv, movVec) for crv in cvs_sleeve]
        cvs_right  = [rs.VectorAdd(crv, movVec) for crv in cvs_right]
        cvs_left   = [rs.VectorAdd(crv, movVec) for crv in cvs_left]
    ######## depict demo
    if demo :
        ######## the sections
        if 1 :
            for section in sections :
                rs.AddCurve( section, 1 )
                rs.Sleep( verbose/10 )
        ######## default panels
        if 1 :
            for panel in panels :
                rs.AddCurve( panel, 1 )
                new_order = [ panel[2],panel[0],panel[3],panel[1] ]
                rs.AddCurve( new_order, 1 )
                rs.Sleep( verbose/10 )
        ######## the cvs
        if 0 :
            rs.AddPoints( cvs_sleeve )
            rs.AddPoints( cvs_right )
            rs.AddPoints( cvs_left )
    else: # if not demo
        rs.AddCurve( sections[0], 1 )
        rs.AddCurve( sections[-1], 1 )
        rs.ObjectColor(rs.AllObjects()[:2], [160,0,160])
        #rs.ZoomExtents()
    if verbose==0 : rs.EnableRedraw( 1 )
    ######## return values
    return [ panels, panels_sleeve, panels_right, panels_left, sections, cvs_sleeve, cvs_right, cvs_left ]



################
######## functions 4giza & ra
################

######## generate the pyramids @ giza / egypt / africa
def makePyramid (NameOrNumber=2, SrfsOrCrvs=0, verbose = 0):
    rs.UnitSystem(4) # meters
    rs.CurrentLayer("Default")
    rs.LayerLocked ("OSM", 1)
    if verbose: rs.Redraw()
    for p, pyra in enumerate(pyramids):
        if type(NameOrNumber)==int and p==NameOrNumber:# or pyramids[i][0] == str(NameOrNumber):
            break
        if type(NameOrNumber)==str and pyra[0]==NameOrNumber:
            break
    print "pyramids["+str(p)+"][0]", pyramids[p][0]
    pyraNam    = pyramids[p][0]
    height     = pyramids[p][1]
    osmID      = pyramids[p][2]
    baseCrv = rs.ObjectsByName("_bldg3D_crv_"+osmID)
    if not baseCrv: baseCrv = rs.ObjectsByName("Wcrv_"+osmID)
    baseCrv = baseCrv[0]        # ObjectsByName() always returns list !
    baseCoords = rs.CurveEditPoints( baseCrv )[0:4]
    #dm2.textDots( baseCoords )
    cen = pntCentroid( baseCoords )
    top = rs.VectorAdd( cen, [0, 0, height] )
    #rs.AddPoint( center )
    #rs.AddCurve( [center, top] )
    #########################################################
    # sort baseCoords radially - so that face_0 facing south:
    baseCoords = [ cor[1] for cor in sorted( [ [rs.Angle(cen, cor)[0], cor] for cor in baseCoords ] )]
    if len(pyra)==3:
        pyra.append(top)
        pyra.append(baseCoords)
    else:
        pyra[3]=top
        pyra[4]=baseCoords
    #########################################################
    if 1:
        rs.CurrentLayer("GIZA::pyramids")
        if not rs.ObjectsByName(pyraNam+"_base"):
            rs.ObjectName(rs.AddCurve( baseCoords, 1), pyraNam+"_base" )
        for i in range(4):
            p0 = baseCoords[i]                      # some rocket science :
            p1 = baseCoords[i + 1 - 4*(i==3)]       # need last + first pnt of baseCoords
            if SrfsOrCrvs==0: obj = rs.AddSrfPt( [p0, p1, top] )  # surface - or..
            else: obj = rs.AddCurve( [p0, p1, top], 1 )         # .. just curves
            rs.ObjectName( obj, pyraNam+"_face_"+str(i) )# name it for later adressing


######################### 4 pyramids mit_ohne OSM
########## action directe / 2020 12 15 / diag
rs.EnableRedraw(0)
pyras=[
["cheops", 146.6, 4420397, [1248.52044692,1177.13508851,146.6],
[[1119.11710484,1044.36437918,0.0],[1378.68076153,1045.09689965,0.0],[1377.91265704,1309.92508270,0.0],[1118.37126425,1309.15399252,0.0]]],
["chefren", 143.5, 4420396, [863.452413325,765.592578692,143.5],
[[739.094627173,642.396896715,0.0],[988.160855873,642.743869166,0.0],[987.804633503,888.788264014,0.0],[738.749536751,888.441284875,0.0]]],
["mykerinos", 65.0, 4420398, [592.158465300,320.622683574,65.0],
[[534.010729284,264.613746413,0.0],[650.128090131,264.420989649,0.0],[650.306201316,376.631619887,0.0],[534.188840470,376.824378347,0.0]]],
["henutsen", 29.6, 219797726, [1472.76242917,1010.17695143,29.6],
[[1446.28508828,984.182182777,0.0],[1498.62751285,983.578177545,0.0],[1499.23977005,1036.16529323,0.0],[1446.89734548,1036.78215218,0.0]]],
["meritetis", 30.0, 219797724, [1472.74294826,1069.51108927,30.0],
[[1446.34074803,1042.51380133,0.0],[1498.47166557,1041.87123964,0.0],[1499.13958251,1096.51480147,0.0],[1447.01979692,1097.14451462,0.0]]],
["hetepheres", 30.25, 198032492, [1471.22622020,1137.33379761,30.25],
[[1446.04018540,1111.85924919,0.0],[1496.12282431,1111.57652051,0.0],[1496.41225499,1162.80191979,0.0],[1446.32961608,1163.09750096,0.0]]],
["khentkawes", 18.5, 73174154, [1392.15876887,434.391845831,18.5],
[[1369.09615337,407.048940709,0.0],[1420.91537633,413.114422728,0.0],[1415.21581840,461.741187826,0.0],[1363.40772739,455.662832060,0.0]]],
["queen_A", 21.2, 25416060, [588.713127060,209.858105857,21.2],
[[570.234091589,190.903771808,0.0],[607.047447194,190.903771808,0.0],[607.047447194,228.812439906,0.0],[570.523522264,228.812439906,0.0]]],
["queen_B", 21.2, 25416067, [534.712042076,207.590007688,21.2],
[[519.650514972,191.212180857,0.0],[549.628853842,191.083677085,0.0],[549.762437231,223.967834353,0.0],[519.806362259,224.096338458,0.0]]],
["queen_C", 21.2, 25416093, [482.467022060,206.526636076,21.2],
[[468.554868698,191.263582365,0.0],[496.573984530,191.456338026,0.0],[496.373609447,221.783264813,0.0],[468.365625564,221.603359102,0.0]]]
]

#pyras = pyramids[:]
pyramids = pyras
#########################################
############### make pyramid mit_ohne OSM / 2020 12 15 / diag
def makePyramid (NameOrNumber=2, SrfsOrCrvs=0, verbose = 0):
    pyramids = pyras
    rs.UnitSystem(4) # meters
    if "GIZA::pyramids" not in rs.LayerNames():
        newEmptyLayer( "GIZA::pyramids", [240,230,100] )
    if verbose: rs.Redraw()
    for p, pyra in enumerate(pyramids):
        if type(NameOrNumber)==int and p==NameOrNumber:break# or pyramids[i][0] == str(NameOrNumber):
        if type(NameOrNumber)==str and pyra[0]==NameOrNumber:break
    if verbose: print "pyramids["+str(p)+"] :", pyramids[p][0]
    pyraNam     = pyramids[p][0]
    top         = pyramids[p][3]
    baseCoords  = pyramids[p][4]
    ############################

    rs.CurrentLayer("GIZA::pyramids")
    rs.DeleteObjects(rs.ObjectsByName(pyraNam+"_face_*"))
    rs.DeleteObjects(rs.ObjectsByName(pyraNam+"_base"))
    rs.ObjectName(rs.AddCurve( baseCoords, 1), pyraNam+"_base" )
    if verbose: rs.Redraw()
    for i in range(4):
        p0 = baseCoords[i]                      # some rocket science :
        p1 = baseCoords[i + 1 - 4*(i==3)]       # need last + first pnt of baseCoords
        if SrfsOrCrvs==0: obj = rs.AddSrfPt( [p0, p1, top] )  # surface - or..
        else: obj = rs.AddCurve( [p0, p1, top], 1 )           # .. just curves
        rs.ObjectName( obj, pyraNam+"_face_"+str(i) )         # name it for later adressing
        if verbose: rs.Redraw()
    if verbose: rs.Redraw()
    pyramids = pyras
    rs.CurrentLayer("Default")


################
######## functions for interaction
################

######## break if you need to
def esc( ):
    if _host.EscapePressed(0): raise Exception('***ESCape*Key*Pressed***')



################
######## text and display functions
################

######## adding leading zeros
def textPre0( val, sign="0", sollLen=1 ):
    # eng leading zero
    anz = sollLen-len(str(val))
    if anz>0:# and val < pow(10, anz):
        for i in range(anz): val = sign+str(val)
    return str(val)

######## adding leading zeros
def textDots(coordList, strX=""):
    state = rs.EnableRedraw(0)
    if len(coordList):
        for i, pt in enumerate(coordList):
            rs.AddTextDot(str(i)+strX, pt)
    else:
        print "***________no list > no textDots"
    rs.EnableRedraw(state)



################
######## timing functions
################

######## timing variables
global timeX
timeX = time.time()

######## set time
def timeSet():
    global timeX
    timeX = time.time()

######## get time
def timeGet(verbose=0, prenull=0):
    global timeX
    tim = float(time.time())
    tim -=  float(timeX)
    if verbose: print str(round(tim,2))+"s"
    return round(tim,2)

######## transpose seconds to minutes
def timeSec2Min( secs ):
    min = int(secs/60.0)
    sec = int(secs-min*60)
    if min > 59:
        hor = int(min/60.0)
        min = int(min-hor*60)
        return textPre0(hor,1)+":"+textPre0(min,1)+":"+textPre0(sec,1)+" "
    min = textPre0(min,1)
    sec = textPre0(sec,1)
    return textPre0(min,1)+"min"+textPre0(sec,1)+"s"



################
######## date/time/location- and osm-related functions
################

def ortX(ortX):
    ort = "guinea"
    lat = 0#
    lon = 0#
    timeZone = 0#
    ### graz
    if ortX == "graz": 
        ort = "graz"
        lat = 47.0654 #=kronesgasse / opernring 47.07086780
        lon = 15.4486 #                         15.43827860
        timeZone = 1
    
    if ortX == "kollerweg":
        ort = "kollerweg"
        lat = 47.130380844984266 # lt google maps
        lon = 15.518638635469191 
        timeZone = 1
    ### NYC, UN headquaters
    if ortX == "NYC UN": 
        lat = 40.7492161
        lon = -73.96867250
        timeZone = -5
    ### stonehenge, UK
    if ortX == "stonehenge": 
        lat = 51.178889
        lon = -1.826111
        timeZone = 0
    ### gizeh, egypt
    if ortX == "giza": ### cairo 30 2 N .. 31 14 E
        ort == "giza"
        lat = 31.1241000
        lon = 29.9694000
        timeZone = 2
    if ortX == "koenigsberg": 
        ort == "koenigsberg"
        lat = 54.6969000
        lon = 20.4943000
        timeZone = 2
    if ortX == "shepperton": 
        ort == "shepperton"
        lat = 51.3928000
        lon = -0.4964000
        timeZone = 0
    return [lat, lon, timeZone]

def daysInMonth(year):
    return [31, 28+(int(year)%4==0), 31,30,31,30,31,31,30,31,30,31]

def number2date( number=31, year=2020):
    months = daysInMonth(year)
    for i in range(0, 11):
        if number <= months[i]:
            return [i+1, number]
        number -= months[i]
        if number <= months[i+1]:
            return [i+2, number]
#print number2date( number=32+28, year=2020)
def date2number( year=2020, mon=12, day=30, verbose=0 ):
    months = daysInMonth(year)
    if day > daysInMonth(year)[int(mon)-1]:
        if verbose: print "*** ________no good date: date2number("+str(year)+(", ")+str(mon)+", "+str(day)+") | return =",
        return 0
    number = 0
    for m in range(1, int(mon)): number += months[m-1]
    return number+int(day)
#print date2number(year=2020, mon=2, day=31)
def date2number( year=2020, mon=12, day=30, verbose=0 ): # diag 20 12 18 21:00
    if type(year)==list:
        return date2number( year[0], year[1], year[2], verbose=0 )
    months = daysInMonth(year)
    if day > daysInMonth(year)[int(mon)-1]:
        if verbose: print "*** ________no good date: date2number("+str(year)+(", ")+str(mon)+", "+str(day)+") | return =",
        return 0
    number = 0
    for m in range(1, int(mon)): number += months[m-1]
    return number+int(day)
#print date2number(year=2020, mon=2, day=31)

def getDateNow():
    now = datetime.now()
    #print "day :", type(now.day), now.day
    return [now.year, now.month, now.day, now.hour, now.minute, now.second]

_2day = getDateNow()
dayNumber2day = date2number(_2day[0], _2day[1], _2day[2])


dlSaving=0 # sommerzeit o.a.
dat = getDateNow()
ort = "graz" # default
ort = "giza" # default
ort = "koenigsberg" # default

def setSun ( year=dat[0], mon=dat[1], day=dat[2], hour=dat[3], min=dat[4], sec=dat[5], verbose=0):
    sun = sc.doc.Lights.Sun
    sun.Enabled = 1
    sun.TimeZone = ortX(ort)[2]
    sun.DaylightSavingMinutes = dlSaving
    if day <= daysInMonth(year)[mon-1]:
        sun.SetPosition(System.DateTime(year, mon, day, hour, min, sec), ortX(ort)[0],ortX(ort)[1])
        if verbose:
            print "*** sonnenstand am", year, mon, day, "(tag "+str(date2number(year,mon,day))+")","um", str(hour)+":"+str(min)+":"+str(sec)+" in "+ort.upper()+" @ lat =",ortX(ort)[0], "/ lon =", ortX(ort)[1], "/ timeZone =", ortX(ort)[2]#,":"
            print "*** [ azimut", round(sun.Azimuth,2), " / altitude",round(sun.Altitude,2),"/ sunVector [", sun.Vector, "] ]"
        return [ sun.Azimuth, sun.Altitude, [sun.Vector[0],sun.Vector[1],sun.Vector[2]] ]
    else:
        print "*** ________no good date: setSun("+str(year)+(", ")+str(mon)+", "+str(day)+") | return =",
        return [0,0,[0,0,0]]



################
######## delete functions
################

######## delete selected
def eS() :
    rs.DeleteObjects( rs.SelectedObjects() )

######## delete visible
def eV() :
    rs.SelectObjects( rs.AllObjects() )
    eS()

######## erase all
def eA() :
    rs.DeleteObjects( rs.AllObjects() )

######## delete AbsolutelyAll
def eAA():
    """Deletes Absolutely All objects, incl hidden and locked
    """
    rs.UnlockObjects(rs.AllObjects())
    rs.ShowObjects  (rs.AllObjects())
    eA()
    #print ("''' all objects deleted")



################
######## display functions
################

######## zoom all
def zA() :
    rs.ZoomExtents( all=1 )

######## zoom selected
def zS() :
    rs.ZoomSelected( all=1 )



################
######## math and array functions
################

######## very simple remapping of a value
def reMap(i, iMin, iMax, oMin, oMax):
    '''reMaps val i from in(min-max) 2 out(min-max)
    '''
    inFac  = float(i-iMin)/float(iMax-iMin)# 
    outFac = (oMax-oMin)
    return (oMin + outFac*inFac)

######## list mixxing
######## new: return list 2020 12 15 / diag
def permutate( list, num):
    return [ perm for perm in permutations(list, num) ]
    
def combinate( list, num):
    return [ comb for comb in combinations(list, num) ]


################
######## basic point and vector functions
################

######## get a point between two points
def pntInbetween( coord0, coord1, fac=.5 ) :
    vec = rs.VectorSubtract( coord1, coord0 )
    vec = rs.VectorScale( vec, fac )
    coord = rs.VectorAdd( coord0, vec )
    return coord

######## get a point between two points
def pntCentroid( coords ) :
    x_sum = 0
    y_sum = 0
    z_sum = 0
    for coord in coords :
        x_sum += coord[ 0 ]
        y_sum += coord[ 1 ]
        z_sum += coord[ 2 ]
    num = len( coords )
    x = x_sum / num
    y = y_sum / num
    z = z_sum / num
    coord = [ x, y, z ]
    return coord

######## sort a list of coordinates depending on their distance to one point
def pntsSortDistancePnt( origin, coords ) :
    dists = []
    for coord in coords :
        dist = rs.Distance( origin, coord )
        dists.append( abs(dist) )
    zipped_lists = zip( *sorted( zip(dists,coords) ) )
    return zipped_lists[1]

######## sort a list of coordinates depending on their distance to one plane
def pntsSortDistancePln( plane, coords ) :
    dists = []
    for coord in coords :
        dist = rs.DistanceToPlane( plane, coord )
        dists.append( abs(dist) )
    zipped_lists = zip( *sorted( zip(dists,coords) ) )
    return zipped_lists[1]



################
######## point and vector functions for curves
################

######## perpendicular frame with normalized parameters
def plnCurvePerp( crv, crv_parameter=0.5 ) :
    crv_parameter = rs.CurveParameter( crv, crv_parameter )
    pln = rs.CurvePerpFrame( crv, crv_parameter )
    return pln

######## perpendicular distance ("normalabstand") point..curve
def pntCurveDist( pnt, crv  ):
#    para = rs.CurveClosestPoint(crv, pnt)
#    poin = rs.EvaluateCurve(crv, param)
#    dist = rs.Distance(pnt, poin)
    return rs.Distance(pnt, rs.EvaluateCurve(crv, rs.CurveClosestPoint(crv, pnt)))

######## perpendicular distance ("normalabstand") point..curve
def pntCurveClosest( pnt, crv  ):
#    para = rs.CurveClosestPoint(crv, pnt)
     return rs.EvaluateCurve(crv, rs.CurveClosestPoint(crv, pnt))

######## origin of the perpendicular frame
def pntCurvePerp( crv, crv_parameter=0.5 ) :
    prepframe = plnCurvePerp( crv, crv_parameter )
    pnt = prepframe[0]
    return pnt

######## axis of the perpendicular frame
def vecCurvePerpX( crv, crv_parameter=0.5 ) :
    prepframe = plnCurvePerp( crv, crv_parameter )
    vec = rs.VectorUnitize( prepframe[1] )
    return vec
def vecCurvePerpY( crv, crv_parameter=0.5 ) :
    prepframe = plnCurvePerp( crv, crv_parameter )
    vec = rs.VectorUnitize( prepframe[2] )
    return vec
def vecCurvePerpZ( crv, crv_parameter=0.5 ) :
    prepframe = plnCurvePerp( crv, crv_parameter )
    vec = rs.VectorUnitize( prepframe[3] )
    return vec

######## projection of the curve direction onto a plane
def vecCurvePerpNormal( crv, crv_parameter=0.5, nor=[1,1,1] ) :
    prepframe = plnCurvePerp( crv, crv_parameter )
    dir = rs.VectorUnitize( prepframe[3] )
    vec = rs.VectorCrossProduct( dir, nor )
    vec = rs.VectorRotate( vec, 90, nor )
    vec = rs.VectorUnitize( vec )
    return vec

######## projections of the curve direction onto default planes
def vecCurvePerpXY( crv, crv_parameter=0.5 ) :
    vec = vecCurvePerpNormal( crv, crv_parameter, [0,0,1] )
    return vec
def vecCurvePerpXZ( crv, crv_parameter=0.5 ) :
    vec = vecCurvePerpNormal( crv, crv_parameter, [0,1,0] )
    return vec
def vecCurvePerpYZ( crv, crv_parameter=0.5 ) :
    vec = vecCurvePerpNormal( crv, crv_parameter, [1,0,0] )
    return vec

### new 2020 12 15 / diag
def pnt2str( pnt ): # [x,y,z] > "x,y,z" | useful at rs.command(..)
    return str(pnt[0])+","+str(pnt[1])+","+str(pnt[2])

def pnt2XY0( pnt ): # [x,y,z] > [x,y,0]
    return [pnt[0],pnt[1],0]

def pnt2cor( pnt ): # [<Rhino.Geometry.Point3d object at 0x0000000000000104 [x,y,z]>] > [x,y,z]
    return [ val for val in pnt ]



################
######## layer and material functions
################

######## set up an empty new layer in rhino
def newEmptyLayer( lay, color=[127,127,127], parent="", transe=0.0, gloss=0.0, refl=0.0 ):
    #rs.CurrentLayer( "Default")
    layX = lay
    if parent: layX = parent+"::"+lay
    rs.AddLayer( lay, color, parent=parent )
    if rs.IsLayer( layX ) :
        rs.ShowObjects( rs.ObjectsByLayer( layX ) )
        rs.DeleteObjects( rs.ObjectsByLayer( layX ) )
        #rs.PurgeLayer( layX )
    rs.LayerColor(layX, color)
    rgbMat2Lay( layX, *color, T=transe, Gloss=gloss, Refl=refl, matNam=layX+"_layMat" )
    rs.CurrentLayer( lay )

######## assign a material to an object 
def rgbMat2Obj(obj_id = "", R=127, G=127, B=127, T=0.0, Gloss=0, Refl=0.0, matNam="none"):
    """ Adds Material to Objects.
    Parameters:
      obj_id = Guid of Geometry in RhinoDoc
      Red[opt] = 0-255
      Green[opt] = 0-255
      Blue[opt] = 0-255
      Transparency[opt] = 0.0 - 1.0, 1.0 being transparent
      Glossiness[opt] = 0.0 - 255.0, 255.0 being glossy
      Reflectivity[opt] = 0.0 - 1.0, 1.0 being fully reflectant
      matName[opt] = Materialname as String
    Returns:
      Material index
    """
    if obj_id: index = rs.AddMaterialToObject(obj_id)
    else: index = sc.doc.Materials.Add()
    R=int(R)
    G=int(G)
    B=int(B)
    rs.MaterialColor( index, (R, G, B) )
    rs.MaterialTransparency( index, T-0.000001 ) # T 0.0..1.0
    rs.MaterialShine( index, Gloss )             # Gloss 0.0..255.0
    #rs.MaterialReflectiveColor( index, (191, 191, 255) )
    newMat = sc.doc.Materials[index]
    newMat.Reflectivity=Refl
    sc.doc.Materials.Modify(newMat,index,1)
    if matNam == "none": matNam = "mat_%s_%s_%s_%s_ind_%s" % (R, G, B, int(T*100), index)
    #print "***", matNam#, #" .. created (ind", index, ")"
    rs.MaterialName (index, matNam)
    return index

######## assign a material to a layer 
def rgbMat2Lay(lay_nam = "", R=127, G=127, B=127, T=0.0, Gloss=0.0, Refl=0.0, matNam="none"):
    """ Adds Material to LAYER.
    Parameters:
      lay_nam = layerName
      Red[opt] = 0-255
      Green[opt] = 0-255
      Blue[opt] = 0-255
      Transparency[opt] = 0.0 - 1.0, 1.0 being transparent
      Glossiness[opt] = 0.0 - 1.0, 1.0 being glossy
      Reflectivity[opt] = 0.0 - 1.0, 1.0 being fully reflectant
      matName[opt] = Materialname as String
    Returns:
      Material index
    """
    if lay_nam: index = rs.AddMaterialToLayer(lay_nam)
    else: index = sc.doc.Materials.Add()
    rs.ResetMaterial(index)
    R=int(R)
    G=int(G)
    B=int(B)
    #rs.MaterialReflectiveColor( index, (191, 191, 255) )
    newMat = sc.doc.Materials[index]
    newMat.Reflectivity=Refl
    sc.doc.Materials.Modify(newMat, index, 1)
    if matNam == "none": matNam = "mat_%s_%s_%s_%s_ind_%s" % (R, G, B, int(T*100), index)
    #print "***", matNam#, #" .. created (ind", index, ")"
    rs.MaterialColor( index, (R, G, B) )
    rs.MaterialTransparency( index, T-0.000001 ) # T 0.0..1.0
    rs.MaterialShine( index, Gloss*255 )             # Gloss 0.0..1.0
    rs.MaterialName (index, matNam)
    return index



################
######## basic library data and functions
################

######## feedback in status bar
print lib_cc
print "    sourced", datetime.now().strftime('%Y-%m-%d %H:%M:%S')
setSun(verbose=1)
schlafTage = date2number(2021,12,24) - dayNumber2day
print "btw : "+str(schlafTage)+" tage sinds noch bis weihnachten\'21 - und noch", schlafTage*8, "stunden schlaf :)"
