#######################
#-*- coding: utf-8 -*-


######## DM* ############# mini
######## agruber@tugraz.at
######## library #########

version = "   '''  ver 20251017 by _diag 4 DM* @ I OI III @ TUGraz ''' ver_03"



################
######## basic library data and functions
################

######## import
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import RhinoPython.Host as _host
import sys, os, platform
import System, System.DateTime

import datetime, time
import random, math

from itertools import combinations
from itertools import permutations
from itertools import product

rs.UnitAbsoluteTolerance(tolerance=0.00001, in_model_units=True)

pi = math.pi



################
######## delete functions
################

######## delete Selected
def eS() :
    rs.DeleteObjects( rs.SelectedObjects() )

######## delete Visible
def eV() :
    rs.SelectObjects( rs.AllObjects() )
    eS()

######## delete All
def eA() :
    rs.DeleteObjects( rs.AllObjects() )
    rs.Redraw()

######## delete Absolutely All
def eAA():
    """Deletes Absolutely All objects, incl hidden and locked
    """
    rs.UnlockObjects(rs.AllObjects())
    rs.ShowObjects  (rs.AllObjects())
    eA()
    rs.Redraw()
    #print ("''' all objects deleted")

def eDup(verbose=0):
    selected = rs.SelectedObjects()
    rs.UnselectAllObjects()
    vorher = len(rs.AllObjects())
    rs.Command("_selDup", 0)
    if selected and rs.SelectedObjects():
        for obj in rs.SelectedObjects():
            if obj in selected: selected.remove( obj )
    rs.DeleteObjects( rs.SelectedObjects() )
    if selected: rs.SelectObjects(selected)
    if verbose: print "*** dm.eDup() deleted", vorher - len(rs.AllObjects()), "objects ***"
#eDup()



################
######## display functions
################

######## zoom all
def zA( proz=0.95 ) :
    rs.ZoomExtents( all=1 )
    rs.Command("-_zoom Factor "+str(proz)+" _enter", 0) ### diag 2021 11 07
    rs.Redraw()

######## zoom Selected
def zS() :
    rs.ZoomSelected( all=1 )


################
######## 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

def normVec3pnts( p0, p1,p2):
    return rs.VectorUnitize(rs.VectorCrossProduct( rs.VectorSubtract(p0,p1), rs.VectorSubtract(p0,p2) ))

### _diag 2021 11 13
######## get segmets+1 points between two points
######## similar 2 rs.DivideCurve(..)
def pntsInbetween( coord0, coord1, segments, create_points=0, create_line=0):
    '''
    return = coords
    '''
    coords = []
    vec = rs.VectorSubtract( coord1, coord0 )
    for i in range(segments+1):
        coords.append(rs.VectorAdd( coord0, rs.VectorScale(vec, float(i)/segments) ) )
        print i/segments
    if create_points: rs.AddPoints( coords )
    if create_line  : rs.AddLine( coord1, coord0 )
    print len(coords)
    return coords



def circumcircleOfTriangle(p0, p1, p2, verbose = 1):
    lineA = symmetryLine(p0, p1)
    lineB = symmetryLine(p1, p2)
    center= rs.LineLineIntersection(lineA, lineB)[0]
    if verbose:
        rs.AddCircle(center, rs.Distance(center,p0) )
    return [center, rs.Distance(center,p0)]

### diag 2022 12 11 / for delaunay_3D

def circumcircleOfTriangle(p0, p1, p2, verbose = 0):
    '''
    arguments:
        p0, p1, p2 .. 3 coords
        verbose 0/1 generate circle
    returns:
        list [center, radius]
    '''
    p2N = rs.LineClosestPoint([p0,p1], p2)
    p2Nvec = rs.VectorSubtract(p2, p2N)
    p0p1M = rs.VectorAdd( p0, rs.VectorScale( rs.VectorSubtract( p1, p0 ), .5 ) )
    p0p1N = rs.VectorAdd(p0p1M, rs.VectorScale(p2Nvec, 100000) )
    p0p1_N = rs.VectorAdd(p0p1M, rs.VectorScale(p2Nvec, -100000) )
    
    p1p2M = rs.VectorAdd( p1, rs.VectorScale( rs.VectorSubtract( p2, p1 ), .5 ) )
    p1p2N = rs.VectorAdd(p1p2M, rs.VectorScale(rs.VectorSubtract(p0, rs.LineClosestPoint([p1,p2], p0)), 100000)  )
    p1p2_N = rs.VectorAdd(p1p2M, rs.VectorScale(rs.VectorSubtract(p0, rs.LineClosestPoint([p1,p2], p0)), -100000)  )
    
    line01 = [p0p1_N, p0p1N]
    line02 = [p1p2_N, p1p2N]
    #rs.ObjectColor(rs.AddLine( p0p1M, p0p1N ), [0,200,0])
    #rs.ObjectColor(rs.AddLine( p1p2M, p1p2N ), [220,100,0])
    #print line01,"---",line02, "///",
    print rs.Distance(p0p1M, p0p1N),"---",  rs.Distance(p1p2M, p1p2N)
    center = rs.LineLineIntersection(line01, line02)[0]
    #rs.AddPoint( center )
    if 0 or verbose:
        rs.ObjectColor(rs.AddCurve( [center,p0,p1,p2,p0], 1), [100,200,100])
        pln = rs.PlaneFromPoints(center,p0,p1)
        rs.AddCircle(pln, rs.Distance(center,p0) )
    return [center, rs.Distance(center,p0)]
    

######## get a point in center/centroid/mitte von coords/points/pointcloud
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 li^st 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 list(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
### ?? fehler diag 2021 11 21 ??
def plnCurvePerp( crv, crv_parameter=0.5 ) :
    ###crv_parameter = rs.CurveParameter( crv, crv_parameter ) 
    #pln = rs.CurvePerpFrame( crv, crv_parameter )
    return rs.CurvePerpFrame( crv, crv_parameter )

######## 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..Line / _diag 2021 11 04
def pntLineDist( pnt, line):
    '''
    arguments:  pnt: [x,y,z]
               line: [point, point] 
       return: distance of nearest point on LINE from tst_pnt
    '''
    #line = [point0, point1]
    #poin = rs.LineClosestPoint(line, pnt)
    #dist = rs.Distance(pnt, poin)
    return rs.Distance(pnt, rs.LineClosestPoint(line, pnt))

######## perpendicular distance ("normalabstand") point..curve
def pntCurveClosest( pnt, crv  ):
    '''
    arguments: pnt: [x,y,z]
               crv: ID of curve
       return: pnt [x,y,z] on curve that is closest to pnt
    '''
    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=[pi,pi,pi] ) :
    prepframe = plnCurvePerp( crv, crv_parameter )
    dir = rs.VectorUnitize( prepframe[3] )
    vec = rs.VectorCrossProduct( dir, nor )
    ### vec = rs.VectorRotate( vec, 90, nor ) ### korr diag 2022 11 04
    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 pnt2XZ0( pnt ): # [x,y,z] > [x,y,0]
    return [pnt[0],0, pnt[2]]
def pnt2YZ0( pnt ): # [x,y,z] > [x,y,0]
    return [0, pnt[1],pnt[2]]

def pnt2cor( pnt ): # [<Rhino.Geometry.Point3d object at 0x0000000000000104 [x,y,z]>] or 'vector' etc > [x,y,z]
    return [ val for val in pnt ]

def pnts2cors( pnts ): # [<Rhino.Geometry.Point3d object at 0x0000000000000104 [x,y,z]>] or 'vector' etc > [x,y,z]
    return [ [pnt[0],pnt[1],pnt[2]] for pnt in pnts]

def cor2pnt( cor ): # [[x,y,z] convert to <Rhino.Geometry.Point3d object at 0x0000000000000104 [x,y,z]>])
    return rs.coerce3dpoint(cor)

def cPlane3pts( p0, p1, p2):
    p0 = pnt2str(p0) 
    p1 = pnt2str(p1) 
    p2 = pnt2str(p2)
    cmd = "cPlane 3Point "+p0+" "+p1+" "+p2+" enter"
    rs.Command(cmd, 0)

# cPlane3pts( [0,0,0], [0,0,1], [0,1,0] )

#########################
### new 2022 11 29 / diag

def pnts2XY0( coords ):
    return [ pnt2XY0(cor) for cor in coords]

#########################
### new 2022 12 08 / diag
coords=[]
def pntRemoveByDist(coords=coords, minDist=1.0, randomize=1, verbose=1):
    lenVorher = len(coords)
    for i in range(1001):
        if randomize:
            random.shuffle(coords)
        distList = sorted( [ [pair, rs.Distance(pair[0],pair[1])] for pair in combinate( coords, 2) ], key=lambda sortKey: (sortKey[1]) )
        if verbose: print i, "len(coords)", len(coords), "min ",distList[0][1]
        if distList[0][1] < minDist:
            coords.remove(distList[0][0][0] )
            #rs.AddCurve( distList[0][0] )
            #rs.AddPoint( distList[0][0][0] )
        else:
            print "XXX pntRemoveByDist done ",
            if 1 or verbose: print ": cnt =", i,  "len(coords) vorher/nachher "+str(lenVorher)+"/"+str(len(coords))+" - minDist", distList[0][1], "\nXXXXXXXXXXXXXXXXXXXXXXXX"
            break
    return coords

'''
USAge
anz=100
a=10
coords = [ [random.uniform(0,a),random.uniform(0,a),0] for i in range(anz) ]
#pnts = rs.AddPoints( coords )
coords = pntRemoveByDist(coords=coords, minDist=0.5, verbose=0)
'''
    
##########
# ConvHull
# worx @ xy_plane only
def pntConvHull(coordList, verbose=0):
    avg=pntCentroid(coordList)
    start = a = min(coordList)
    coords = [start]
    for i in range(1,10001):
        esc()
        o = a
        a = avg
        for b in coordList:
            if (a[0]-o[0])*(b[1]-o[1])-(a[1]-o[1])*(b[0]-o[0]) < 0:
                a = b
        coords.append(a)
        if a == start:
            break
    if a == start:# or i == 1000:
        if verbose: print "*** convHull: i=",i,": len convCoords=", len(coords), "(from "+str(len(coordList))+"coords)"

    return coords

### new 2022 12 09 ff / diag
#########################
def pntRandVec (a=-1, b=1, anzahl=1):
    return  [[random.uniform(a,b) for i in range(3) ] for j in range(anzahl)]

### new 2024 10 29 / diag

def randVec (a=-1, b=1):
    '''
        randVec (a=-1, b=1)
        Parameters:
            a: value von
            b: value bis
        Returns:
            list: [rnd(a,b), rnd(a,b), rnd(a,b)]
    '''
    return  [random.uniform(a,b) for i in range(3) ]

def pntRandCoords (a=-1, b=1, anzahl=100):
    return  [[random.uniform(a,b) for i in range(3) ] for j in range(anzahl)]

def getSurfacePoints( objID ): 
    rs.UnselectAllObjects()
    if rs.ObjectType(objID)==16 or rs.ObjectType(objID)==1073741824:
        rs.Command("_solidPtOn _selID "+str(objID)+" _enter _enter", 0)
        coords = rs.ObjectGripLocations( objID )
        rs.Command("_pointsOff _enter", 0)
    rs.UnselectAllObjects()
    if rs.ObjectType(objID)==8:
        rs.EnableObjectGrips(objID, 1)
        coords = rs.ObjectGripLocations( objID )
        rs.EnableObjectGrips(objID, 0)
    return coords ### danke, andi !

def setSurfacePoints( objID, coords ): 
    rs.UnselectAllObjects()
    if rs.ObjectType(objID)==16 or rs.ObjectType(objID)==1073741824:
        rs.Command("_solidPtOn _selID "+str(objID)+" _enter _enter", 0)
        rs.ObjectGripLocations( objID, coords )
        rs.Command("_pointsOff _enter", 0)
    rs.UnselectAllObjects()
    if rs.ObjectType(objID)==8:
        rs.EnableObjectGrips(objID, 1)
        rs.ObjectGripLocations( obj, coords )
        rs.EnableObjectGrips(objID, 0)



### DISPLAY  etc 
################

### experimental
def PointRadius(displayModeX=0, rad=3, styl=3,  verbose=0 ):
    '''
        arguments:
                displayModeX: int .. number of displayMode
                rad  = 3 : point radius
                styl = 3 : point style
                verbose : quasselig
                point style:
                    https://developer.rhino3d.com/api/rhinocommon/rhino.display.pointstyle
                    0 ControlPoint "square with center"
                    1 RoundControlPoint "round with center"
                    2 Simple "solid square"
                    3 RoundSimple "solid circle"
        Standard displayModes_numbers
        0 Wireframe
        1 Shaded
        2 Rendered
        3 Ghosted
        4 XRay
        5 Technical
        6 Artistic
        7 Pen
        8 Arctic
        9 Raytraced
        10 etc ! 
    '''
    display_modes = Rhino.Display.DisplayModeDescription.GetDisplayModes()
    if styl>12:
        print "!!! print nix style>12 > set_2 \"3\""
        styl = 3
    if styl==0: styx = Rhino.Display.PointStyle.ControlPoint
    if styl==1: styx = Rhino.Display.PointStyle.RoundControlPoint
    if styl==2: styx = Rhino.Display.PointStyle.Simple
    if styl==3: styx = Rhino.Display.PointStyle.RoundSimple
    if styl==4: styx = Rhino.Display.PointStyle.ActivePoint
    if styl==5: styx = Rhino.Display.PointStyle.RoundActivePoint
    if styl==6: styx = Rhino.Display.PointStyle.ArrowTip
    if styl==7: styx = Rhino.Display.PointStyle.Heart
    if styl==8: styx = Rhino.Display.PointStyle.Chevron
    if styl==9: styx = Rhino.Display.PointStyle.Triangle
    if styl==10: styx = Rhino.Display.PointStyle.X
    if styl==11: styx = Rhino.Display.PointStyle.Pin
    if styl==12: styx = Rhino.Display.PointStyle.Asterisk

    #print display_modes[displayModeX].EnglishName+"("+str(displayModeX)+") >> pointStyle", "\""+str(styx)+"\""
    if displayModeX != "all" and displayModeX <= len(Rhino.Display.DisplayModeDescription.GetDisplayModes()):
        selected_description = Rhino.Display.DisplayModeDescription.GetDisplayModes()[int(displayModeX)]
        selected_description.DisplayAttributes.PointRadius =  rad
        selected_description.DisplayAttributes.PointStyle = styx # Rhino.Display.PointStyle.Simple
        Rhino.Display.DisplayModeDescription.UpdateDisplayMode(selected_description)
        if 0 or verbose : print "*** style \""+(display_modes[int(displayModeX)].EnglishName+"\":::::::::::::: ")[0:15]+" PointRadius =", rad, "geaendert, danke Eszter & danke Andi fuer PointStyle = \""+str(styx)+"\""
    else:
        #if 0 or verbose : print "ALL"
        for displayModeX in range(len(display_modes)):
            selected_description = display_modes[displayModeX]
            selected_description.DisplayAttributes.PointRadius =  rad
            selected_description.DisplayAttributes.PointStyle = styx # Rhino.Display.PointStyle.Simple
            Rhino.Display.DisplayModeDescription.UpdateDisplayMode(selected_description)
            #if 0 or verbose : print "*** style \""+(display_modes[displayModeX].EnglishName+"\":::::::::::::: ")[0:15]+" PointRadius =", rad, "geaendert, danke Eszter & danke Andi fuer PointStyle = \""+str(styx)+"\""
    if 1:
        ###DISPLAY_MODE##
        #print displayModeX
        if isinstance(displayModeX, int) and int(displayModeX) < 11:
            selected_description = display_modes[int(displayModeX)]
        ###RADIUS POINTS###
        disX = displayModeX
        if verbose:
            print "PointStyle 0: square outline"
            print "PointStyle 1: circle outline"
            print "PointStyle 2: square solid"
            print "PointStyle 3: circle solid"
            print "PointStyle 4: square ActivePoint"
            print "PointStyle 5: round ActivePoint"
        for i, disX in enumerate(display_modes):
            english_name = disX.EnglishName
            english_name = english_name.translate(None, "_ -,.")
            if 0 or verbose:
                num = str(i)
                if i<10:num= " "+num
                print num+" = "+(str(english_name)[0:]+":::::::::::::::::")[0:13],
                print "pointRadius=", int(display_modes[i].DisplayAttributes.PointRadius),
                print "/ pointStyle =", display_modes[i].DisplayAttributes.PointStyle

def printDisplay(state=1, scale=1, thickness=1, color="Display"):
    rs.Command("_PrintDisplay State=Off _enter", 0)
    if state: 
        cmd = "_PrintDisplay State=On Color="+str(color)+" Scale="+str(scale)+" _enter"
        #print cmd
        rs.Command(cmd, 0)

def textDots(coordList, strX="", justName=0):
    RDstate = rs.EnableRedraw(0)
    lis = []
    if len(coordList):
        for i, pt in enumerate(coordList):
            if not justName: 
                lis.append(rs.AddTextDot(str(i)+strX, pt))
            else:
                lis.append(rs.AddTextDot(strX, pt))
    else:
        print "***________no list > no textDots"
    rs.EnableRedraw(RDstate)
    return lis

global timeX
timeX = time.time()

def setTime():
    global timeX
    timeX = time.time()

def getTime(verbose=0):
    global timeX
    tim = float(time.time())
    tim -=  float(timeX)
    if verbose:
        print "tim: "+str(round(tim,2))+"s"
    return round(tim,0)


# very simple leading zero
def preNull( val, sign="0", sollLen=1 ):
    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)


######## very simple remapping of a value
def reMap(i, iMin, iMax, oMin, oMax, limit=0):
    inFac  = float(i-iMin)/float(iMax-iMin)# 
    outFac = (oMax-oMin)
    if limit and (oMin + outFac*inFac) < oMin:
        return oMin
    if limit and  (oMin + outFac*inFac) > oMax:
        return oMax
    return (oMin + outFac*inFac)
    
    
######## list mixxing  / iterations / 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) ]

################
######## functions for interaction
################

######## break if you need to
def esc(wo=""):
    if _host.EscapePressed(0):
        raise Exception(wo+'***ESCape*Key*Pressed***')
        #print rs.CommandHistory()



###########################
### DM2_w25 / setup 4 hu_02
def setUp_hu_02( anzahl=64, rotateSqu=0 ):
    rCircle = random.uniform(4,12)
    aCube   = random.uniform(4,12)
    mCube   = [0,0,random.uniform(4,12)]
    mCircle = [ 0, 0, 0]
    anz = anzahl
    if anz < 5:
        anz=8
        print "   *** anzahl coords set 8 (= minimum)"
    anz -= anz%4
    vecRadial = [-rCircle*.5, -rCircle*.5, 0]
    coordsCir = []
    dAng = 360.0/anz
    for i in range(anz):
        vec = rs.VectorRotate(vecRadial, dAng*i, [0,0,1] )
        coordsCir.append( vec)
    movCube = random.choice(coordsCir)
    #rs.AddLine(mCircle, mCube)
    coordsCub = []
    dA = aCube/(anz/4)
    
    for i in range( int(anz/4)+1 ):
        vec = [mCube[0]-aCube*0.5 + dA*i, mCube[1]-aCube*0.5, mCube[2]]
        coordsCub.append( vec)
    for vec in coordsCub[0:int(anz/4)]:
        vec= rs.VectorAdd(rs.VectorRotate(vec, 90, [0,0,1] ),[0,dA, 0])
        coordsCub.append( vec)
    for vec in coordsCub[1:int(anz/2)]:
        vec= rs.VectorRotate(vec, 180, [0,0,1] )
        coordsCub.append( vec)
    
    rota = 0
    rvec = [0,0,1]
    if rotateSqu:
        rota = rotateSqu # random.randint(-90,90)
        rvec = [random.uniform(-0.1*rotateSqu,0.1*rotateSqu), random.uniform(-0.1*rotateSqu,0.1*rotateSqu), 1.00]
        rvec = [rotateSqu, rotateSqu, 1.00]
        for i,vec in enumerate(coordsCub):
            coordsCub[i] = rs.VectorRotate(vec, rotateSqu, rvec)
    movCube = rs.VectorSubtract(random.choice(coordsCir), random.choice(coordsCub))
    movCube = rs.VectorSubtract(coordsCir[0], coordsCub[0])
    movCube[2] = 0

    for i,vec in enumerate(coordsCub):
        pass
        coordsCub[i] = rs.VectorAdd(vec, movCube)
    if 1:
        rota = round(rotateSqu, 2)
        print "   *** *********** *********** *** DM2_w25 / hu_02 / square_&_circle"
        print "   *** setUp_hu_02("+str(anzahl)+", "+str(rota)+") returned 2 arrays with", anz, "pointCoords each: [coordsCir, coordsSqu]"
        print "   *** coordsSqu are rotated "+str(rota)+".0Â° @ axis ["+str(rota)+", "+str(rota)+", 1.0]"
        print "   *** ********* *********** *** ************************* *****"
    return[coordsCir, coordsCub]


###########################
### DM2_w25 / setup 4 hu_02
axe = randVec()
def coordsCub (edge_len=10, anz_pts=10, what="A", angle=random.uniform(-0, 0), axe=randVec(), pos=[0,0,0], allInOne=1):
    dist_pts = edge_len/(anz_pts - 1)
    #print ("dist_pts = "+str(dist_pts))
    anz = anzY = anz_pts
    if  what == "E":
        anzY=1
    coordsCub = []
    coords = []
    #X=Y=Z=0
    for x in range(anz):
        for y in range(anz):
                X = dist_pts * x
                Y = dist_pts * y
                if what=="A":
                     coords.append( [X-edge_len*.5, Y-edge_len*.5, 0] )
                if what=="F" or (x==0 or x==anz-1 or y==0 or y==anz-1):
                     if what=="F": coords.append( [X, Y, 0] )
                if what == "E" and y==0:# and len(coords)< edge_len:# (x==0 or x==anz-1 or y==0 or y==anz-1):
                    coords.append( [X, 0, 0] )
    if what == "A":
        what = "ALL"
        coordsCub = [ [rs.VectorAdd( cor, [0, 0, dist_pts*i-edge_len*.5] ) for cor in coords] for i in range(anz) ]
    if what == "F":
        what = "FACES"
        coordsCub.append( coords )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [1, 0,0]), [0, 0, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [0,-1,0]), [X, 0, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [1, 0,0]), [0, X, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [0,-1,0]), [0, 0, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor,  0, [0,-1,0]), [0, 0, X]) for cor in coords] )
    if what == "E":
        what = "EDGES"
        coordsCub.append( coords )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor,  90, [0, 0, 1]), [X, 0, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 180, [0, 0, 1]), [X, X, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor,  90, [0, 0, -1]), [0, X, 0]) for cor in coords] )
        
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [0, -1, 0]), [0, 0, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [0, -1, 0]), [X, 0, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [0, -1, 0]), [X, X, 0]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 90, [0, -1, 0]), [0, X, 0]) for cor in coords] )

        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor,  0, [0, 0, 1]), [0, 0, X]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor,  90, [0, 0, 1]), [X, 0, X]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor, 180, [0, 0, 1]), [X, X, X]) for cor in coords] )
        coordsCub.append( [ rs.VectorAdd( rs.VectorRotate(cor,  90, [0, 0, -1]), [0, X, X]) for cor in coords] )
    
    for i,coords in enumerate(coordsCub):
        coordsCub[i] = [ rs.VectorAdd( rs.VectorRotate(cor,  angle, axe), pos ) for cor in coords]
    #########
    coordsSph = [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( randVec(), random.uniform(0,1001), randVec())), edge_len*.5) for i in range(1001)]
    ##rs.AddPoints(coordsSph)
    if allInOne:
        tmp = []
        for coords in coordsCub: tmp.extend( coords )
        coordsCub = tmp[:]
        coordsCub = rs.CullDuplicatePoints(coordsCub)
        print ("   ***************************************************")
        print ("   *** "+what+"_List : "+str(len(coordsCub)))+" coords"
        print ("   *************************************************** DM2_w25 / hu_03 / spherification")
        return [ coordsSph, coordsCub ]
    else:
        print ("   ***************************************************")
        print ("   *** "+what+"_Lists : "+str(len(coordsCub))+" lists / "+str(len(coordsCub[0])))+" coords each"
        print ("   *************************************************** DM2_w25 / hu_03 / spherification")
        return [ coordsSph, coordsCub ]



######## set up an empty new layer in rhino

def newEmptyLayer( lay, color=[105,105,105], transe=0.0, gloss=0.0, refl=0.0 ):
    #rs.CurrentLayer( "Default")
    layX = lay
    #if parent: layX = parent+"::"+lay
    rs.AddLayer( lay, color, parent=0 )
    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.Redraw()
    rs.CurrentLayer( lay )


####################################################################


lib  = os.getcwd()+"DM_lib.py"
if platform.system() == 'Windows' and os.path.isfile( lib ):
    tims = os.path.getmtime( lib )
    saveDat = datetime.datetime.fromtimestamp(tims).strftime("%A, %B %d, %Y %H:%M:%S")
    print "                                     "+lib+"  saveDat: "+saveDat
print     "   '''''''''''''''''''''''''''''''''''''''''CC by-nc-sa '''"
print     "   '''  DM_lib mini version imported in %ss            ''' \n%s" % (getTime(0), version) 
print     "   ''''''''''''''''''''''''''''''''''''''''''''''''''''''''\n"
####################################################################