#######################
#-*- coding: utf-8 -*-


######## DM* ############# mini 4 python_2+1
######## agruber@tugraz.at
######## library #########

dat = "2025 12 19"
version = "   |||  ver: "+dat.replace(" ", "")+" by _diag 4 DM1+1 @ I OI III @ TUGraz ||| "+str(dat)+" += switchList + makeSrf_fromCoords"
################
######## basic library data and functions
################

######## import
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import System, sys, os, platform

import datetime, time
from datetime import datetime

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
Rhino.ApplicationSettings.AppearanceSettings.EchoCommandsToHistoryWindow = 1
Rhino.ApplicationSettings.AppearanceSettings.EchoPromptsToHistoryWindow  = 1

################
######## 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", False)
    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", False) ### diag 2021 11 07
    rs.Redraw()

######## zoom Selected
def zS() :
    rs.ZoomSelected( all=1 )


################
######## basic point and vector functions
################

def exportCoordLists( list2export=[], exportedListName="allCoords", path="P:/", fileName="allCoords"):
    setTime()
    if not os.path.exists(path): os.makedirs(path)
    fo = open(path+fileName+".py", 'w')
    fo.write( exportedListName+" = [")
    #list = list2export[0:]
    for j,list in enumerate(list2export):
        fo.write( "\n[ ### list_"+str(j)+"\n")
        #print j, len(list)
        if 1:
            for i, cor  in enumerate(list):
                out = "["+str(cor[0])+","+str(cor[1])+","+str(cor[2])+"]"
                fo.write( out  )
                if i<len(list)-1:
                    fo.write( ",\n"  )
        fo.write( "\n]")
        if j<len(list2export)-1:
            fo.write( ", ###")

    fo.write( "\n] ### END\n")
    fo.close()
    print ("*** "+str(len(list2export))+" coord_Lists exported to file "+str(path+fileName)+".py | in"+str(getTime())+"s")
    #print path+fileName+".py"
    
def Reparameterize( crv, param=1001 ):
    '''
    arguments:
        crv  : guid of curve (!)
        param: number - best: rs.CurveLenght(crv)
    returns:
        DOM number - rs.CurveDomain(crv)[1]
    '''
    print ("*** Reparameterized: DOM "+str(rs.CurveDomain(crv)[1])+" >> "+str(param)),
    rs.Command("Reparameterize -selId "+str(crv)+" enter 0 "+str(param)+" ", False)
    return rs.CurveDomain(crv)[1]

######## 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


### diag 2022 12 11 / for delaunay_3Dtol
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, False)

# 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", False)
        coords = rs.ObjectGripLocations( objID )
        rs.Command("_pointsOff _enter", False)
    rs.UnselectAllObjects()
    if rs.ObjectType(objID)==8:
        rs.EnableObjectGrips(objID, True)
        coords = rs.ObjectGripLocations( objID )
        rs.EnableObjectGrips(objID, False)
    return coords ### danke, andi !

def getMeshPoints( objId ):
    verts=rs.coercemesh(objId).Vertices
    return [ verts.Point3dAt(i) for i in range(verts.Count-1) ]


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( objID, coords )
        rs.EnableObjectGrips(objID, 0)

### DISPLAY  etc 
################

def mathRound(number, nachkomma):
    return math.floor(number*pow(10, nachkomma))/pow(10, nachkomma)
    
def getCameraTarget(view=rs.CurrentView(), verbose=1):
    if verbose==2: print ("***\nview: \"%s\" : [camPos], [targetPos], lens \n" % (rs.CurrentView())),
    cam   = rs.ViewCameraTarget(rs.CurrentView())
    plane = rs.ViewCameraPlane(rs.CurrentView())
    camPos    = "%s, %s, %s" % (mathRound(cam[0][0], 8),mathRound(cam[0][1], 8),mathRound(cam[0][2], 8))
    targetPos = "%s, %s, %s" % (mathRound(cam[1][0], 8),mathRound(cam[1][1], 8),mathRound(cam[1][2], 8))
    lensVal   = round( rs.ViewCameraLens(rs.CurrentView()), 8)
    
    upVec = rs.ViewCameraUp(rs.CurrentView(), up_vector=None)
    if verbose: print ("dm.setCameraTarget( [%s], [%s], lens=%s, rota=0, upVec=[0,0,1] ) # ... danke, andi !" % (camPos, targetPos, lensVal ))# upVec)
    return [rs.ViewCameraTarget(rs.CurrentView())[0], rs.ViewCameraTarget(rs.CurrentView())[1], lensVal, upVec]


def setCameraTarget(camera=[0, 0, 0], target=[0, 0, 1], lens=50, rota=0, upVec=0, verbose=0 ):
    rs.ViewCameraTarget(rs.CurrentView(), camera, target )
    if lens : rs.ViewCameraLens(rs.CurrentView(), lens)
    if upVec: rs.ViewCameraUp(rs.CurrentView(), upVec)
    if 1 or rota : 
        #rs.RotateView(rs.CurrentView(), direction=0, angle=rota)
        #rs.RotateCamera(view=None, direction=0, angle=rota)
        rs.Command("-_viewportproperties rotation "+str(rota)+" enter enter", False)
    if verbose :
        rs.Redraw()
        getCameraTarget(view=rs.CurrentView(), verbose=verbose)
    #rs.Command("-ViewportProperties Rotation 0 -enter",1)



def SetObjDisplayModeAllViewports(objIDs, displaymodeX=1, verbose=1):
    #msg="Select objects to set display mode"
    #objIDs=rs.GetObjects(msg,8+16+32,preselect=True)
    all_dmodes = Rhino.Display.DisplayModeDescription.GetDisplayModes()
    if not all_dmodes:
        print ("Failed to get display mode data!") ; return
    #check display modes for validity and create 2 parallel lists modes/names
    valid_dmodes=[]
    valid_modenames=[]
    for i,dmode in enumerate(all_dmodes):
        if dmode is not None and not dmode.PipelineLocked or 1:
            local_name=dmode.LocalName
            if local_name:
                valid_dmodes.append(dmode)
                valid_modenames.append(local_name)
                if verbose==2 and not dmode.PipelineLocked:
                    print ("\t", i, "=", local_name)

        if not valid_dmodes:
            print ("XXX No valid display modes found!") ; return
    if 0:
        msg="Choose a display mode for objects"    
        mode_name=rs.ListBox(valid_modenames,msg,"Display Mode List")
        if not mode_name: return
        for i in range(len(valid_modenames)):
            if mode_name==valid_modenames[i]: break
    
    if not objIDs:
        print ("............XXX no objects selected XXX") ; return
        
    vIDs=[view.ActiveViewportID for view in sc.doc.Views]
    
    for vID in vIDs:
        for objID in objIDs:
            objRef=sc.doc.Objects.Find(objID)
            attr = objRef.Attributes
            attr.SetDisplayModeOverride(valid_dmodes[displaymodeX], vID)
            sc.doc.Objects.ModifyAttributes(objID, attr, False)
    if verbose:
        print ("...........", len(objIDs), "objects set_2 DisplayMode: \""+str(valid_modenames[displaymodeX])+"\"")
    sc.doc.Views.Redraw()
### USAge
### objs = rs.ObjectsByLayer("PROJECT::scheiben::srf")
### SetObjDisplayModeAllViewports(objIDs=objs, displaymodeX=1, verbose=1)
### 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(str.maketrans("", "", "_ -,."))
            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 =", str(display_modes[i].DisplayAttributes.PointStyle))

def printDisplay(state=True, scale=1, color="Display"):
    rs.Command("_PrintDisplay State=Off _enter", False)
    if state==True: 
        cmd = "_PrintDisplay State=On Color="+str(color)+"  Thickness=Scale Scale="+str(scale)+" _enter"
        rs.Command(cmd, False)

################
######## text and display functions
################

######## adding leading zeros
def textPre0( val, sign="0", sollLen=2 ):
    # 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)

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,2)


# 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) ]


### switch list / diag 2025 11 30
def switchList (listX):
    x_dir = len(listX[0])
    y_dir = len(listX)
    print ( "list x/y_dir = "+str(x_dir)+ "/" +str(y_dir) )
    tmp=[]
    for x in range(len(listX[0])):
        cols = []
        for y in range(len(listX)):
            cols.append(listX[y][x])
        tmp.append(cols)
    return tmp

### switch list / short version / diag 2025 11 30
def switchList (listX):
    return [ [listX[y][x] for y in range(len(listX))] for x in range(len(listX[0])) ]

################
######## functions for interaction
################

################
######## date/time/SUN & location- and osm-related functions
################


######## get time
def timeGet(verbose=0, prenull=0):
    '''
    timeGet(verbose=0, prenull=0)
    Parameters:
        verbose: int 0/1 print
        prenull: int, textPre0(tim, "0", prenull)
    Returns:
        round(tim,2)
    '''
    global timeX
    tim = float(time.time())
    tim -=  float(timeX)
    tim = round(tim,2)
    txt = str(tim)
    if prenull:
        txt = textPre0(tim, sign="0", sollLen=prenull)
        print ("txt "+str(txt))
    if verbose:
        print (str(txt)+"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"




def getDateNow():
    now = datetime.now()
    #print "day :", type(now.day), now.day
    #printTime = str(now.year)+textPre0(now.month)+textPre0(now.day)+textPre0(now.hour)+textPre0( now.minute)+textPre0(now.second)
    #print printTime
    return [now.year, now.month, now.day, now.hour, now.minute, now.second]#, printTime]

dat = getDateNow()

def daysInMonth(year=dat[0]):
    return [31, 28+(int(year)%4==0), 31,30,31,30,31,31,30,31,30,31]
    
def date2number( year=dat[0], mon=12, day=30, verbose=0 ):
    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 number2minute(num):
    minu = int(num%60)
    hor = int((num-minu)/60)
    return [hor, minu]


### https://www.timeanddate.de/stadt/zeitumstellung/oesterreich?year=2024
dlSaving=0 # sommerzeit o.a.
dlSaving = 300 < date2number( *dat[0:3] ) < 90 ### 
if 0:
    print ("heute ", date2number( *dat[0:3], verbose=0 ) )
    print ("26.10.", date2number( dat[0], 10, 26, verbose=0 ) )
    print ("30.03. ", date2number( dat[0], 3, 30, verbose=0 ) )
    print ("dlSaving", dlSaving*1 )

def ortX(ortX):
    ort = "guinea"
    lat = 0#
    lon = 0#
    timeZone = 0#
    ### graz
    if ortX == "hart": 
        ort = "hart"
        lat = 47.04618 #=hart bei graz
        lon = 15.51435 #                         
        timeZone = 1+dlSaving ## UTC+1 .. sommerzeit: UTC+2
    
    if ortX == "graz":
        ort = "graz"
        lat = 47.0654 #=kronesgasse / 
        lon = 15.4486 #
        ##lat = 47.07086780 #=opernring
        ##lon = 15.43827860 #                         
        timeZone = 1+dlSaving ## UTC+1 .. sommerzeit: UTC+2

    
    if ortX == "schulgasse":
        ort = "schulgasse"
        lat = 47.067994 # lt google maps
        lon = 15.466236 
        timeZone = 1+dlSaving
        
    ### 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
    if ortX == "barcelona": 
        ort == "barcelona"
        lat = 41.3737000
        lon = 2.1133000
        timeZone = 1
    if ortX == "HONOLULU": 
        ort == "HONOLULU"
        lat = 21.306944
        lon = -157.858333
        timeZone = -10
    if ortX == "TIRANA": 
        ort == "TIRANA"
        lat = 41.332
        lon = 19.832
        timeZone = 1
    
    if ortX == "STOCKHOLM":
        ort == "STOCKHOLM"
        lat = 59.406667
        lon = 17.9575
        timeZone = 1

    return [lat, lon, timeZone, ortX]

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=2025):
    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)


_2day = getDateNow()
dayNumber2day = date2number(_2day[0], _2day[1], _2day[2])
dat = getDateNow()

ort = "graz"
#ort = "giza"
#ort = "koenigsberg"
#ort = "shepperton"

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]) ##28/10/2024-12/44/39
        if verbose:
            print ("    setSun @", year, textPre0(mon, sign="0", sollLen=2), textPre0(day, sign="0", sollLen=2), "(day# "+str(date2number(year,mon,day))+")","@", str(hour)+":"+str(min)+":"+str(sec)+" @ "+ort.upper()+" @ lat/lon =",str(round(ortX(ort)[0],4))+"°/"+str(round(ortX(ort)[1],4))+"°", "| tZ = "+str(ortX(ort)[2])),
            print ("| azi/alti =", str(round(sun.Azimuth,4))+"°/"+str(round(sun.Altitude,4))+"°")#,":"
            #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]] ]
        sunVec = sun.Vector
        return [ sun.Azimuth, sun.Altitude, sun.Vector ]
    else:
        print ("*** ________no good date: setSun("+str(year)+(", ")+str(mon)+", "+str(day)+") | return ="),
        return [0,0,[0,0,0]]



######## break if you need to

def esc():
    sc.escape_test(1)

######## add empty new layer in rhino / empty existing layer and set current / color etc changes ok
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, True)
    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 ] 

if not "2.7" in sys.version:
    reload = " "
def reload_lib( which ):
    if "2.7" in sys.version:
        #print ("   sys.version / py :", sys.version[0:6])
        reload(which)
    else:
        #print ("   sys.version / py :", sys.version[0:6])
        import importlib
        importlib.reload(which)



####################################################################
lib  = os.getcwd()+"DM_lib.py"
if 0 and 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     ("   |||  py_ver "+str(sys.version[0:6])+"  |||||||||||||||||||||  CC by-nc-sa  ||| 2025 11 25 += getPixxels, flowAlongSrf, exportCoordLists, getMeshPoints")
print     ("   |||  DM_lib mini version imported in %ss               ||| \n%s" % (getTime(0), version) )
#print     ("   |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||")
if 1:
    schlafTage = (date2number(2025,12,24) - dayNumber2day)%365
    print ("   |||  btw: "+str(schlafTage)+" tage sinds noch bis weihnachten - dh, eh noch "+str(schlafTage*4)+ " stunden schlafen !")
print ("   |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||")

####################################################################

def setCrvStartPoint( crvID, set2point=[0,0,0] ):
    '''

    '''
    if not rs.IsCurveClosed(crvID):
        print ("!!! curve ist not closed")
        return
    param = rs.CurveClosestPoint(crvID, set2point)
    rs.CurveSeam(crvID, param)
    ### tst
    ### print (str(rs.CurveStartPoint(crvID))+"\n"+"str(rs.EvaluateCurve(crvID,param)))
    return rs.CurveStartPoint(crvID)
    

####################################
######## functions MVDVR LODGE  2025
### no dm.functionality !
edge_len=what=pos=angle=axe=allPanels=0
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 )
### no dm.functionality !

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 0 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 ]
#allLodgeData = getLodge( demo=0, verbose=0 )
######## functions MVDVR LODGE  2025
####################################



############################
### DM2_w** demo UN_NYC_slab / simplyfied version
unoX = [   0.876922678230265,  -0.480631476711064, 0 ]
unoY = [   0.480631476711061,   0.876922678230267, 0 ]
uno0 = [ 727.495136230253000, 531.705385598354000, 0 ]

slabs = L = 11
depth = D =  4
floors= H = 40
fH = 4.0
lenY =  87.50
lenX =  22.00
lenZ = 156.00

UNerror = 1
def getUnoCoord( l, d, h ):
    if UNerror and (  l >= L or d >= D or h >= H or l<0 or d<0 or h<0 ):
        print ("*** getUnoCoord: any parameter too big or neg:",l,d,h,"? ______________***")
        #return UnoGridCoords[ 0 ]
        return [0,0,0]
    else:
        #print "index :", l + d*L + h*D*L 
        return UnoGridCoords[ l + d*L + h*D*L ]

UnoGridCoords = []
def getUnoGridCoords(L=11, D=4, H=40, fH = 4.0):
    #baseCoords = rs.CurveEditPoints(rs.ObjectsByName("_bldg3D_crv_137989966")[0])
    #baseXYZ = baseCoords[14]
    #baseXYZ = [727.495136230253,531.705385598354,0.00]
    #print baseXYZ
    #    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)
    #    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 = uno0
                cor = rs.VectorAdd( cor, rs.VectorScale(unoX, lenX*x/(D-1)))
                cor = rs.VectorAdd( cor, rs.VectorScale(unoY, slab_spacing*y))
                cor = rs.VectorAdd( cor, [0,0, fH*z])
                UnoGridCoords.append( cor )
    #print ("*** UnoGridCoords = [",L,"*",D,"*", H,"=", len(UnoGridCoords),"coords]   by getUnoGridCoords() @ DM2_lib ***")
    #print ("**************************************************************************************\n")
    return UnoGridCoords
UnoGridCoords = getUnoGridCoords(L=10, D=4, H=40, fH = 4.0)

##################### / 2025 11 07
def gC(L=1, D=1, H=1):
    vecX=rs.VectorScale(unoX, D*lenX/(depth-1)) 
    vecY=rs.VectorScale(unoY, L*lenY/(slabs-1)) 
    vecZ=[0,0,H*fH]
    vecXYZ = rs.VectorAdd(rs.VectorAdd( rs.VectorAdd(uno0,vecX), vecY ), vecZ)
    return vecXYZ

def UN_slab(showAll=0):
    #eA()
    slabs = 10
    depth = 4
    floors= 39
    fH = 4.0
    #lenY = 116.56
    #lenX =  28.18
    lenZ = 156.00
    rs.ObjectColor( rs.AddLine( uno0, rs.VectorAdd( uno0, rs.VectorScale(unoX, lenX) ) ), [200,0,0] )# x/Red
    rs.ObjectColor( rs.AddLine( uno0, rs.VectorAdd( uno0, rs.VectorScale(unoY, lenY) ) ), [0,200,0] )# y/Green
    rs.ObjectColor( rs.AddLine( uno0, rs.VectorAdd( uno0, [0,0,39*fH] ) ),                [0,0,200] )# z/Blue
    
    linX = rs.AllObjects()[2]
    linY = rs.AllObjects()[1]
    linZ = rs.AllObjects()[0]
    if 1:
        for y in range(0, slabs+1):
            rs.CopyObject( linZ, rs.VectorScale( unoY, lenY/slabs*y ) )
            if showAll:
                for x in range(1, depth+1):
                    rs.CopyObject( rs.AllObjects()[0], rs.VectorScale( unoX, lenX/depth) )
    if 1:
        #rs.CopyObject( linY, rs.VectorScale( unoX, lenX) )
        for f in range(1, floors+1):
            rs.CopyObject( linY, [0,0,fH*f] )
        #rs.CopyObject( rs.AllObjects()[0], rs.VectorScale( unoX, lenX) )
    if showAll:
        for y in range(0, slabs+1):
            pass
            rs.CopyObject( linX, rs.VectorScale( unoY, lenY/slabs*y ) )
            rs.CopyObject( rs.AllObjects()[0], [0,0,fH*(floors+0)] )
        #eDup()
    #zA()
#newEmptyLayer("Default")
#UN_slab(showAll=1)

def getUNpanelCoords( anzL=10, anzH=39, anzD=3, stepL=1, stepH=4, stepD=1, verbose=0):
    depthVec  = dVec = rs.VectorUnitize(rs.VectorSubtract( getUnoCoord(0, 1, 0), getUnoCoord(0, 0, 0) ))
    lengthVec = lVec = rs.VectorUnitize(rs.VectorSubtract( getUnoCoord(1, 0, 0), getUnoCoord(0, 0, 0) ))
    frontPanels = []
    sidePanels = []
    backPanels = []
    upSidePanels = []
    topPanels = []
    allPanels = []
    lenL = rs.Distance( getUnoCoord(0, 0, 0), getUnoCoord(10, 0, 0) )
    lenD = rs.Distance( getUnoCoord(0, 0, 0), getUnoCoord(0, 3, 0) )
    lenH = rs.Distance( getUnoCoord(0, 0, 0), getUnoCoord(0, 0, 39) )

    anzY = int(anzL/stepL)
    anzZ = int(anzH/stepH)
    anzX = int(anzD/stepD)
    deltaL = lenL/(anzY)
    deltaH = lenH/(anzZ)
    deltaD = rs.Distance( getUnoCoord(0, 0, 0), getUnoCoord(0, 3, 0) )/anzX

    for z in range(anzZ+0):
        for y in range(anzY+0):
            pass
            p0 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*y)), [0,0,deltaH*z] )
            p1 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+1))), [0,0,deltaH*z] )
            p2 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+1))), [0,0,deltaH*(z+1)] )
            p3 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+0))), [0,0,deltaH*(z+1)] )
            coords = [p0, p1, p2, p3]
            coords = [p0, p3, p2, p1]
            frontPanels.append( coords )
            allPanels.append( coords )
    
    for z in range(anzZ+0):
        for x in range(anzX+0):
            pass
            p0 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(dVec, deltaD*x)), [0,0,deltaH*z] )
            p1 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(dVec, deltaD*(x+1))), [0,0,deltaH*z] )
            p2 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(dVec, deltaD*(x+1))), [0,0,deltaH*(z+1)] )
            p3 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(dVec, deltaD*(x+0))), [0,0,deltaH*(z+1)] )
            coords = [p1, p2, p3, p0]
            sidePanels.append( coords )
            allPanels.append( coords )

    for panel in frontPanels:
        coords = [ rs.VectorAdd(rs.VectorSubtract( getUnoCoord(0, 3, 0), getUnoCoord(0, 0, 0) ), cor) for cor in panel ]
        #coords = reversed([ rs.VectorAdd(rs.VectorSubtract( getUnoCoord(0, 3, 0), getUnoCoord(0, 0, 0) ), cor) for cor in panel ])
        coords.reverse()
        backPanels.append(coords)
        allPanels.append( coords )
    
    for panel in sidePanels:
        coords = [ rs.VectorAdd(rs.VectorSubtract( getUnoCoord(10, 0, 0), getUnoCoord(0, 0, 0) ), cor) for cor in panel ]
        coords.reverse()
        upSidePanels.append(coords)
        allPanels.append( coords )

    if 1:
        ### topPanels / 2025 01 09
        for y in range(anzY+0):
            for x in range(0,anzX+0):
                pass
                p0 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+0))),  rs.VectorScale(dVec, deltaD*x) )
                p1 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+1))),  rs.VectorScale(dVec, deltaD*x) )
                p2 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+1))),  rs.VectorScale(dVec, deltaD*(x+1)) )
                p3 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(0, 0, 0), rs.VectorScale(lVec, deltaL*(y+0))),  rs.VectorScale(dVec, deltaD*(x+1)) )
                p0[2]=p1[2]=p2[2]=p3[2]=156
                #p0 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(y+0, 0, 0), rs.VectorScale(dVec, deltaD*x)), [0,0,4*39] )
                #p1 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(y+1, 0, 0), rs.VectorScale(dVec, deltaD*x)), [0,0,4*39] ) 
                #p2 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(y+1, 0, 0), rs.VectorScale(dVec, deltaD*(x+1))), [0,0,4*39] ) 
                #p3 = rs.VectorAdd(rs.VectorAdd(getUnoCoord(y+0, 0, 0), rs.VectorScale(dVec, deltaD*(x+1))), [0,0,4*39] ) 
                coords = [p0, p1, p2, p3]
                topPanels.append( coords )
                allPanels.append( coords )
    #allPanels.extend(backPanels)
    #allPanels.extend(upSidePanels)
    if verbose:
        print ("    ### ################ DM2_w24 / hu_06 / UN_panelling")
        print ("    ### getUNpanelCoords( anzL="+str(anzL)+",anzH="+str(anzH)+",anzD="+str(anzD)+",stepL="+str(stepL)+",stepH="+str(stepH)+",stepD="+str(stepD)+") ..",len(allPanels), "panelCoordLists generated:")
        print ("    ### allPanels = [frontPanels, backPanels, sidePanels, upSidePanels, allPanels, topPanels]")
        print ("    ### ##########################################################################")
    return [frontPanels, backPanels, sidePanels, upSidePanels, allPanels, topPanels]

if 0: ### tst
    topPanels = getUNpanelCoords( anzL=10, anzH=39, anzD=3, stepL=1, stepH=4, stepD=1, verbose=0)[5]
    for panel in topPanels:
        rs.AddCurve( panel )

####################################
if 1: ### UN PANELS ## dm2_w25 hu_05
    pass
    UnoGridCoords = getUnoGridCoords(11, 4, 40, 4.0)
    UnoBaseCoords = [getUnoCoord(0,0,0), getUnoCoord(L-1,0,0), getUnoCoord(L-1,D-1,0), getUnoCoord(0,D-1,0), getUnoCoord(0,0,0)]
    UnoPanelCoords = getUNpanelCoords( anzL=10, anzH=39, anzD=3, stepL=1, stepH=4, stepD=1, verbose=0)

###################################
### recursive division of UN_panels

minHig = 4
#global maxPanels
maxPanels = 16
recPanels  = [ [getUnoCoord( 0, 0, 0), getUnoCoord( 0, 0, 39), getUnoCoord(10, 0, 39), getUnoCoord(10, 0, 0)] ]
global cnt
cnt=0
def dividePanel(recPanels=recPanels, maxPanels=maxPanels, minHig=minHig, verbose=0):
    '''
        arguments: maxPanels=25, minHig=4
        return: panels/coords
    '''
    global cnt
    cnt *= (len(recPanels) > 1)
    cnt += 1
    if maxPanels>500: maxPanels=500
    if minHig>12:  minHig=12
    
    panel=random.choice( recPanels )
    if rs.Distance( panel[0], panel[1] ) > minHig*2:# and len(recPanels) < maxPanels-3 and cnt < 1001:
        recPanels.remove( panel )
        pMid = pntInbetween(panel[0],panel[2])
        recPanels.append([panel[0], pntInbetween(panel[0],panel[1]), pMid, pntInbetween(panel[3], panel[0])])
        recPanels.append([pntInbetween(panel[0], panel[1]), panel[1],pntInbetween(panel[1],panel[2]), pMid])
        recPanels.append([pMid, pntInbetween(panel[1],panel[2]), panel[2], pntInbetween(panel[2],panel[3])])
        recPanels.append([pntInbetween(panel[0],panel[3]), pMid, pntInbetween(panel[2],panel[3]), panel[3]])
        if verbose:
            print ("*** "+str(int(len(recPanels)/3))+": len recPanels = "+str(len(recPanels)))
    
    if (1 < len(recPanels) <= maxPanels-3) and cnt < 500:# and cnt<501:
        dividePanel(recPanels=recPanels, maxPanels=maxPanels, minHig=minHig, verbose=verbose )
    else:
        lenx = int(len(recPanels)/3)
        print ("*** ********* **********\n*** recursive executions: "+str(lenx)+" >> anzahl panels: "+str(lenx*3+1)+" (max="+str(maxPanels)+"|cnt:"+str(cnt)+")")
    return recPanels



def getPixels(imagePath, steps_x=1, steps_y=1, verbose=1):
    # https://discourse.mcneel.com/t/how-to-store-list-of-list-when-reading-rgb-values-of-an-image/88276/6
    """
    Gets the pixel colors of an image.
    Args:
      image_path: An absolute path to an image file.
      steps_x: A number of pixels to sample in image x-direction.
      steps_y: A number of pixels to sample in image y-direction.
    Returns:
      A list of lists with a sublist of pixel *colors*
        for each sampled row of the image .. starting linx_unten
    """
    ###
    setTime()
    bitmap = System.Drawing.Bitmap.FromFile(imagePath)
    pixels = []
    for y in range(bitmap.Height-1, -1, -1):
        if y % steps_y == 0:
            row_pixels = []
            for x in range(bitmap.Width):
                if x % steps_x == 0:
                    pixel = bitmap.GetPixel(x, y)
                    row_pixels.append( [pixel.R,  pixel.G,  pixel.B ] )
            pixels.append(row_pixels)
    if verbose:
        print ("\timagePath = "+str(imagePath))
        print ("\twidth "+str(bitmap.Width)+" / steps_x("+str(steps_x)+") >> "+str(int(bitmap.Width/steps_x))+"px")
        print ("\thight "+str(bitmap.Height)+" / steps_y("+str(steps_y)+") >> "+str(int(bitmap.Height/steps_y))+"px .. = "+str(int(bitmap.Width/steps_x)*int(bitmap.Height/steps_y))+" pixelz/RGBs"),
        print ("| in "+str(getTime())+"s")
    return pixels
    
#bitmap = System.Drawing.Bitmap.FromFile("alice.jpg")


############# 2024 12 14
def makeDodekaeder( rad=10.0, pos=[0,0,0], makeCrv=1, makeSrf=1, verbose=1):
    ### https://de.wikipedia.org/wiki/Dodekaeder#/media/Datei:Dodekaeder-w.svg
    '''
    return: allCoords = 12 coordLists
    '''
    r = rad
    c = (5**0.5+1)*0.5*r
    a = rs.Distance([r,0,0], rs.VectorRotate( [r,0,0], 72, [0,0,1] ))
    if verbose:
        print ("*** dodecahedron | pentagondodekaeder")
        print ("*** radius\t\t r "+str(r) )
        print ("*** kantePentagon\t a "+str(a) )
        print ("*** kante Cubus\t c "+str(c) )
        print ("*** allCoords = [ rs.VectorAdd(pos, rs.VectorRotate(cor, 72.0*i, [0,0,1])) for cor in [[r,0,0], [c, 0, r], rs.VectorRotate([c,0,c], 36.0, [0,0,1] ), [c*.5,a*.5,r+c]] for i in range(5) ]")
    allCoords = [ rs.VectorAdd(pos, rs.VectorRotate(cor, 72.0*i, [0,0,1])) for cor in [[r,0,0], [c, 0, r], rs.VectorRotate([c,0,c], 36.0, [0,0,1] ), [c*.5,a*.5,r+c]] for i in range(5) ]
    indices=[[x+(i*5) for x in [0,1,2,3,4]] for i in range(0,4)] 
    pentaIndices = [[0,1,2,3,4,0]]
    pentaIndices.extend( [[indices[0][0+i], indices[0][1+i], indices[1][1+i], indices[2][0+i], indices[1][0+i],indices[0][0+i]] for i in range(4)] )
    pentaIndices.append( [4,0,5,14,9,4] )
    pentaIndices.append( [6,11,16,15,10,6] )
    pentaIndices.extend( [[pentaIndices[6][0]+i, pentaIndices[6][1]+i, pentaIndices[6][2]+i, pentaIndices[6][3]+i, pentaIndices[6][4]+i, pentaIndices[6][5]+i] for i in range(1,4)] )
    pentaIndices.append( [5,10,15,19,14,5] )
    pentaIndices.extend( [range(15,20)] )
    pentaIndices[-1].append(15)
    pentaIndices[0].reverse()
    allCoords = [[allCoords[i] for i in indlist] for indlist in pentaIndices ]
    if makeCrv:
        for coords in allCoords:
            crv=rs.AddCurve( coords, 1 )
            if makeSrf: rs.AddPlanarSrf(crv)
    return allCoords
### USAge
#coords = makeDodekaeder( rad=1.0, pos=[1,11,0], makeCrv=1, makeSrf=1, verbose=1)


############# 2025 02 02
def flowAlongSrf(objs, base="ID", target="ID", preserveIt=0, verbose=0 ):
    #setTime()
    flowed = []
    for i,obj in enumerate(objs):
        esc()
        color = rs.ObjectColor(obj)
        matIndex = rs.ObjectMaterialIndex(obj)
        ###print "matIndex", matIndex
        chg = 0
        if rs.IsCurve(obj) and not preserveIt and rs.CurveDegree(obj)==1:
            chg=1
            rs.ChangeCurveDegree(obj, 2)
        objM  = Rhino.DocObjects.ObjRef(obj)
        morph = Rhino.Geometry.Morphs.SporphSpaceMorph(rs.coercesurface(base), rs.coercesurface(target))#, ptBase, ptTarg)
        morph.PreserveStructure = preserveIt
        geom = objM.Geometry().Duplicate()
        if (morph.Morph(geom)):
            sc.doc.Objects.Add(geom)
            #sc.doc.Views.Redraw()
            rs.ObjectColor( rs.AllObjects()[0], color)
            flowed.append( rs.AllObjects()[0] )
        if chg:
             rs.ChangeCurveDegree(obj, 1)
        if matIndex > 0:
            rs.AddMaterialToObject(rs.AllObjects()[0])
            rs.ObjectMaterialIndex(rs.AllObjects()[0], matIndex) 
        if verbose>1 and i%verbose==0:
            print ("-flowed "+str(i+(i==0))+" von "+str(len(objs))+" in "+str(getTime())+"s |")
            rs.Redraw()
    if 0<verbose<2:
        print ("-flowed: "+str(len(flowed))+" objs in "+str(getTime())+"s |")
        rs.Redraw()
    return flowed

### USAge
if 0:
    target = rs.ObjectsByName("DEM")[0]
    #target = rs.ObjectsByName("040_3")[0]
    base = rs.ObjectsByName("base")[0]
    rug = rs.ObjectsByName("kreuz_sm")[0]
    #rug = rs.ObjectsByName("tst_crv")[0]
    objs = rs.ObjectsByLayer("pattern")
    
    
    newEmptyLayer("FLOW::srf", [0,200,100])
    flowAlongSrf(objs, base=base, target=target, preserveIt=0, verbose=0)

rs.EnableRedraw(1)

#########################

###################### 4 animatzi
#################################
trans = ["No", "Yes"]

def makeName( name="tst", frameNumber=1110, anzahl=4, format="jpg"):
    pre = ("0"*10 + str(frameNumber))[-anzahl:]
    ### name = pre+"_"+name+"."+format
    name = name+"_"+pre+"."+format
    return name



def makeSrf_fromCoords (coords=[], deg = 2):
    # calc anzahl in row / xDir
    anzY = vonY = 0
    anzX = vonX = 0
    steps=1
    if 1:
        y0 = coords[0][1]
        for xDir, cor in enumerate(coords):
            yX = cor[1]
            if yX != y0:
                break
        yDir = int(len(coords)/xDir)
        xDir = xDir
        print "______________________xDir", xDir
        print "______________________yDir", yDir
        
        anzX = xDir
        anzY = yDir
        
        coordsA = []
        for y in range(0, anzY, steps):
            if y>yDir:break
            for x in range(0, anzX, steps):
                coordsA.append( coords[vonX+x + xDir*(vonY+y)] ) # 1251
                if x>xDir:break
        anzY = int(anzY/steps)
        anzX = int(anzX/steps)
        print "pointcount", anzY,"/", anzX, "*=", anzY*anzX
        print "len(coordsA)", len(coordsA), "diff=", len(coordsA)-anzY*anzX
        if len(coordsA) > anzY*anzX:
            anzX += 1
            print "pointcount korr", anzY,"/", anzX, "*=", anzY*anzX
            print "len(coordsA)", len(coordsA), "diff=", len(coordsA)-anzY*anzX

        srf = rs.AddSrfPt( [[0,0,0],[0,1,0],[1,1,0],[1,0,0]])
        #deg = 1
        rs.RebuildSurface(srf, degree=(deg,deg), pointcount=(anzY, anzX )) ## old
        rs.EnableObjectGrips(srf, 1)
        rs.ObjectGripLocations(srf, coordsA )
        rs.EnableObjectGrips(srf, 0)
        rs.FlipSurface(srf, 1)
        rs.Command("ApplyPlanarMapping -selid "+str(srf)+" enter enter enter enter enter", 0) # need 4 texturing !
        rs.ObjectName(rs.AllObjects()[0], "x_"+str(vonX)+"-"+str(vonX+anzX*(steps)-steps)+"_y_"+str(vonY)+"-"+str(vonY+anzY*(steps)-steps)+"_"+str(steps)+"mRaster")
        rs.ObjectName(rs.AllObjects()[0], "SRF_from_coords_deg_"+str(deg) )
        return rs.AllObjects()[0]
        
        