#######################
#-*- coding: utf-8 -*-

'''
library 4 [DM*] @ III OI III by _diag / agruber@tugraz.at
2018/12
2023/06
2024/12
'''

import rhinoscriptsyntax as rs
import scriptcontext as sc


import Rhino
from System.Drawing import Color
import RhinoPython.Host as __host # 4 esc()
import math, random # a + (b - a)*random
import fnmatch # unix filename_match
import struct  # 4 OSM, HGT getCor()
import re      # reg ex

import os.path, time
import System, System.DateTime
import sys
#print sys.modules#.clear()
#sys.path.append("L:/dm2_w16/PY/")
from time import gmtime, strftime, ctime
from System.Drawing import Color
from itertools import combinations as cb # 4 convHull

###___GPX-----------------------------------------------------------------------
import clr
clr.AddReferenceByPartialName('System.Xml')
from System.Xml import XmlTextReader, XmlNodeType, XmlReaderSettings, XmlReader
import System.Xml as xml

#import _
global timeX
timeX = time.time()

global move2guinea


global HGTpath
HGTpath="L:/PY/HGT/HGT/"


import clr
clr.AddReferenceByPartialName('System.Xml')
from System.Xml import XmlTextReader, XmlNodeType


def rand(a, b=0): # 20171010
    r = random.uniform(a, b) # float
    if (type(a)==int) and  (type(b)==int) : return int(r)
    else: return r

global abzugLon
global abzugLat
### Abplattung 6.356.752 
###große Halbachse a = 6.378.137 Meter,
base = 6356752*0.759
#base = 6378137
def lat2coord(lat):
    global minLat
    global move2guinea
    global abzugLat
    move2guinea = 0
    val = (base * math.log((math.sin(math.radians(lat))+1.0) / math.cos(math.radians(lat)))) - ( move2guinea * (base * math.log((math.sin(math.radians(int(minLat)))+1.0) / math.cos(math.radians(int(minLat))))) )
    abzugLat = ( 1 * (base * math.log((math.sin(math.radians(int(minLat)))+1.0) / math.cos(math.radians(int(minLat))))) )
    return val

def lon2coord(lon):
    global minLon
    global move2guinea
    global abzugLon
    move2guinea = 0
    val = (base * math.radians(lon)) - ( move2guinea *(base * math.radians(int(minLon) )) )
    abzugLon = 1 *(base * math.radians(int(lon)))
    #print val, "-", abzug, "=", val - move2guinea*abzug
    return val


'''
    DORIS ooe / 0.5m ALS DGM
    https://www.land-oberoesterreich.gv.at/211787.htm
    #https://search.earthdata.nasa.gov/granules/download.txt?project=8306465326&collection=C1000000240-LPDAAC_ECS

    https://gisgeography.com/free-global-dem-data-sources/
    https://gisgeography.com/srtm-shuttle-radar-topography-mission/
    https://earthexplorer.usgs.gov/
    !!! https://e4ftl01.cr.usgs.gov/MEASURES/
    !!! http://e4ftl01.cr.usgs.gov/MEASURES/SRTMGL1.003/2000.02.11/N33E009.SRTMGL1.hgt.zip
    USA: https://dds.cr.usgs.gov/srtm/version2_1/SRTM1/
    http://www.eorc.jaxa.jp
    europa 1' / 3'
    http://www.viewfinderpanoramas.org/Coverage%20map%20viewfinderpanoramas_org1.htm
    http://data.opendataportal.at/dataset?res_format=hgt&tags=H%C3%B6henmodell
    all europe :
    https://drive.google.com/drive/folders/0BxphPoRgwhnoWkRoTFhMbTM3RDA
    https://drive.google.com/drive/folders/0BxphPoRgwhnoekRQZUZJT2ZRX2M
'''




 
def getCor(hgtFile, n, e, DEMsec=3):
    anzahl = (3600 / DEMsec) + 1
    i = anzahl - int(round(n / DEMsec, 0))
    j = int(round(e / DEMsec, 0))
    hgtFile.seek(((i - 1) * anzahl + (j - 0)) * 2)  # was (j -1) !!! go to the right spot,
    buf = hgtFile.read(2)  # read two bytes and convert them:
    val = struct.unpack('>h', buf)[0]  # ">h" is a signed two byte integer
    return val
    if not val == -32768:  # the not-a-valid-sample value
        return val
    else:
        return None
        

def getCoords(degN, minN, anzN, degE, minE, anzE, west=0, DEMsec=3, deg=2, eleFact=1.0, HGTpath="L:\PY\HGT\HGT\\"):
    global allCoords
    global tile
    global tileName
    global move2guinea
    global minLat
    global minLon
    global abzugLat
    global abzugLon
    
    west = 0
    if degE < 0:
        west=1
        degE *= -1
    tileName = "xxx"
    tmp = anzE
    anzE = anzN
    anzN = tmp
    eastx=int(60/DEMsec*anzE+1)
    nordx=int(60/DEMsec*anzN+1)
    
    if (eastx or nordx) > 999:
        print "*** *** *** 2_many elevPts > ESC (",sorted([anzN, anzE])[1],") ***"
        gogo=1
    else: gogo=1
    rs.AddLayer("DEM", [0, 155, 0])
    ### R=150+10*DEMsec, G=150+20*DEMsec, B=150+30*DEMsec
    col = [150, 85*(DEMsec+(DEMsec==1)), 50*(DEMsec+(DEMsec==1))]
    rs.AddLayer("DEM::DEM"+str(DEMsec), col)
    rgbMat2Lay( "DEM::DEM"+str(DEMsec), col, T=0, Gloss=0.0, Refl=0.2, reflCol=[250,250,200], matNam="DEM"+str(DEMsec) )
    
    rs.CurrentLayer("DEM::DEM"+str(DEMsec))
    demFolder = ""
    if DEMsec == 3:    demFolder = "DEM"+str(DEMsec)+"\\"
    degNt= str(abs(degN))
    degEt= str(degE)
    
    if abs(degN) < 10:  degNt = "0"+str(abs(degN))
    if degE < 100: degEt = "0"+str(degE)
    if degE < 10: degEt = "00"+str(degE)

    minNt= str(minN)
    minEt= str(minE)
    if minN < 10: minNt = "0"+minNt
    if minE < 10: minEt = "0"+minEt
    
    tile = "N"+degNt+"E"+degEt
    minusN = ""
    if degN < 0:
        minusN = "-"
        tile = "S"+degNt+"E"+degEt
        print "### degN < 0 :", tile
    if west:
        tile = "N"+degNt+"W"+degEt
        if degN < 0: tile = "S"+degNt+"W"+degEt
        if tileName=="xxx": tileName = "DEM_"+minusN+degNt+"_"+minNt+"_"+str(anzE)+"_-"+degEt+"_"+minEt+"_"+str(anzN)
    if tileName=="xxx":
        tileName =  "DEM_"+minusN+degNt+"_"+minNt+"_"+str(anzE)+"_"+degEt+"_"+minEt+"_"+str(anzN)

    tile = HGTpath+demFolder+tile+".hgt"
    print "***", tile,

    coords = allCoords = []
    max = 0
    maxCor = []
    
    if 1 and gogo:
        hgtFile = open(tile, "rb")
        setTime()
        for iE,E in enumerate(range(minE, minE+1)): # min !
            for iN, N in enumerate(range(minN, minN+1)): # min !
                coords = allCoords = []
                for j in range(0, 60*anzE+1, DEMsec): # east: scan direction given @ getCor!
                    coords = []
                    for i in range(0,60*anzN+1, DEMsec): # north
                        esc()
                        n = N*60 + j # sec !
                        e = E*60 + i # src !
                        #ele = getCor(hgtFile, n-3*(DEMsec==1001), e+3*(DEMsec==1001), DEMsec=DEMsec)
                        ele = getCor(hgtFile, n, e, DEMsec=DEMsec)
                        if i and j and i<60*anzN and j<60*anzE:
                            pass
                            ele += rand(-0.01, 0.01)
                        #print ele
                        if iE+iN+i+j ==0:
                            minLon = int(degE + (E+0)/60.0 + i/3600.0)
                            minLat = int(degN-0 + (N+0)/60.0 + j/3600.0)
                            if west: minLon*=-1
                            #print "||| minLon / minLat", round(minLon,4),"/", round(minLat,4)
                        lon = lon2coord( (degE + (E+0)/60.0 + i/3600.0))
                        if west: lon = lon2coord((degE - (E+0)/60.0 - i/3600.0)*-1)
                        lat = lat2coord(degN-0 + (N+0)/60.0 + j/3600.0)
                        if not ele: ele = 0
                        cor = [lon, lat, ele*eleFact]
                        allCoords.append(cor)
                        #print i,j,"-",(degN-0 + (N+0)/60.0 + j/3600.0),"________",int(lat)
                        if 0 and ele > max:
                            max = ele
                            print i,j,"__",n,":",ele,"  e:",e, " ele=", ele
                            maxCor = cor
                            rs.AddPoint(cor)
        hgtFile.close()
        #print "len(allCoords)", len(allCoords)
        coordsByZ = sorted(allCoords, key=lambda cor: cor[2])
        print "*** Z elev:",round(coordsByZ[0][2]/eleFact,1), "-", round(coordsByZ[-1][2]/eleFact,1),"meters",

        return allCoords


### USAge
def makeDEM(degN, minN, anzN, degE, minE, anzE, HGTpath=HGTpath, west=0, DEMsec=1, deg=1, eleFact=1.0, move2Guinea=1):
    diplayMode = rs.ViewDisplayMode(rs.CurrentView())
    diplayMode = rs.ViewDisplayMode(rs.CurrentView(), "wireframe")
    global move2guinea
    global abzugLon
    global abzugLat
    move2guinea=move2Guinea
    west = 0
    if degE < 0: west=1
    rs.AddLayer("Default", [105,105,105])
    anzN0=anzN
    anzE0=anzE
    eastE=nordN=0
    east=int(60/DEMsec*anzE+1)
    nord=int(60/DEMsec*anzN+1)
    if minN+anzN>60: anzN0 = 60-minN
    if minE+anzE>60: anzE0 = 60-minE
    allCoords=allCoordsN=allCoordsE=allCoordsEN=[]
    global tileName
    print "*** **********************" #HGTpath", HGTpath
    allCoords = getCoords( degN+0, minN, anzN0, degE, minE, anzE0, west=west, DEMsec=DEMsec, deg=deg, eleFact=eleFact, HGTpath=HGTpath)
    if minN+anzN>60:
        allCoordsN  = getCoords( degN+1,    0, minN+anzN-60, degE, minE, anzE0, west=west, DEMsec=DEMsec, deg=deg, eleFact=eleFact, HGTpath=HGTpath)
        anzN0 = 60-minN
        nord=int(60/DEMsec*anzN0+1)
        nordN=int(60/DEMsec*(minN+anzN-60)+1)
    if minE+anzE>60:
        allCoordsE  = getCoords( degN+0, minN, anzN0, degE+1,  0, minE+anzE-60, west=west, DEMsec=DEMsec, deg=deg, eleFact=eleFact, HGTpath=HGTpath)
        anzE0 = 60-minE
        east=int(60/DEMsec*anzE0+1)
        eastE=int(60/DEMsec*(minE+anzE-60)+1)
    if minN+anzN>60 and minE+anzE>60:
        allCoordsEN = getCoords( degN+1,    0, minN+anzN-60, degE+1,  0, minE+anzE-60, west=west, DEMsec=DEMsec, deg=deg, eleFact=eleFact, HGTpath=HGTpath)
    coords = allCoords
    if (minN+anzN>60) or (minE+anzE>60):
        coordsW=allCoords [0:-east-(minN+anzN<=60)]+allCoordsN
        coordsE=allCoordsE[0:-eastE-(minN+anzN<=60)]+allCoordsEN
        if (minN+anzN<=60):
            coordsW=allCoords+allCoordsN
            coordsE=allCoordsE+allCoordsEN
        coords = []
        for nor in range(nord+nordN-(minN+anzN>60)):
            for eas in range(east-(minE+anzE>60)): coords.append(coordsW[eas+nor*east])
            for eas in range(eastE): coords.append(coordsE[eas+nor*eastE])
    #coords.sort( key=lambda cor: (cor[1],  cor[0]) )
    if 0:
        srf=makeSrf (coords, nord+nordN-(minN+anzN>60), east+eastE-(minE+anzE>60), deg=deg)
        rs.ObjectLayer(srf, "Default")
        print "len(allCoords)\t", len(allCoords[0:-east])
        print "len(coords)   \t", len(coords), "deg", deg
        print "nord=", nord
        print "nordN=", nordN
        print "east=", east
        print "eastE=", eastE
    if 1:
        for srf in rs.ObjectsByName(tileName):
            if rs.ObjectLayer(srf)==rs.CurrentLayer():
                rs.DeleteObject(srf)
        #srf = rs.AddSrfPt([[0,0,0],[0,1,0],[1,1,0],[1,0,0]])
        if move2Guinea:
            coords = [ [cor[0]-abzugLon, cor[1]-abzugLat, cor[2]] for cor in coords ]
        srf = rs.AddSrfPt([[0,0,0], [anzE,0,0], [anzE,anzN,0], [0,anzN,0]])
        print east+eastE-(minE+anzE>60)-1
        crv = rs.AddCurve( [coords[0], coords[east+eastE-(minE+anzE>60) -1],coords[-1], coords[-east+eastE-(minE+anzE>60)], coords[0]], 2)
        rs.ObjectColor(crv, [200,0,200])
        rs.ObjectPrintWidth( crv, 2.0)
        rs.ZoomBoundingBox(rs.BoundingBox(crv))
        rs.Redraw()
        rs.Sleep(2000)
        rs.RebuildSurface(srf, degree=(deg,deg), pointcount=(nord+nordN-(minN+anzN>60), east+eastE-(minE+anzE>60)) )
        rs.EnableObjectGrips(srf, 1)
        rs.ObjectGripLocations(srf, coords )
        rs.EnableObjectGrips(srf, 0)
        rs.FlipSurface( srf, True)

        rs.ZoomBoundingBox(rs.BoundingBox(srf))
        rs.Redraw()
        rs.ObjectName( srf, tileName)
        rs.DeleteObject(crv)
        #print "tilename 1", tileName
        if 0:
            degNt= str(degN)
            degEt= str(degE)
            if abs(degN) < 10:  degNt = "0"+str(abs(degN))
            if degE < 100: degEt = "0"+str(degE)
            if degE < 10: degEt = "00"+str(degE)
    
            minNt= str(minN)
            minEt= str(minE)
            if minN < 10: minNt = "0"+minNt
            if minE < 10: minEt = "0"+minEt
            tile = "N"+degNt+"E"+degEt
            if degN < 0: tile = "S"+degNt+"E"+degEt
            tileName = "DEM_"+degNt+"_"+minNt+"_"+str(anzE)+"_"+degEt+"_"+minEt+"_"+str(anzN)
    #_.purgeAll()
    rs.Command("ApplyPlanarMapping -selid "+str(srf)+" enter enter enter enter enter", 0) # need 4 texturing !
        #s.FlipSurface( srf, True)
        #rs.Command("-dir -selid "+str(srf)+" enter flip SwapUV enter", 0)
    rs.ViewDisplayMode(rs.CurrentView(), diplayMode)
    rs.ZoomExtents()
    rs.Redraw()
    dist = round(rs.Distance([0,0,0], allCoords[0])*0.001, 2)
    #global abzugLon
    #global abzugLat
    print "--- subtract guinea LON=", abzugLon, "LAT=", abzugLat
    print #"||| minLon/minLat "+str(round(allCoords[0][0]*0.001,2))+"/"+str(round(allCoords[0][1]*0.001,2))+" =",dist,"KM from guinea"
    print "*** **********************"
    ### degN, minN, anzN, degE, minE, anzE
    if 1:
        print "\nperl   _stamen_4.pl  3  ",degN," ",minN," ",anzN," ",degE," ",minE," ",anzE," 15  %typ% 11"      #osm
        print "perl	_stamen_4.pl  3  ",degN," ",minN," ",anzN," ",degE," ",minE," ",anzE," %zoom%  %typ% 11"    #osm
        print "perl	_stamen_4.pl  0  ",degN," ",minN," ",anzN," ",degE," ",minE," ",anzE," %zoom%  %typ% 11"    #bing
        print "perl	_stamen_4.pl  1  ",degN," ",minN," ",anzN," ",degE," ",minE," ",anzE," %zoom%  %typ% 11"    #arcGis
        print "perl	_stamen_4.pl  5  ",degN," ",minN," ",anzN," ",degE," ",minE," ",anzE," %zoom%  %typ% 11"    #google
 
    return allCoords # [allCoords, allCoordsN, allCoordsE, allCoordsEN]
    #return srf
### HGT import == makeDEM_______________________________________

tileID=TEXpath=""
def texMat2Dem( tileID=tileID, TEXpath=TEXpath, sty="sat", zoo=17, transe=0, gloss=0, refl=0, reflCol=[255,255,255], verbose=1): 
        # sat, osm, stamen: ton, lin, ter0, ter1
        if not tileID:
            tileID=rs.AllObjects()[0]
        tileName = rs.ObjectName( tileID )
        ind = rs.AddMaterialToObject(rs.ObjectsByName( tileName )[0])
        nams   = tileName.split("_")
        imgNam = str(int(nams[1]))
        for nam in nams[2:]: imgNam += "_"+str(int(nam))
        imgNam += "_z"+str(zoo)
        imgNam += "_"+sty
        ext = "png" # 
        if sty == "sat": ext="jpg"
        imgNam += "."+ext
        if verbose:
            pass
            print "imgNam", TEXpath+imgNam
        if os.path.exists(TEXpath+imgNam):
            #print "imgNam", IMGpath+imgNam
            tex=rs.MaterialTexture( ind )
            if not tex: tex = "nixi"
            print "attached tex:", tex,
            rs.MaterialTexture( ind, TEXpath+imgNam )
            if rs.MaterialTexture( ind ) != tex:
                print " >> ", rs.MaterialTexture( ind )
            else: print
            
            #rs.MaterialTexture( ind, filename=None )
            rs.MaterialReflectiveColor( ind, reflCol )
            mat = sc.doc.Materials[ind]
            mat.Transparency=transe
            mat.Reflectivity=refl
            mat.Shine=gloss*255
            sc.doc.Materials.Modify(mat,ind,1)
            
            objref = Rhino.DocObjects.ObjRef(tileID)
            rhino_object = objref.Object()
            #rhino_object.CommitChanges()
        else:
            print "### no finding:", TEXpath+imgNam

#sc.doc.Materials.

def GPXin(GPXfile, GPXpath = 'L:\\PY\\GPX\\'):
    #settings = xml.XmlReaderSettings()
    settings = XmlReaderSettings()
    settings.IgnoreWhitespace = True
    GPXfile = GPXpath+GPXfile# +".gpx"
    #reader = xml.XmlReader.Create(GPXfile, settings)
    reader = XmlReader.Create(GPXfile, settings)
    gpxCoords=[]
    cnt = 0
    while reader.ReadToFollowing("trk"):
        cnt += 1
        while reader.ReadToFollowing("trkseg"):
            reader.ReadStartElement()
            points = []
            while reader.ReadToNextSibling("trkpt"):
                lon= float(reader.GetAttribute("lon"))
                lat= float(reader.GetAttribute("lat"))
                lon = lon2coord(lon)
                lat = lat2coord(lat)
                if reader.ReadToDescendant("ele"):
                    ele = reader.ReadElementContentAsFloat()
                    while reader.IsStartElement():reader.Skip()
                gpxCoords.append([lon,lat,ele])
            #gpxCoords = rs.CullDuplicatePoints(gpxCoords)
    return gpxCoords

#import scriptcontext
#import Rhino
sweep = Rhino.Geometry.SweepOneRail()
sweep.AngleToleranceRadians = sc.doc.ModelAngleToleranceRadians
sweep.SweepTolerance = sc.doc.ModelAbsoluteTolerance
sweep.ClosedSweep = False
sweep.SetToRoadlikeTop()
#print sweep


def drawGPX (GPXfile, GPXpath = 'L:\\PY\\GPX\\', eleFact=1.0, baseEle=0.0, deg=2, track=1, trackXY0=1, loftIt=1, trackIt=1, steps=20, trackBreite=15.1, delOld=1):
    print "### reading:", GPXfile
    rs.AddLayer("GPX")
    rs.AddLayer("crv", [200,0,0], parent="GPX")
    rs.AddLayer("srf", [200,250,200], parent="GPX")
    rs.AddLayer("track", [255,0, 0], parent="GPX")
    rs.AddLayer("kmLines", [25,25, 250], parent="GPX")
    rs.AddLayer("hmLines", [100,250, 250], parent="GPX")
    if delOld:
        rs.DeleteObjects(rs.ObjectsByLayer("Default"))
        rs.DeleteObjects(rs.ObjectsByLayer("GPX::crv"))
        rs.DeleteObjects(rs.ObjectsByLayer("GPX::srf"))
        rs.DeleteObjects(rs.ObjectsByLayer("GPX::track"))
        rs.DeleteObjects(rs.ObjectsByLayer("GPX::kmLines"))
        rs.DeleteObjects(rs.ObjectsByLayer("GPX::hmLines"))
    rs.Redraw()
    coords = []
    coordsXY0 = []
    coordsi = GPXin(GPXfile, GPXpath)
    if 1:
        anz = steps
        if steps < 0: anz = 1
        for i in range(0, len(coordsi), anz):
                    cor = coordsi[i]
                    coords.append([cor[0], cor[1], cor[2]*eleFact])
                    coordsXY0.append([cor[0], cor[1], baseEle])
        if steps > 1:# damit jedenfalls endPts erreicht wird
                    cor = coordsi[-1]
                    coords.append([cor[0], cor[1], cor[2]*eleFact])
                    coordsXY0.append([cor[0], cor[1], baseEle])
        coords = rs.CullDuplicatePoints(coords)
        coordsXY0 = rs.CullDuplicatePoints(coordsXY0)
        print "len coords:", len(coordsi), " >>", len(coords), "| steps =", steps
        rs.Command("_cplane W T _enter",0)
        
        if track or loftIt or trackIt:
            rs.CurrentLayer("GPX::crv")
            track0 = rs.AddCurve(coordsi, 1)
            rs.ObjectColor(track0, [0,25,255])
            track = rs.AddCurve(coords, 1)
            rs.ObjectName(track, "trackCrv")
            trackXY0 = rs.AddCurve(coordsXY0, 1)
            points = len(coords)-1
            if steps < 0: # zwecks besserer angleichung
                points *= steps*-1
                deg = 2
            if deg != 1:
                rs.RebuildCurve(track, degree=deg, point_count=points)
                rs.RebuildCurve(trackXY0, degree=deg, point_count=points)


        if loftIt:
            rs.CurrentLayer("GPX::srf")
            lofted = rs.AddLoftSrf( [trackXY0, track], loft_type=0 )
            rs.Redraw()
            
            if 1: # km markierungen
                #kmMmeters = 10000.0
                #kmSize = 5.0
                coords = rs.DivideCurveLength(track, kmMeters, create_points=0, return_points=1)
                if coords and len(coords) > 1:
                    for cor in coords[1:]:
                        lin = rs.AddLine( cor, [cor[0], cor[1], baseEle] )
                        rs.ObjectName(lin, "kmLine")
                        pip = rs.AddPipe(lin, [0,1], [kmSize, kmSize] )
                        rs.ObjectLayer(lin, "GPX::crv")
                        rs.ObjectLayer(pip, "GPX::kmLines")
                    rs.Redraw()
            
            if 1: # hoehen linien
                meters = 250*eleFact
                #hmSize = 10.0
                lin = rs.AddCurve( [[8550000,3790000, baseEle+meters], [8700000,3790000, baseEle+meters], [8700000,3790000, baseEle+meters+hmSize], [8550000,3790000, baseEle+meters+hmSize],[8550000,3790000, baseEle+meters]], 1 )
                rs.MoveObject(lin, [-minLon, -minLat, 0])
                for i in range(0,15):
                    hLine = rs.CopyObject( lin, [0,0,i*meters] )
                    rs.ObjectName(hLine, "hLine")
                    rs.ObjectLayer(hLine, "Default")
                    #rs.CopyObject(hLine, [0,0, thickness])
                rs.DeleteObject(lin)
                rs.Redraw()
                if 1:
                    rs.CurrentView("Front")
                    rs.ZoomExtents()
                    rs.Redraw()
                    rs.DeleteGroup("splitters")
                    splitters = rs.AddGroup("splitters")
                    rs.AddObjectsToGroup(rs.ObjectsByName("hLine"), "splitters")
                    srf = rs.ObjectsByLayer("GPX::srf")[0]
                    rs.Command("split -selid "+str(srf)+" enter -SelGroup "+str(splitters)+" enter enter",0)
                    rs.DeleteGroup("splitters")
                    rs.UnselectAllObjects()
                    for crv in rs.ObjectsByName("hLine"):
                        cen = rs.CurveAreaCentroid(crv)[0]
                        crv = rs.ScaleObject(crv, cen, [1,1,1.01])
                        rs.Command("selBoundary SelectionMode=Window  Precise=Yes -selid "+str(crv)+" enter",0)
                        rs.DeleteObject(crv)
                    rs.ObjectLayer( rs.SelectedObjects(), "GPX::hmLines")
                    rs.UnselectAllObjects()
                    rs.CurrentView("Perspektive")
                    rs.Redraw()
    if 0:
        rs.Command("-circle 0,0,0 "+str(trackBreite)+" _enter",0)
        rs.Command("_curve -"+str(trackBreite*0.5)+",0,0 "+str(trackBreite*0)+",0,0 _enter",0)
        rs.Command("_curve -"+str(trackBreite*0)+",0,0 "+str(trackBreite*0.5)+",0,0 _enter",0)
        profile1=rs.AllObjects()[0]
        profile2=rs.AllObjects()[1]
        rs.UnselectAllObjects()
        #rs.AddSweep1(track, [circ])
        #rs.CurrentLayer("Default")
        rail_crv = rs.coercecurve(track)
        cross_sections = [rs.coercecurve(crv) for crv in [profile1]]
        breps1 = sweep.PerformSweep(rail_crv, [rs.coercecurve(crv) for crv in [profile1]])
        breps2 = sweep.PerformSweep(rail_crv, [rs.coercecurve(crv) for crv in [profile2]])
        breps = breps1+breps2
        for brep in breps:
            sc.doc.Objects.AddBrep(brep)
        rs.JoinSurfaces(rs.AllObjects()[0:2], delete_input=1)
        rs.ObjectName(rs.AllObjects()[0], "track")
        #rs.DeleteObject(profile)

    if trackIt:
        rs.UnitAbsoluteTolerance( 0.1 )
        rs.CurrentLayer("track")
        rs.SelectObject(track)
        rs.ZoomSelected()
        rs.Redraw()
        rs.Command("_cplane Curve  enter", 0)
        rs.UnselectAllObjects()
        plane = rs.AddNamedCPlane("cp")
        plane = rs.NamedCPlane("cp")
        #circ= rs.AddCircle(coords[0], trackBreite)
        #print "plane", plane
        elliHoehe = trackBreite*.33333
        elli = rs.AddEllipse(plane, trackBreite, elliHoehe)
        rs.ObjectLayer(elli, "GPX::crv")
        elliCoords = rs.CurveEditPoints(elli)
        track_0 = rs.CopyObject(track, rs.VectorSubtract(rs.CurveStartPoint(track),elliCoords[2] ))
        track_1 = rs.CopyObject(track, rs.VectorSubtract(rs.CurveStartPoint(track),elliCoords[6] ))
        track=rs.AddSweep2([track_0, track_1], [elli])
        #track=rs.AddSweep1( track, [elli])
        rs.CapPlanarHoles(track)
        rs.ObjectName(track, "track")
        rs.Command("_cplane W T _enter",0)
        rs.UnitAbsoluteTolerance( 0.001 )
    rs.Command("_cplane W T _enter",0)
    rs.CurrentLayer("Default")
    rs.LayerVisible("GPX::crv", 0)
    rs.CurrentView("Perspective")
    rs.ZoomExtents()
    rs.Redraw()
    if saveIt:
        rs.Command("-saveAs \"D:\\diag\\"+folder+"\\"+GPXfile+".3dm\" enter", 0)
        print "saved 2", "D:/diag/"+folder+"/"+GPXfile+".3dm/"
    print "FINI"


def setTime():
    global timeX
    timeX = time.time()

def getTime(verbose=0, prenull=0):
    global timeX
    tim = float(time.time())
    tim -=  float(timeX)
    #tim = 1.1234
    if verbose:
        print str(round(tim,2))+"s"
    #return preNull( round(tim,1), prenull)
    return round(tim,0)

def preNull( val, sign="0", sollLen=1 ):
    # eng leading zero
    anz = sollLen-len(str(val))
    if anz>0:# and val < pow(10, anz):
        for i in range(anz): val = sign+str(val)
    return str(val)

def echo( on ):
        Rhino.ApplicationSettings.AppearanceSettings.EchoCommandsToHistoryWindow = on
        Rhino.ApplicationSettings.AppearanceSettings.EchoPromptsToHistoryWindow = on

def esc( throw_exception=1, reset=False ):
    "Tests to see if the user has pressed the escape key"
    rc = __host.EscapePressed(reset)
    #rc = sc.escape_test()
    if rc and throw_exception:
        raise Exception('\n*** esCapeKeyPressed ***')
        print "rc", rc
        return rc

### mat @ _diag 
def rgbMat2Lay(lay_nam = "", col=[127,127,127], T=0.0, Gloss=0.0, Refl=0.0, reflCol=[255,255,255], matNam="none"):
    """ Adds Material to LAYER.
    Parameters:
      lay_nam = layerName
      col = [r,g,b]
      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)
    #rs.MaterialReflectiveColor( index, (191, 191, 255) )
    newMat = sc.doc.Materials[index]
    newMat.Reflectivity=Refl
    sc.doc.Materials.Modify(newMat, index, 1)
    if not matNam: matNam = "mat_%s_%s_%s_%s_ind_%s" % (col[0], col[1], col[2], int(T*100), index)
    #print "***", matNam#, #" .. created (ind", index, ")"
    rs.MaterialColor( index, col )
    rs.MaterialTransparency( index, T-0.000001 ) # T 0.0..1.0
    rs.MaterialShine( index, Gloss*255 )             # Gloss 0.0..1.0
    rs.MaterialReflectiveColor( index, reflCol )
    rs.MaterialName (index, matNam)
    return index
    
def printDisplay(state=1):
    if state: rs.Command("_PrintDisplay State=On Color=Display Thickness=40 _enter", 0)
    else: rs.Command("_PrintDisplay State=Off _enter", 0)


def eDup(verbose=1):
    selected = rs.SelectedObjects()
    rs.UnselectAllObjects()
    vorher = len(rs.AllObjects())
    rs.Command("_selDup", 0)
    if selected and rs.SelectedObjects():
        for obj in rs.SelectedObjects():
            if obj in selected: selected.remove( obj )
    rs.DeleteObjects( rs.SelectedObjects() )
    if selected: rs.SelectObjects(selected)
    if verbose: print "*** dm.eDup() deleted", vorher - len(rs.AllObjects()), "objects ***\n"



def eAA():
    """Deletes Absolutely All objects, incl hidden and locked
    """
    rs.UnlockObjects(rs.AllObjects())
    rs.ShowObjects  (rs.AllObjects())
    rs.DeleteObjects(rs.AllObjects())
    rs.Redraw()

eDup(0)
echo(0)

rs.EnableRedraw(0)
####################################################################
#version = "'''  ver 20200114 by _diag 4 DM* @ I OI III @ TUGraz '''"     #
version = "'''  ver 20231209 by _diag 4 DM* @ I OI III @ TUGraz '''"     #
print     "''''''''''''''''''''''''''''''''''''''''''''''''''''''''"
print     "''' _DEMlib  imported in %ss                        ''' \n%s" % (getTime(prenull=1), version) 
print     "''''''''''''''''''''''''''''''''''''''''''''''''''''''''"
############################################