#######################
#-*- coding: utf-8 -*-


######## DM* ############# mini
######## agruber@tugraz.at
######## library #########

version = "   '''  ver 20251024 by _diag 4 DM* @ I OI III @ TUGraz  ''' ver_05 / new: hu_03_setUp"

################
######## 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=1)
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 "*** 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()




######## set up an empty new layer in rhino

def newEmptyLayer( lay, color=[105,105,105], transe=0.0, gloss=0.0, refl=0.0 ):
    '''
    newEmptyLayer( lay, color=[105,105,105], transe=0.0, gloss=0.0, refl=0.0 )
    new layer is set current !
    '''
    layX = lay
    rs.AddLayer( lay, color, parent=0 )
    if rs.IsLayer( layX ) :
        rs.ShowObjects( rs.ObjectsByLayer( layX ) )
        rs.DeleteObjects( rs.ObjectsByLayer( 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*255 )         # Gloss 0.0..1.0 // diag 2022 01 28
    #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



###########################
### 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_03

def setUp_hu_03(edge_len=random.uniform(8,16), anz_pts=random.randint(8,16), what="A", angle=random.uniform(-360, 360), axe=randVec(), pos=[0,0,random.uniform(8,16)], allInOne=1, verbose=1):
    edge_len *= 1.0
    dist_pts = edge_len / (anz_pts - 1)
    anz = anz_pts
    what = what.upper()
    if what == "E" or what == "F": pos = rs.VectorAdd( pos, [edge_len*-0.5, edge_len*-0.5, 0]  )
    coordsCub = []
    coords = []
    #X=Y=Z=0
    for x in range(anz_pts):
        for y in range(anz_pts):
            X = dist_pts * x - edge_len*0.5*(what=="A")
            Y = dist_pts * y - edge_len*0.5*(what=="A")
            if 1 and what=="A":
                 coords.append( [X-edge_len*0.0, Y-edge_len*0.0, 0] )
            if what=="F" or (x==0 or x==anz_pts-1 or y==0 or y==anz_pts-1):
                 if what=="F": coords.append( [X, Y, 0] )
            if what == "E" and y==0:
                coords.append( [X, 0, 0] )
    #rs.AddPoints( coords )
    radius = edge_len*(3**0.5)*0.5 # raum_diag
    radius = edge_len*(2**0.5)*0.5 # face_diag
    
    coordsCub = []
    coordsSph = []
    if what == "A":
        ### what = "\"A\"_ll"
        coordsCub = [ [rs.VectorAdd( cor, [0, 0, dist_pts*i-edge_len*.5] ) for cor in coords] for i in range(anz) ]
        #coordsCub = [ rs.VectorAdd( cor, [0, 0, dist_pts*i-edge_len*1.0] ) for cor in coordsCub ] ## 2025 10 21 :)
        coordsSph = [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( randVec(), random.uniform(-360,360), randVec())), radius) for i in range(anz_pts**3)]
    if what == "F":
        what = "\"F\"_aces"
        ### CUB
        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] )
        
        ### SPH
        pts = anz_pts**2
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,0,1])), radius) for i in range(pts)]  ) ### aequator
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [0,radius,0], random.uniform(-360,360), [1,0,0])), radius) for i in range(pts)] ) ### 0_meridian
        #coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,1,0])), radius) for i in range(pts)] ) ### 0_meridian
        ## 45deg
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,radius,0], random.uniform(-360,360), [1,-1,0])), radius) for i in range(pts)] ) ### 0_meridian
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,-radius,0], random.uniform(-360,360), [1,1,0])), radius) for i in range(pts)] ) ### 0_meridian
    
        coordsSph.append( [rs.VectorRotate(vec, 45, [1,0,0]) for vec in coordsSph[0]] ) ### 0_meridian
        coordsSph.append( [rs.VectorRotate(vec, -45, [1,0,0]) for vec in coordsSph[0]] ) ### 0_meridian

    if what == "E":
        what = "\"E\"_edge"
        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] )
        
        ### SPH
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,0,1])), radius) for i in range(anz_pts*4)]  ) ### aequator
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [0,radius,0], random.uniform(-360,360), [1,0,0])), radius) for i in range(anz_pts*4)] ) ### 0_meridian
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,1,0])), radius) for i in range(anz_pts*4)] ) ### 0_meridian

    ### move_2 0/0/0
    pos = [pos[0], pos[1], pos[2]+edge_len*.5*(what=="A")]
    #pos = rs.VectorAdd( pos, [edge_len*-0.0, edge_len*-0.0, edge_len*.5*(what=="A")]  )
    for i,coords in enumerate(coordsCub):
        pass
        coordsCub[i] = [ rs.VectorAdd( rs.VectorRotate(cor,  angle, axe), pos ) for cor in coords]
    if what == "A":
        what = "\"A\"_ll"
    if allInOne:
        tmp = []
        for coords in coordsCub: tmp.extend( coords )
        coordsCub = tmp[:]
        lenx = len(coordsCub)
        coordsCub = rs.CullDuplicatePoints(coordsCub)
        diff = lenx-len(coordsCub)
        tmp = []
        for coords in coordsSph: tmp.extend( coords )
        coordsSph = tmp[:]
        coordsSph = rs.CullDuplicatePoints(coordsSph)
        for i in range(diff):
            coordsSph.remove(random.choice(coordsSph))
        if verbose:
            print ("   *** allInOne = 1 *****************************")
            print ("   *** "+what+"_list : "+str(len(coordsCub)))+" coords each (Sph & Cub)"
            print ("   *** ****************************************** DM2_w25 / hu_03 / spherification")
        return [ coordsSph, coordsCub ]
    if allInOne == 0:
        if verbose:
            print ("   *** allInOne = 0 ***************************************")
            if len(coordsSph) > 7:
                print ("   *** "+what+" | SPH == CUB == "+str(len(coordsSph))+" coords each")
            if len(coordsSph) < 7:
                print ("   *** "+what+" | SPH = "+str(len(coordsSph))+" lists a "+str(len(coordsSph[0]))+" | CUB = "+str(len(coordsCub))+" lists a "+str(len(coordsCub[0]))+" == "+str(len(coordsCub)*len(coordsCub[0]))+" coords each")
            print ("   *** ************************************** DM2_w25 / hu_03 / spherification")
        return [ coordsSph, coordsCub ] 


###########################
### DM2_w25 / setup 4 hu_03

def coordsCub(edge_len=random.uniform(8,16), anz_pts=random.randint(8,16), what="A", angle=random.uniform(-360, 360), axe=randVec(), pos=[0,0,random.uniform(8,16)], allInOne=1, verbose=1):
    edge_len *= 1.0
    dist_pts = edge_len / (anz_pts - 1)
    anz = anz_pts
    what = what.upper()
    if what == "E" or what == "F": pos = rs.VectorAdd( pos, [edge_len*-0.5, edge_len*-0.5, 0]  )
    coordsCub = []
    coords = []
    #X=Y=Z=0
    for x in range(anz_pts):
        for y in range(anz_pts):
            X = dist_pts * x - edge_len*0.5*(what=="A")
            Y = dist_pts * y - edge_len*0.5*(what=="A")
            if 1 and what=="A":
                 coords.append( [X-edge_len*0.0, Y-edge_len*0.0, 0] )
            if what=="F" or (x==0 or x==anz_pts-1 or y==0 or y==anz_pts-1):
                 if what=="F": coords.append( [X, Y, 0] )
            if what == "E" and y==0:
                coords.append( [X, 0, 0] )
    #rs.AddPoints( coords )
    radius = edge_len*(3**0.5)*0.5 # raum_diag
    radius = edge_len*(2**0.5)*0.5 # face_diag
    
    coordsCub = []
    coordsSph = []
    if what == "A":
        ### what = "\"A\"_ll"
        coordsCub = [ [rs.VectorAdd( cor, [0, 0, dist_pts*i-edge_len*.5] ) for cor in coords] for i in range(anz) ]
        #coordsCub = [ rs.VectorAdd( cor, [0, 0, dist_pts*i-edge_len*0.01] ) for cor in coordsCub ] ## 2025 10 21 :)
        coordsSph = [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( randVec(), random.uniform(-360,360), randVec())), radius) for i in range(anz_pts**3)]
    if what == "F":
        what = "\"F\"_aces"
        ### CUB
        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] )
        
        ### SPH
        pts = anz_pts**2
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,0,1])), radius) for i in range(pts)]  ) ### aequator
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [0,radius,0], random.uniform(-360,360), [1,0,0])), radius) for i in range(pts)] ) ### 0_meridian
        #coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,1,0])), radius) for i in range(pts)] ) ### 0_meridian
        ## 45deg
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,radius,0], random.uniform(-360,360), [1,-1,0])), radius) for i in range(pts)] ) ### 0_meridian
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,-radius,0], random.uniform(-360,360), [1,1,0])), radius) for i in range(pts)] ) ### 0_meridian
    
        coordsSph.append( [rs.VectorRotate(vec, 45, [1,0,0]) for vec in coordsSph[0]] ) ### 0_meridian
        coordsSph.append( [rs.VectorRotate(vec, -45, [1,0,0]) for vec in coordsSph[0]] ) ### 0_meridian

    if what == "E":
        what = "\"E\"_edge"
        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] )
        
        ### SPH
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,0,1])), radius) for i in range(anz_pts*4)]  ) ### aequator
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [0,radius,0], random.uniform(-360,360), [1,0,0])), radius) for i in range(anz_pts*4)] ) ### 0_meridian
        coordsSph.append( [ rs.VectorScale(rs.VectorUnitize(rs.VectorRotate( [radius,0,0], random.uniform(-360,360), [0,1,0])), radius) for i in range(anz_pts*4)] ) ### 0_meridian

    ### move_2 0/0/0
    pos = [pos[0], pos[1], pos[2]+edge_len*.5*(what=="A")]
    for i,coords in enumerate(coordsCub):
        pass
        coordsCub[i] = [ rs.VectorAdd( rs.VectorRotate(cor,  angle, axe), pos ) for cor in coords]
    if what == "A":
        what = "\"A\"_ll"
    if allInOne:
        tmp = []
        for coords in coordsCub: tmp.extend( coords )
        coordsCub = tmp[:]
        lenx = len(coordsCub)
        coordsCub = rs.CullDuplicatePoints(coordsCub)
        diff = lenx-len(coordsCub)
        tmp = []
        for coords in coordsSph: tmp.extend( coords )
        coordsSph = tmp[:]
        coordsSph = rs.CullDuplicatePoints(coordsSph)
        for i in range(diff):
            coordsSph.remove(random.choice(coordsSph))
        if verbose:
            print ("   *** allInOne = 1 *****************************")
            print ("   *** "+what+"_list : "+str(len(coordsCub)))+" coords each (Sph & Cub)"
            print ("   *** ****************************************** DM2_w25 / hu_03 / spherification")
        return [ coordsSph, coordsCub ]
    if allInOne == 0:
        if verbose:
            print ("   *** allInOne = 0 ***************************************")
            if len(coordsSph) > 7:
                print ("   *** "+what+" | SPH == CUB == "+str(len(coordsSph))+" coords each")
            if len(coordsSph) < 7:
                print ("   *** "+what+" | SPH = "+str(len(coordsSph))+" lists a "+str(len(coordsSph[0]))+" | CUB = "+str(len(coordsCub))+" lists a "+str(len(coordsCub[0]))+" == "+str(len(coordsCub)*len(coordsCub[0]))+" coords each")
            print ("   *** ************************************** DM2_w25 / hu_03 / spherification")
        return [ coordsSph, coordsCub ] 



####################################################################
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"
####################################################################


def makeDummyBox():
    p0 = [0,0,0]
    p1 = [edge_len, 0,0]
    p2 = [edge_len,edge_len,0]
    p3 = [0,edge_len,0]
    coords = [ [0,0,0], [edge_len, 0,0], [edge_len,edge_len,0],[0,edge_len,0] ]
    coords = [ rs.VectorAdd(cor, [edge_len*-.5*(what.lower()=="a"),edge_len*-.5*(what.lower()=="a"),edge_len*-.5*(what.lower()=="a")] ) for cor in [p0,p1,p2,p3] ]
    coords.extend( [ rs.VectorAdd(cor, [0,0,edge_len] ) for cor in coords ])
    posX = [pos[0]-edge_len*.5*(what.lower()=="f" or what.lower()=="e"),pos[1]-edge_len*.5*(what.lower()=="f" or what.lower()=="e"),pos[2]+edge_len*.5*(what.lower()=="a")]
    coords = [ rs.VectorAdd(rs.VectorRotate(cor, angle, axe), posX) for cor in coords ]
    return rs.AddBox( coords )


################
######## functions 4duerer 2020
######## functions cage 4_corona 2021
######## functions MVDVR LODGE  2025
################

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=0 ) :
    """
    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): talk & sleep / 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]
    """
    newEmptyLayer( "LODGE::demo", [100,200,100] )
    rs.DeleteObjects(rs.ObjectsByLayer("LODGE::demo"))
    if 1 or verbose:
        print "\t                      ________"
        print "\t                     /_/_/_|__\\"
        print "\t### dmLODGE          |_|_|_|__|\n\t########################DM2_w25"
    if verbose:
        print "\t### return [ panels, panels_sleeve, panels_right, panels_left, sections, cvs_sleeve, cvs_right, cvs_left ] => allData[] !\n"
        rs.ObjectColor( rs.AddCurve( [[0,0,0], [pos_x, pos_y, 0]] ), [200,0,20] )
        #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 "\tthe 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 "\tthe 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 "\tthe 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
    if verbose: section0_id = rs.AddCurve( section0, 1 );
    if verbose: 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 "\tnew 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
    else: # if not demo
        pass
        #rs.AddCurve( sections[0], 1 )
        #rs.AddCurve( sections[-1], 1 )
        #rs.ObjectColor(rs.AllObjects()[:2], [100,100,120])
        #rs.ObjectName( rs.AllObjects()[:2], "lodgeSections")
        #rs.ZoomExtents()
    if verbose:
        allData = [ panels, panels_sleeve, panels_right, panels_left, sections, cvs_sleeve, cvs_right, cvs_left ]
        print "\t### allData[0][0][0] = panels[0][0] = \"p0\" = [", allData[0][0][0], "] etc etc etc ... "
    return [ panels, panels_sleeve, panels_right, panels_left, sections, cvs_sleeve, cvs_right, cvs_left ]

rs.EnableRedraw(0)
#allLodgeData = getLodge( demo=0, verbose=0 )
rs.EnableRedraw(1)