#######################
#-*- coding: utf-8 -*-
'''
library 4 [DM*] @ III OI III by _diag / agruber@tugraz.at
2018/12
2022/05
2022/11
'''

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
from time import gmtime, strftime, ctime
from System.Drawing import Color
from itertools import combinations as cb # 4 convHull

import clr
clr.AddReferenceByPartialName('System.Xml')
from System.Xml import XmlTextReader, XmlNodeType, XmlReaderSettings, XmlReader
import System.Xml as xml

#import DM2_lib as dm
global timeX
timeX = time.time()

def setTime():
    global timeX
    timeX = time.time()
setTime()


def getTime(verbose=0, prenull=0):
    global timeX
    tim = float(time.time())
    tim -=  float(timeX)
    if verbose: print str(round(tim,2))+"s"
    #return preNull( round(tim,1), prenull)
    return round(tim,1)
###
### DEM & OSM utilities :
###
#ftp://ftp.glcf.umd.edu/glcf/SRTM/
#https://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_06/
#https://dds.cr.usgs.gov/srtm/version2_1/SRTM3/North_America/
### OSMi
#   https://github.com/ll--/Rhino-OSMImport
### bigggg exports
#   https://export.hotosm.org/de/v3/
### osm anaytics
#   http://osm-analytics.org/#/compare/polygon:cpj%7DAimn~Gin%40vErFyWzTJ/2012...now/buildings
# https://gis.stackexchange.com/questions/43743/extracting-elevation-from-hgt-file
#https://search.earthdata.nasa.gov/granules/download.txt?project=8306465326&collection=C1000000240-LPDAAC_ECS


### RMap projection (mercator)

# ----------------------------------------------------------------------------
# OSM routines
# ----------------------------------------------------------------------------
OSMpath = OSMfile = ''
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

move2guinea=0

def lat2coord(lat):
    global minLat
    val = (6378137.0 * math.log((math.sin(math.radians(lat))+1.0) / math.cos(math.radians(lat)))) - ( move2guinea * (6378137.0 * math.log((math.sin(math.radians(int(minLat)))+1.0) / math.cos(math.radians(int(minLat))))) )
    return val

def lon2coord(lon):
    global minLon
    val = (6378137.0 * math.radians(lon)) - ( move2guinea *(6378137.0 * math.radians(int(minLon) )) )
    #abzug = (6378137.0 * math.radians(int(lon)))
    #print val, "-", abzug, "=", val - move2guinea*abzug
    return val


global layer_conditions
def OSM_layer_condi():
    global layer_conditions
    layer_conditions = [
          # added by _diag ________________________>
          {"layer_name": "_parking", 
           "conditions": [ ["amenity", "parking"] ]},
    
          {"layer_name": "_cycling", 
           "conditions": [ ["highway", "cycleway"],
                           ['bridge','*'] ]},
          {'layer_name':'_cycling',  
           'conditions': [ ['highway','cycleway'] ]},
          {'layer_name':'_cycling',  
           'conditions': [ ['highway','cycleway'],  
                           ['embankment','*'] ]},
    
          {"layer_name": "_tststs_bicylce", 
          "conditions": [ ["amenity", "bicycle_parking"] ]},
          # added by _diag ________________________<

      {'layer_name':'buildings',  
       'conditions': [ ['building','*'] ]},
       
      # cycleways
      {'layer_name':'road_cycle_bridge',  
       'conditions': [ ['highway','cycleway'],  
                       ['bridge','*'] ]},
                       
      {'layer_name':'road_cycle_embankment',  
       'conditions': [ ['highway','cycleway'],  
                       ['embankment','*'] ]},
    
      {'layer_name':'road_cycle',  
       'conditions': [ ['highway','cycleway'] ]},
    
      # redestrian roads and paths
      {'layer_name':'pedestrian_steps',  
       'conditions': [ ['highway','steps'] ]},
      {'layer_name':'pedestrian_footway_bridge',  
       'conditions': [ ['highway','footway'],
                       ['bridge','*']  ]},
      {'layer_name':'pedestrian_footway_tunnel',  
       'conditions': [ ['highway','footway'],
                       ['tunnel','*']  ]},
      {'layer_name':'pedestrian_footway_embankment',  
       'conditions': [ ['highway','footway'],
                       ['embankment','*']  ]},
      {'layer_name':'pedestrian_footway',  
       'conditions': [ ['highway','footway'] ]},
      {'layer_name':'pedestrian_path_bridge',  
       'conditions': [ ['highway','path'],
                       ['bridge','*']  ]},
      {'layer_name':'pedestrian_path_tunnel',  
       'conditions': [ ['highway','path'],
                       ['tunnel','*']  ]},
      {'layer_name':'pedestrian_path_embankment',  
       'conditions': [ ['highway','path'],
                       ['embankment','*']  ]},
      {'layer_name':'pedestrian_path', 
       'conditions': [ ['highway','path'] ]},
      # pedestrian streets
      {'layer_name':'pedestrian_area',  
       'conditions': [ ['highway','pedestrian'],
                       ['area', '*'] ]},
      {'layer_name':'pedestrian_bridge',  
       'conditions': [ ['highway','pedestrian'],
                       ['bridge','*']  ]},
      {'layer_name':'pedestrian_tunnel',  
       'conditions': [ ['highway','pedestrian'],
                       ['tunnel','*']  ]},
      {'layer_name':'pedestrian_embankment',  
       'conditions': [ ['highway','pedestrian'],
                       ['embankment','*']  ]},
      {'layer_name':'pedestrian',  
       'conditions': [ ['highwayX','pedestrianX'] ]},
      # roads
      {'layer_name':'road_motorway_bridge',  
       'conditions': [ ['highway','motorway'],
                       ['bridge','*']  ]},
      {'layer_name':'road_motorway_tunnel',  
       'conditions': [ ['highway','motorway'],
                       ['tunnel','*']  ]},
      {'layer_name':'road_motorway_embankment',  
       'conditions': [ ['highway','motorway'],
                       ['embankment','*']  ]},
      {'layer_name':'road_motorway',  
       'conditions': [ ['highway','motorway'] ]},
      {'layer_name':'road_motorway_link',  
       'conditions': [ ['highway','motorway_link'] ]},
       
      {'layer_name':'road_trunk_bridge',  
       'conditions': [ ['highway','trunk'],
                       ['bridge','*']  ]},
      {'layer_name':'road_trunk_tunnel',  
       'conditions': [ ['highway','trunk'],
                       ['tunnel','*']  ]},
      {'layer_name':'road_trunk_embankment',  
       'conditions': [ ['highway','trunk'],
                       ['embankment','*']  ]},
      {'layer_name':'road_trunk',  
       'conditions': [ ['highway','trunk'] ]},
      {'layer_name':'road_trunk_link',  
       'conditions': [ ['highway','trunk_link'] ]},
       
      {'layer_name':'road_primary_bridge',  
       'conditions': [ ['highway','primary'],
                       ['bridge','*']  ]},
      {'layer_name':'road_primary_tunnel',  
       'conditions': [ ['highway','primary'],
                       ['tunnel','*']  ]},
      {'layer_name':'road_primary_embankment',  
       'conditions': [ ['highway','primary'],
                       ['embankment','*']  ]},
      {'layer_name':'road_primary',  
       'conditions': [ ['highway','primary'] ]},
      {'layer_name':'road_primary_link',  
       'conditions': [ ['highway','primary_link'] ]},
       
      {'layer_name':'road_secondary_bridge',  
       'conditions': [ ['highway','secondary'],
                       ['bridge','*']  ]},
      {'layer_name':'road_secondary_tunnel',  
       'conditions': [ ['highway','secondary'],
                       ['tunnel','*']  ]},
      {'layer_name':'road_secondary_embankment',  
       'conditions': [ ['highway','secondary'],
                       ['embankment','*']  ]},
      {'layer_name':'road_secondary',  
       'conditions': [ ['highway','secondary'] ]},
      {'layer_name':'road_secondary_link',  
       'conditions': [ ['highway','secondary_link'] ]},
       
      {'layer_name':'road_secondary_bridge',  
       'conditions': [ ['highway','secondary'],
                       ['bridge','*']  ]},
      {'layer_name':'road_secondary_tunnel',  
       'conditions': [ ['highway','secondary'],
                       ['tunnel','*']  ]},
      {'layer_name':'road_tertiary_embankment',  
       'conditions': [ ['highway','tertiary'],
                       ['embankment','*']  ]},
      {'layer_name':'road_tertiary',  
       'conditions': [ ['highway','tertiary'] ]},
      {'layer_name':'road_tertiary_link',  
       'conditions': [ ['highway','tertiary_link'] ]},
    
      {'layer_name':'road_track_bridge',  
       'conditions': [ ['highway','track'],
                       ['bridge','*']  ]},
      {'layer_name':'road_track_tunnel',  
       'conditions': [ ['highway','track'],
                       ['tunnel','*']  ]},
      {'layer_name':'road_track_embankment',  
       'conditions': [ ['highway','track'],
                       ['embankment','*']  ]},
      {'layer_name':'road_track',  
       'conditions': [ ['highway','track'] ]},
       
      {'layer_name':'road_residential',  
       'conditions': [ ['highway','living_street'] ]},
      {'layer_name':'road_residential',  
       'conditions': [ ['highway','residential'] ]},
       
      {'layer_name':'road_service',  
       'conditions': [ ['highway','service'] ]},
    
      {'layer_name':'road_unknown',  
       'conditions': [ ['highway','road'] ]},
       
      {'layer_name':'road_proposed',  
       'conditions': [ ['highway','proposed'] ]},
      {'layer_name':'road_proposed',  
       'conditions': [ ['highway','construction'] ]},
       
      {'layer_name':'road_other',  
       'conditions': [ ['highway','*'] ]},
        
      # railways
      {'layer_name':'railway_tram_bridge',  
       'conditions': [ ['railway','tram'],
                       ['bridge','*'] ]},
                       
      {'layer_name':'railway_tram_embankment',  
       'conditions': [ ['railway','tram'],
                       ['embankment','*'] ]},
                       
      {'layer_name':'railway_tram_tunnel',  
       'conditions': [ ['railway','tram'],
                       ['tunnel','*'] ]},
                       
      {'layer_name':'railway_tram',  
       'conditions': [ ['railway','tram'] ]},
       
      {'layer_name':'railway_subway',  
       'conditions': [ ['railway','subway'] ]},
      
      
      {'layer_name':'railway_bridge',  
       'conditions': [ ['railway','rail'],
                       ['bridge','*'] ]},
      {'layer_name':'railway_bridge',  
       'conditions': [ ['railway','light_rail'],
                       ['bridge','*'] ]},
                       
      {'layer_name':'railway_embankment',  
       'conditions': [ ['railway','rail'],
                       ['embankment','*'] ]},
      {'layer_name':'railway_embankment',  
       'conditions': [ ['railway','light_rail'],
                       ['embankment','*'] ]},
    
      {'layer_name':'railway_tunnel',  
       'conditions': [ ['railway','rail'],
                       ['tunnel','*'] ]},
      {'layer_name':'railway_tunnel',  
       'conditions': [ ['railway','light_rail'],
                       ['tunnel','*'] ]},
                       
      {'layer_name':'railway',  
       'conditions': [ ['railway','rail'] ]},
      {'layer_name':'railway',  
       'conditions': [ ['railway','light_rail'] ]},
      {'layer_name':'railway other',  
       'conditions': [ ['railway','*'] ]},
      
      # aerialways
      {"layer_name": "aerial tram", 
       "conditions": [ ["aerialway","cable_car"] ]},
      {"layer_name": "aerial tram chair", 
       "conditions": [ ["aerialway","chair_lift"] ]},
      {"layer_name": "aerial tram chair", 
       "conditions": [ ["aerialway","gondola"] ]},
      {"layer_name": "aerial tram chair", 
       "conditions": [ ["aerialway","mixed_lift"] ]},
    
      {"layer_name": "aeroway", 
       "conditions": [ ["aeroway","aerodrome"] ]},
      {"layer_name": "aeroway", 
       "conditions": [ ["aeroway","apron"] ]},
      {"layer_name": "aeroway", 
       "conditions": [ ["aeroway","helipad"] ]},
      {"layer_name": "aeroway", 
       "conditions": [ ["aeroway","runway"] ]},
      {"layer_name": "aeroway", 
       "conditions": [ ["aeroway","taxiway"] ]},
      
      # water
      {"layer_name": "water", 
       "conditions": [ ["natural","water"] ]},
      {"layer_name": "water", 
       "conditions": [ ["natural","spring"] ]},
      {"layer_name": "water", 
       "conditions": [ ["natural","riverbank"] ]},
      {"layer_name": "water", 
       "conditions": [ ["leisure","marina"] ]},
      {"layer_name": "coast", 
       "conditions": [ ["natural","coast"] ]},
      
      # green
      {"layer_name": "park", 
       "conditions": [ ["leisure","park"] ]},
      {"layer_name": "park", 
       "conditions": [ ["leisure","garden"] ]},
      {"layer_name": "park", 
       "conditions": [ ["leisure","village_green"] ]},
      {"layer_name": "forest", 
       "conditions": [ ["landuse","forest"] ]},
      {"layer_name": "forest", 
       "conditions": [ ["natural","wood"] ]},
       
      # playgrounds
      {"layer_name": "sport", 
       "conditions": [ ["leisure","pitch"] ]},
      {"layer_name": "sport", 
       "conditions": [ ["leisure","stadium"] ]},
      
      # boundary
      {"layer_name": "borders", 
       "conditions": [ ["boundary","administrative"] ]},
      
      # contours
      {"layer_name": "contours_major", 
       "conditions": [ ["contour_ext","elevation_major"] ]},
      {"layer_name": "contours_minor", 
       "conditions": [ ["contour","elevation"] ]},
      

      
      # rest
      {'layer_name':'other',  
       'conditions': [ ['*','*'] ]}
    ]
OSM_layer_condi()

# ----------------------------------------------------------------------------
# Parser & Handler
# ----------------------------------------------------------------------------    

class ipyNetParser():
    """ 
    System.Xml.XmlTextReader parser 
    """

    def __init__( self, xml_doc, root ):
        self.__reader = None
        result = None
        try:
            try:
                self.__reader = XmlTextReader( xml_doc )
                result = self.parse( root )
            finally:
                if self.__reader != None:
                    self.__reader.Close()
                del self.__reader
        except ValueError:
            raise ValueError
        return result
    
    def parse(self,element):
        r = self.__reader
        r.Read()
        while r.Read():
            if r.LocalName.Equals( element ):
                while r.Read():
                    if r.NodeType == XmlNodeType.Element:
                        self.startElement( r.LocalName )
                    elif r.NodeType == XmlNodeType.EndElement:
                        self.endElement( r.LocalName )

    def startElement( self, elementName):
        """
        Abstract method: Implemented by sub-classes to match pattern 
        on element's start

        MUST be implemented by handler subclass.
        """

    def endElement( self, elementName):
        """
        Abstract method: Implemented by sub-classes to match pattern 
        on element's end

        MUST be implemented by handler subclass.
        """

    def getAttribute( self, attrName ):
        """
        Returns value of inserted attribute.
        """
        if self.__reader.HasAttributes:
            self.__reader.MoveToAttribute(attrName)
            return self.__reader.Value

class osmNetHandler( ipyNetParser ):
    """
    A handler to deal with nodes in OSM file 

    example:
      m = osmNetHandler("~/maps/data.osm")
      for id, way in m.elements['way'].iteritems():
        #do something
    """
  
    _inside_element = None
    _relation_types = ["multipolygon", "boundary", "route"]


    def __init__( self, xml_doc ):
        self.elements = {
            "node": {},
            "way": {},
            "relation": {} 
        }
    
        for relation_type in self._relation_types:
            self.elements["relation"][relation_type] = {}
    
        self.lat = {}   
        self.lon = {}  
    
        ipyNetParser.__init__( self, xml_doc, "osm" )

    def startElement( self, name ):
        if name in ["node", "way", "relation"]:
            self._inside_element = name
            self._current_id = int(self.getAttribute("id"))
            self._current_attributes = {}
            self._current_children = []
      
            if name == "node":
                self.lat[self._current_id]=float(self.getAttribute("lat"))
                self.lon[self._current_id]=float(self.getAttribute("lon"))
            elif name == "relation":
                self._relation_type = None
                self._outer_members = []
        
        elif self._inside_element:
            if name in ["nd", "member"]:
                # ignore other children [ehm nodes?] of relation than way
                if name == "member" and self.getAttribute("type") != "way":
                    return
                ref = int(self.getAttribute("ref"))
                self._current_children.append(ref)
                if name == "member" and self.getAttribute("role") == "outer":
                    self._outer_members.append(ref)
        
            elif name == "tag":
                attr_key = self.getAttribute("k")
                if attr_key == "created_by":
                    return

                self._current_attributes[attr_key]=self.getAttribute("v")
                if self._inside_element == "relation" and \
                   self.getAttribute("v") in self._relation_types:
                    self._relation_type = self.getAttribute("v")
    
    
    def endElement(self, name):
        id = self._current_id
        if name in ["node", "way", "relation"]:
            self._inside_element = None
      
            # ignore unattributed nodes
            if name == "node" and self._current_attributes:
                return
      
            element = {
                "attributes": self._current_attributes
            }
      
            if name != "node":
                element["children"] = self._current_children
      
            if name == "relation":
                if self._relation_type:
                    if self._relation_type == "multipolygon":
                        element["outer_members"] = self._outer_members
                    self.elements[name][self._relation_type][id] = element
            else:
                self.elements[name][id] = element
      

# ----------------------------------------------------------------------------
# Rhino routines
# ----------------------------------------------------------------------------

def getLayerName(attributes):
    layer_name = 'Default'
    global layer_conditions
    for layer_condition in layer_conditions:
        pass_layer = False
        for condition in layer_condition["conditions"]:
            if condition[0] != "*" and condition[0] not in attributes:
                pass_layer = True
            elif condition[1] != '*' and attributes[condition[0]] != condition[1]:
                pass_layer = True
    
        if not pass_layer:
            return layer_condition["layer_name"]
    return layer_name
    
def getWayPoints(children_id, model):
    """Get way nodes and project coordiates
    """
    lon = model.lon
    lat = model.lat
    result = []
    for x in children_id:
        if x in lon and x in lat:
            result.append([lon2coord(lon[x]), lat2coord(lat[x]), 0])
    return result
    
def createCurve(waypoints, layer=None):
    #print waypoints
    if not waypoints or len(waypoints) < 2:
        return
    elif len(waypoints) <= 3 and waypoints[0][:] == waypoints[-1][:]:
        return
    curve = rs.AddPolyline(waypoints)
    
    if curve and layer:
        rs.ObjectLayer(curve, layer)
        #curve = rs.ScaleObject(curve, [0,0,0], [2,2,2], copy=False)
        #print "CU____"
    return curve

def _ag_layerColors():
    layerNames = rs.LayerNames()
    if layerNames:
        for name in layerNames:
            #rs.LayerColor(name, randomcolor())
            if name.count("OSM"): rs.LayerVisible(name, 1)
            if name == "OSM::buildings": rs.LayerColor(name,(255,0,0))
            if name == "OSM::buildings::_bldg": rs.LayerColor(name,(255,0,0))
            if name == "OSM::buildings::_bldg3D_crv": rs.LayerColor(name,(255,0,0))
            if name == "OSM::buildings::_bldg3D_srf": rs.LayerColor(name,(100,150,200))

            if name == "OSM::forest"   : rs.LayerColor(name,(0,160,0))
            if name == "OSM::park"     : rs.LayerColor(name,(200,240,40))
            if name == "OSM::water"    : rs.LayerColor(name,(40,100,240))
            if name == "OSM::sport"    : rs.LayerColor(name,(240,80,40))
            if name == "OSM::other"    : rs.LayerColor(name,(200,10,200))
            if name == "OSM::_parking"   : rs.LayerColor(name,(240,140,0))
            if name == "OSM::_railway"   : rs.LayerColor(name,(240,240,40))
            if name == "OSM::_road"      : rs.LayerColor(name,(240,240,240))
            if name == "OSM::_cycling"   : rs.LayerColor(name,(240,140,120))

def _ag_diverseLayers():
    rs.AddLayer("OSM::diverses", [200,0,200])
    for lay in rs.LayerNames():
        #print lay
        if "OSM::" in lay and not "buildings" in lay and not "diverses" in lay:
            #print lay
            rs.AddLayer(lay[5:],color=rs.LayerColor(lay),parent="OSM::diverses")
            rs.ObjectLayer( rs.ObjectsByLayer(lay), "OSM::diverses::"+lay[5:])
            rs.DeleteLayer(lay)
    if 1:
        for lay in rs.LayerNames():
            if 1 and lay[5:] in ["water", "forest", "park", "sport", "other"]:
                rs.DeleteLayer(lay[5:])
    rs.ExpandLayer( "OSM", 1 )
    rs.ExpandLayer( "OSM::diverses", 0 )



def OSMi(OSMfile, OSMpath, do3D=1, minHeight=3.0, heightFac = 1.0, trimBounds=0, randomize=[0.0, 0.0], doAllCurves=1,  verbose=0):
    OSM_overpass_testAndChange(OSMpath, OSMfile, 1)
    OSM_getBounds(OSMfile, OSMpath, drawRect=0, trim=0, verbose=0)
    #    global minLat
    #    global minLon
    #    global maxHeight
    maxHeight = 0.0
    ### << need 4 guinea_move
    # ------------------------------------------------------------------------
    # additional layers
    rs.AddLayer("OSM")
    rs.AddLayer("buildings",  [255, 0, 0]    , parent="OSM" )
    rs.AddLayer("_bldg",   [255, 0, 0]    , parent="OSM::buildings" )
    rs.AddLayer("_bldg3D_crv",   [255, 0, 0]    , parent="OSM::buildings" )
    rs.AddLayer("_bldg3D_srf",   [50, 150, 200] , parent="OSM::buildings" )
    rs.AddLayer("_road",      [250, 240, 220], parent="OSM")
    rs.AddLayer("_railway",   [240, 240, 240], parent="OSM")
    rs.AddLayer("_pedestrian",[140, 240, 240], parent="OSM")
    # default layer:
    initial_layers = rs.LayerNames()
    global layer_conditions
    for layer_condition in layer_conditions:
        rs.AddLayer(layer_condition["layer_name"], parent="OSM" )
    # ------------------------------------------------------------------------ 
    # initial Rhino settings
    ###diag:
    setTime()
    existingObjects = []
    for obj in rs.AllObjects(): existingObjects.append(rs.ObjectName(obj))
    vorher = len(rs.AllObjects())
    rs.EnableRedraw(0)
    ###diag
    # ------------------------------------------------------------------------ 
    # get datamodel
    if not OSMfile:
        OSMfile = rs.OpenFileName()
    if not OSMfile:
        return
    osm_model = osmNetHandler(OSMpath+OSMfile)
    model_elements = osm_model.elements
    used_ways = []
    for id, relation in model_elements['relation']['multipolygon'].iteritems():
        curves = []
        # obtain layer_name
        layer_name = getLayerName(relation["attributes"]) 
        if layer_name in ["Default", "other"]:
            for outer_member in relation["outer_members"]:
                if outer_member not in model_elements['way']:
                  continue
                layer_name = getLayerName(
                    model_elements['way'][outer_member]["attributes"])
                if layer_name not in ["Default", "other"]:
                    break
        # for child in children
        for way_id in relation["children"]:
            used_ways.append(way_id)
            if way_id not in model_elements["way"]:
                continue
            waypoints = getWayPoints(
                model_elements["way"][way_id]["children"], osm_model)
            curve = ""
            if doAllCurves and not existingObjects.count("Wcrv_"+str(way_id)):
                curve = createCurve(waypoints, layer_name)
            if curve:
                rs.ObjectName(curve, "Wcrv_"+str(way_id))
                existingObjects.append("Wcrv_"+str(way_id))
    # ------------------------------------------------------------------------
    # create ways ... ONLY WAYS !
    rs.UnselectAllObjects()
    esc()
    for id, way in model_elements['way'].iteritems():
        esc()
        if id in used_ways:
            continue
        waypoints = getWayPoints(way["children"], osm_model)
        ### diag:
        if not existingObjects.count("crv_"+str(id)) and not existingObjects.count("_bldg3D_crv_"+str(id)):
            if doAllCurves:
                #print len(waypoints)
                curve = createCurve(waypoints, getLayerName(way["attributes"])) # layer names match 
                rs.ObjectName(curve, "crv_"+str(id))
            line = model_elements['way'][id]["attributes"]
            if 0 and verbose: print "\nID",id,":",

            height=0.0
            floorHeight=3.0
            colCode = 0
            higMeth = "nul"
            if 1 or do3D:
                for item in line:
                    if 0 and verbose: print "line_item:", item, line[item],
                    if 1 and item == "building":
                        height = rand(randomize[0], randomize[1])
                        colCode = 1
                        higMeth = "ran"
                    hightF = hightH = 1.0
                    if 1 and item == "height":
                        height = line[item]
                        height = height.replace(" m", "")
                        height = height.replace("m", "")
                        height = height.replace(" c", "")
                        height = height.replace("c", "")
                        height = height.replace("<", "")
                        height = height.replace(";", ".")
                        if height.count("c") or height.count("f") :
                            floors=0.0 #print "\n_________________CM found_________________"
                        colCode = 3
                        higMeth = "hig"
                        
                        hightH = float(height)

                        #if height.isnumeric():height = float(height)
                        #else:height = 0.0
                        #print "hightH", hightH
                        
                    if 1 and item == "building:levels":
                        floors = line[item]
                        floors = floors.replace(";", "")
                        floors = floors.replace("c", "")
                        floors = floors.replace(" c", "")
                        floors = floors.replace("C", "")
                        floors = floors.replace(" ", "")
                        floors = floors.replace("EG", "")
                        if floors.count("-"):
                            floors = 0.0
                        if floors:
                            #print floors, id
                            if len(floors)>3: floors=0.0
                            floors = float(floors)
                            #if floors.isnumeric():
                            #    floors = float(floors)
                        else:
                            floors = 0.0
                        if id==261256941 or id==137989966: # UN building
                            floorHeight=4.0
                        height = floors*floorHeight
                        hightF = float(height)
                        #if 1 or  id==261256941: print "F", hightF
                        colCode = 2
                        higMeth = "flo"
                        #print "flo", hightF 

                    if float(height) > maxHeight: maxHeight = float(height)*heightFac
            if float(height) > minHeight and (waypoints[0] == waypoints[-1]) or id==241833352: ## cooper union # check if closed: if not > no good boolin'
                if verbose: print "____3D_srf_height", height
                if not doAllCurves:
                    curve = createCurve(waypoints, getLayerName(way["attributes"]))
                rs.ObjectName(curve, "_bldg3D_crv_"+str(id))
                rs.ObjectLayer(curve, "OSM::buildings::_bldg3D_crv")
                if len(rs.ObjectsByLayer("OSM::buildings::_bldg3D_crv")) % 16==0: rs.Redraw()
                height = float(height)
                if do3D:
                    if id==34633854:  height = 1.0 # empire state base
                    if id==260904072: height = 1.0 # chrysler base
                    if id==713565776: height = 1.0 # WTC base
                    bldg=rs.ExtrudeCurveStraight(curve, [0,0,0], [0,0, height*heightFac]) 
                    rs.CapPlanarHoles(bldg)
                    name = "_bldg3D_higBy_"+higMeth+"_"+str(id)
                    rs.ObjectName(bldg, name)
                    rs.ObjectLayer(bldg, "OSM::buildings::_bldg3D_srf")
                    rs.ObjectColor(bldg, [250-80*colCode, 100, 80*colCode])
    if len( rs.AllObjects() ) % 100 == 0:
        rs.ZoomExtents()
        rs.Redraw()

    ###diag:
    _ag_layerColors()
    rs.ObjectLayer( rs.ObjectsByLayer("OSM::buildings"), "OSM::buildings::_bldg") # 20180516 @ diag
    rs.ObjectsByLayer("OSM::buildings::_bldg", 1)
    rs.ObjectsByLayer("OSM::buildings::_bldg3D_srf", 1)
    rs.ZoomSelected()
    rs.UnselectAllObjects()
    rs.AddLayer( "Default" )
    rs.CurrentLayer( "Default" )
    rs.DeleteLayer( "OSM" ) # 20180516 @ diag
    #if trimBounds:
    OSM_getBounds(OSMfile, OSMpath=OSMpath, drawRect=1, trim=trimBounds, verbose=0)
    # OSM_makeSrf( ["water", "forest", "park", "sport", "other"] ) # 20180516 @ diag
    nacher = len(rs.AllObjects())
    print "||| OSMi_mport:", OSMfile
    print "||| total objects vorher/nachher:", str(vorher)+"/"+str(nacher), "new =", (nacher - vorher),
    print " ||| done in", str(getTime())+"s\n"
    echo(1)

    ###############################################
    ######### 2022 05 18 ### remove innenhoefe u.a.
    if do3D and "OSM::buildings::_bldg" in rs.LayerNames():
        rs.AddLayer( "OSM::buildings::_bldg3D_srf", [200,0,0])
        rs.DeleteObjects(rs.ObjectsByName("*inner*"))
        allCrvs = rs.ObjectsByLayer("OSM::buildings::_bldg")
        for i,crv in enumerate(allCrvs[0:]):
            if not rs.IsCurveClosed(crv):
                allCrvs.remove(crv)
        rs.EnableRedraw(0)
        rs.UnselectAllObjects()
        innerCrvs = []
        for i,crv in enumerate(allCrvs[0:]):
            esc()
            if i%16==0: rs.Redraw()
            if crv not in innerCrvs:
                outerNam = rs.ObjectName( crv ).split("_")[1]
                rs.UnselectAllObjects()
                rs.Command("-_SelBoundary SelectionMode=Window  Precise=Yes selID "+str(crv)+" enter enter", 0)
                if rs.SelectedObjects():
                    for item in rs.SelectedObjects():
                        if rs.ObjectType( item ) == 4 and item in allCrvs:
                            innerCrvs.append( item )
                            allCrvs.remove(item)
                        else:
                            rs.UnselectObject(item)
                    if rs.SelectedObjects():
                        rs.SelectObject(crv)
                        height = rand(randomize[0], randomize[1])
                        rs.Command("_ExtrudeCrv Output=Surface BothSides=No DeleteInput=No Solid=Yes "+str(height)+" enter", 0)
                        #obj=rs.ExtrudeCurveStraight(crv, [0,0,0], [0,0, height])
                        obj = rs.AllObjects()[0]
                        cenZ = rs.SurfaceAreaCentroid(obj)[0][2]
                        if cenZ<0:
                            rs.MoveObject(obj, [0,0,height])
                        rs.ObjectColor(obj, [200,180,100])
                        rs.ObjectName(obj, "_bldg3D_higBy_ran_inner_"+outerNam)
                        rs.ObjectLayer(obj, "OSM::buildings::_bldg3D_srf")
    rs.UnselectAllObjects()
    ### behuebschung der layerstructure / 2022 11 30 / _diag
    _ag_diverseLayers()


def OSM_getBounds(OSMfile=OSMfile, OSMpath=OSMpath, drawRect=1, trim=1, verbose=0):
    global minLat
    global minLon
    echo(0)
    settings = XmlReaderSettings()
    settings.IgnoreWhitespace = True
    reader = XmlReader.Create(OSMpath+OSMfile, settings)
    reader.ReadToFollowing("bounds")
    minLon = float(reader.GetAttribute("minlon"))
    #minLon -= move2guinea * minLon
    minLat = float(reader.GetAttribute("minlat"))
    #minLat -= move2guinea * minLon
    maxLon = float(reader.GetAttribute("maxlon"))
    maxLat = float(reader.GetAttribute("maxlat"))
    if verbose:
        print OSMfile[0:-4],
        print "\t: minLon/minLat "+str(round(minLon,4))+"°/"+str(round(minLat,4))+"°",
    minlon= lon2coord(minLon)
    maxlon= lon2coord(maxLon)
    minlat= lat2coord(minLat)
    maxlat= lat2coord(maxLat)
    if verbose: print " >> ", round(minlon*0.001,2),"/", round(minlat*0.001,2), "kilometers from guinea (East/North => x/y !)"
    if drawRect:
        rs.AddLayer("OSM")
        rs.Command("cplane W T enter", 0)
        rs.ZoomExtents()
        rec = rs.AddRectangle([minlon, minlat,0], (maxlon-minlon), (maxlat-minlat))
        rs.ObjectName( rec, "bounds_"+OSMfile[0:-4])
        rs.ObjectColor(rec, [0,191,191])
        rs.ObjectLayer(rec, "OSM")
        if drawRect and trim:
            rs.UnselectAllObjects()
            for obj in rs.AllObjects():
                if rs.ObjectType(obj) != 4 or rs.IsCurveClosed(obj):
                    rs.HideObject( obj )
            rs.UnselectAllObjects()
            rs.AllObjects(select=1)
            rs.ShowObject( rec )
            if rs.SelectedObjects():
                rs.Command("_-split selid "+str(rec)+" enter", 0)
            offsetted = rs.OffsetCurve( rec, [-1,-1, 0], 0.1 )[0]
            rs.ObjectColor( offsetted, [200,0,0])
            rs.UnselectAllObjects()
            rs.Command("_selBoundary SelectionMode=W Precise=Yes selid "+str(offsetted)+" -enter invert enter delete enter", 0)# -enter invert 
            rs.ShowObjects(rs.AllObjects())
    return [[minlon, minlat,0],[maxlon, minlat,0], [maxlon, maxlat,0], [minlon, maxlat,0]]# , [minlon, minlat,0]]


def OSM_way_checker(OSMfile, OSMpath=OSMpath, checkKey="value", checkVal="value", verbose=0):
    print "\n||| diag's OSM_way_checker checking @", OSMfile
    settings = XmlReaderSettings()
    settings.IgnoreWhitespace = True
    OSMfile = OSMpath+OSMfile
    reader = XmlReader.Create(OSMfile, settings)
    crvs=[]
    cnt = 0
    while reader.ReadToFollowing("osm"):
        reader.ReadStartElement()
        while reader.ReadToNextSibling("way") and cnt < 1000001:
            id = reader.GetAttribute("id")
            while reader.ReadToDescendant("tag"):
                i=0
                #print id, "tag_k"+str(i), reader.GetAttribute("k")
                if reader.GetAttribute("k").count(checkKey) or checkVal in reader.GetAttribute("v"):
                    #print id, "_____", reader.GetAttribute("k"), reader.GetAttribute("v")
                    cnt += 1
                    if rs.ObjectsByName("*_"+id)[0] and rs.ObjectType(rs.ObjectsByName("*_"+id)[0]) == 4:
                        crvs.append(rs.ObjectsByName("*_"+id)[0])
                        #print "len crvs", len(crvs)
                    if verbose: print id, cnt, "k", reader.GetAttribute("k"), " v:", reader.GetAttribute("v")#, "=> crv_"+id
                    if verbose==3: print id, "__", len(rs.ObjectsByName("crv_"+id))
                while 1 and reader.ReadToNextSibling("tag"):
                    i += 1
                    #print "__tag_k"+str(i), reader.GetAttribute("k")
                    # ori: if reader.GetAttribute("k").count(checkKey) and reader.GetAttribute("v").count("*"+checkVal+"*"):
                    if reader.GetAttribute("k").count(checkKey) or checkVal in reader.GetAttribute("v"):#.count("*"+checkVal+"*"):
                        cnt += 1
                        if rs.ObjectsByName("*_"+id)[0] and rs.ObjectType(rs.ObjectsByName("*_"+id)[0]) == 4 :
                            crvs.append(rs.ObjectsByName("*_"+id)[0])
                        if verbose==2: OSM_findID( id, verbose=1 )
                        if verbose: print id, cnt, "k", reader.GetAttribute("k"), " v:", reader.GetAttribute("v")#, "=> crv_"+id
                        if verbose==3: print id, "__", len(rs.ObjectsByName("crv_"+id))
                while reader.IsStartElement():reader.Skip()
    print "||| diag's OSM_way_checker  found",cnt,"WAYs  with key \""+checkKey+"\" OR val \""+checkVal+"\""
    reader.Close()
    return crvs
### USAge
#print OSM_nodeChecker("graz_grieskai_0.osm", OSMpath = OSMpath,  attributeX="bicycle_parking")[0]


def OSM_node_checker(OSMfile, OSMpath = "L:\\OSM\\", checkKey="diag", checkVal="diag", andOr = "or", verbose=1):
    #print "::: OSM_node_checker:"#, OSMfile[0:-4], "- check k=\""+str(checkKey)+"\" |", andOr.upper(),"| v=\""+checkVal+"\""
    print "\n||| diag's OSM_node_checker checking @", OSMfile
    global minLon
    global minLat
    OSM_getBounds(OSMfile, OSMpath, drawRect=0, trim=0, verbose=0)
    settings = XmlReaderSettings()
    settings.IgnoreWhitespace = True
    OSMfile = OSMpath+OSMfile
    
    reader = XmlReader.Create(OSMfile, settings)
    IDs = []
    coords = []
    cnt = 0
    ### NODE
    while reader.ReadToFollowing("osm"):
            reader.ReadStartElement()
            while reader.ReadToNextSibling("node"): ### was node
                lon= lon2coord(float(reader.GetAttribute("lon")))
                lat= lat2coord(float(reader.GetAttribute("lat")))
                id = reader.GetAttribute("id")
                if reader.ReadToDescendant("tag") and reader.GetAttribute("k") != "created_by":
                    if andOr == "or":
                        if reader.GetAttribute("k").count(checkKey) or reader.GetAttribute("v").count(checkVal):
                            if verbose: print id,"\t", cnt,"k="+reader.GetAttribute("k"), " v="+reader.GetAttribute("v")
                            cnt += 1
                            coords.append([lon,lat,0])
                        while reader.ReadToNextSibling("tag"):
                            if reader.GetAttribute("k").count(checkKey) or reader.GetAttribute("v").count(checkVal):
                                if verbose: print id,"\t", cnt,"k="+reader.GetAttribute("k"), " v="+reader.GetAttribute("v")
                                cnt += 1
                                coords.append([lon,lat,0])
                                IDs.append( id )
                                #print "ID - ", id
                        while reader.IsStartElement():reader.Skip()
                    if andOr == "and":
                        if reader.GetAttribute("k").count(checkKey) and reader.GetAttribute("v").count(checkVal):
                            if verbose: print id,"\t", cnt,"k="+reader.GetAttribute("k"), " v="+reader.GetAttribute("v")
                            cnt += 1
                            coords.append([lon,lat,0])
                        while reader.ReadToNextSibling("tag"):
                            if reader.GetAttribute("k").count(checkKey) and reader.GetAttribute("v").count(checkVal):
                                if verbose: print id,"\t", cnt,"k="+reader.GetAttribute("k"), " v="+reader.GetAttribute("v")
                                cnt += 1
                                coords.append([lon,lat,0])
                                IDs.append( id )
                        while reader.IsStartElement():reader.Skip()
    reader.Close()
    if len(coords):
        coords = rs.CullDuplicatePoints(coords, tolerance=0.00000001)
    #print cnt, "findings >",len(coords),"coords\n'''''''''''''''''''''''''''''"
    print "||| diag's OSM_node_checker found", cnt, "NODEs ("+str(len(coords))+" coords) with k=\""+checkKey+"\" "+str.upper(andOr)+" val=\""+checkVal+"\""

    if 0 and verbose:
        print "*** coords:"
        print "coords = [",
        for cor in coords: print "["+str(cor)+"],",
        print "] \n|||||||||||||||||||||||||||||"
    if 0 and verbose and len(IDs):
        IDs = set(IDs)
        print "*** IDs:"
        print "IDs = [",
        for id in IDs: print id,",",
        print "] \n|||||||||||||||||||||||||||||"
    return coords

### USAge
#if 1: coords = OSM_node_checker("cooper_square", OSMpath = "L:\\OSM\\", checkKey="diag", checkVal="diag", andOr = "or", verbose=1)
#   print len(coords)


def OSM_ID_checker(OSMfile, OSMpath=OSMpath, checkID="value", verbose=0):
    print "||| diag's ID_checker checking @", OSMfile, ">>> ID", checkID
    settings = XmlReaderSettings()
    settings.IgnoreWhitespace = True
    OSMfile = OSMpath+OSMfile
    reader = XmlReader.Create(OSMfile, settings)
    crvs=[]
    cnt = 0
    while reader.ReadToFollowing("osm"):
        reader.ReadStartElement()
        while reader.ReadToNextSibling("way") and cnt < 1000001:
            id = reader.GetAttribute("id")
            #id = reader.GetAttribute("ref")
            if id == checkID:
                while reader.ReadToDescendant("tag"):
                    i=-1
                    key = reader.GetAttribute("k")
                    val = reader.GetAttribute("v")
                    cnt += 1
                    if rs.ObjectsByName("*_"+id):crvs.extend(rs.ObjectsByName("*_"+id))
                    print cnt, "\tk:", key, "\t v:", val#, "=> crv_"+id
                    while 1 and reader.ReadToNextSibling("tag"):
                        key = reader.GetAttribute("k")
                        val = reader.GetAttribute("v")
                        cnt += 1
                        if rs.ObjectsByName("*_"+id):crvs.extend(rs.ObjectsByName("*_"+id))
                        print cnt, "\ttk:", key, "\t v:", val#, "=> crv_"+id
    if not cnt:
        print "*** ID ", checkID, ": \tno findings @ ", OSMfile
    reader.Close()
    rs.SelectObjects(crvs)
    rs.ZoomSelected()

### USAge
# OSM_ID_checker(OSMfile, OSMpath=OSMpath, checkID="464974861", verbose=0)


def OSM_markCoords(coords, hig=50, rad=10, lay="_node_marks", color=[0,255,255], doDelete=1):
    rs.EnableRedraw(0)
    rs.AddLayer(lay, [200,0,200], parent="OSM")
    rs.CurrentLayer(lay)
    if doDelete: rs.DeleteObjects(rs.ObjectsByLayer(lay))
    rs.Redraw()
    for i, cor in enumerate(coords):
        #srfs=rs.ExplodePolysurfaces( rs.AddCone([cor[0],cor[1],0], hig, rad), 1)
        #rs.ObjectColor(srfs[1], color)#
        srfs= rs.AddCone([cor[0],cor[1],0], hig, rad)
        rgbMat2Obj(srfs, color[0], color[1], color[2])
    rs.Redraw()


def OSM_makeSrf( layerz ):
    for lay in layerz:
        for nam in rs.LayerNames():
            if "OSM::diverses::"+lay == nam:
                newNam = nam+"::_"+lay+"_srf"
                print "found :", nam,">>", newNam
                rs.AddLayer("_"+lay+"_srf", rs.LayerColor(nam),  parent=nam)
                rs.DeleteObjects( rs.ObjectsByLayer(newNam) )
                rs.CurrentLayer( newNam )
                crvs = rs.ObjectsByLayer(nam)
                for crv in crvs:
                    if rs.IsCurveClosed( crv ):
                        id  = rs.ObjectName(crv)[4:]
                        srf = rs.AddPlanarSrf( crv )
                        #rgbMat2Obj( srf, rs.ColorRedValue(rs.LayerColor(nam)), rs.ColorGreenValue(rs.LayerColor(nam)), rs.ColorBlueValue(rs.LayerColor(nam)) )
                        #print id, srf
                        if srf:
                            rs.ObjectName( srf, "_"+lay+"_"+str(id) )
                            rs.FlipSurface( srf, True)
                            if lay == "other": rs.MoveObject(srf, [0,0,-0.1])
                            if lay == "park":  rs.MoveObject(srf, [0,0,0.1])
                        if 0 and not rs.IsCurveClosed(crv):
                            print "nixi",nam, id
                            rs.SelectObject( crv )
    rs.CurrentLayer( "Default" )
### USAge
#OSM_makeSrf( ["water", "forest", "park", "sport", "other"] )


# newLay must be like "_railway", "_road"
def makeOSM_additionalLayer (newLay, color=[250,200,0], height=10):
    rs.AddLayer(newLay, color, parent="OSM")
    rs.AddLayer(newLay+"_srf", rs.LayerColor("OSM::"+newLay), parent="OSM::"+newLay)
    crvs = []
    for name in rs.LayerNames():
         if name.count(newLay[1:]) and name != ("OSM::"+newLay):
            #print "\tname___",name,"count ", name.count("OSM::"+namY)
            crvs.extend(rs.ObjectsByLayer(name))
    for crv in crvs:
        if rs.ObjectType(crv) == 4:
            srf=rs.ExtrudeCurveStraight(crv, [0,0,0], [0,0, height])
            rs.ObjectLayer(srf, "OSM::"+newLay+"::"+newLay+"_srf")

### USAge
#makeOSM_additionalLayer("_railway", [200,200,0], height=5)
#makeOSM_additionalLayer("_road", [100,200,0], height=5)
#makeOSM_additionalLayer("_road_resi", [250,200,0], height=25)
#makeOSM_additionalLayer("_road_seco", [250,200,0], height=25)



def OSM_makeAllClosedCrvs():
    rs.DeleteObjects(rs.ObjectsByLayer("Default"))
    for crv in rs.ObjectsByType( 4 ):
        if rs.IsCurveClosed(crv) and not rs.ObjectLayer(crv).count("buildings") and rs.ObjectLayer(crv) != "OSM":
            srf = rs.AddPlanarSrf( crv )
            rs.MoveObject( srf, [0,0, -0.2])
            rs.ObjectColor( srf, [0,100,100])
            #rgbMat2Obj( srf, 0, 100, 100 )
            rs.ObjectName( srf, "_all_"+str(rs.ObjectName(crv)[4:]) )



def OSM_findID( findID, verbose=1):
    print "+++ crv_"+findID, "=", len(rs.ObjectsByName("crv_"+findID)),"finded"
    #rs.UnselectAllObjects()
    rs.SelectObject(rs.ObjectsByName("crv_"+findID))
    rs.ZoomSelected()
###USAge
#  OSM_findID( "107403224" )
def OSM_split_bounds():
    splitter = rs.ObjectsByName("bounds_*")[0]
    nam = rs.ObjectName(splitter)
    for crv in rs.ObjectsByType(4):
        if rs.IsCurveClosed(crv)==False:
            rs.Command("split  -SelId {} enter -SelId {} enter".format( crv, splitter))
    splitterX = rs.OffsetCurve(splitter, [0,0,0], -0.0001)[0]
    splitter  = rs.OffsetCurve(splitter, [0,0,0], -0.00015)[0]
    rs.ObjectName(splitter, nam)
    rs.ObjectColor(splitter, [127,255,191])
    rs.Command("selBoundary SelectionMode=C selid "+str(splitterX)+" invert delete",False)
    

def OSM_combinat(baseCurves=[], parent=0):
    lay = "_combinat"
    if parent: newEmptyLayer (lay, [150, 110, 50], parent="OSM::buildings")
    else: newEmptyLayer (lay, [150, 110, 50])
    if not baseCurves:
        baseCurves = rs.ObjectsByLayer("OSM::buildings")
        baseCurves.extend (rs.ObjectsByLayer("OSM::buildings::_bldg3D_crv"))
    srfs = rs.AddPlanarSrf( baseCurves )
    srfs = rs.BooleanUnion(srfs, delete_input=True)
    #rs.SelectObjects(srfs)
    if 1 or srfs:
        for srf in srfs:
            borders = rs.DuplicateSurfaceBorder(srf, type=1)
            #char_curves.append(max(borders, key = rs.CurveArea))
            rs.LockObjects(max(borders, key = rs.CurveArea))
        rs.DeleteObjects(rs.ObjectsByLayer(lay))
        rs.UnlockObjects(rs.AllObjects())
    rs.CurrentLayer("Default")
    if parent: return rs.ObjectsByLayer("OSM::buildings::"+lay)
    else: return rs.ObjectsByLayer(lay)
    



def OSM_bool(): 
    ## try 20200114
    rs.UnitAbsoluteTolerance( 0.00001 )
    currView = rs.CurrentView("Top",  return_name=True)
    currMode = rs.ViewDisplayMode(view=None, mode="Wireframe", return_name=True)
    #rs.ZoomExtents()
    newEmptyLayer("booled", [100,0,200])
    for lay in rs.LayerNames():
        if "buildings" in lay or "booled" in lay or lay=="OSM":
            pass
        else:
            rs.LayerVisible( lay, 0 )
    rs.LayerVisible( "OSM::buildings::_bldg", 0 )
    rs.LayerVisible( "OSM::buildings::_bldg3D_srf", 0 )
    if 1:
        rs.UnselectAllObjects()
        for bor in rs.ObjectsByName("_bldg3D_crv_*")[0:]: #rs.ObjectsByName("bor")[0:]:
            rs.Command("selboundary SelectionMode=Window -selID "+str(bor)+" enter ", 0)
        rs.DeleteObjects( rs.SelectedObjects() )
        crvs = rs.ObjectsByName("_bldg3D_crv_*")
        for crv in crvs:
            rs.ObjectName( rs.AddPlanarSrf( crv ), "planSrf")
    if 1:
        rs.SelectObjects( rs.ObjectsByName("planSrf") )
        rs.Command(" join enter", 0 )
        rs.UnselectAllObjects()
        for srf in rs.ObjectsByName("planSrf"):
            rs.ObjectName(rs.DuplicateSurfaceBorder(srf), "bor" )
        rs.DeleteObjects( rs.ObjectsByName("planSrf") )

    if 1:
        rs.LayerVisible( "OSM::buildings::_bldg3D_srf", 1 )
        rs.LayerVisible( "OSM::buildings::_bldg3D_crv", 0 )
        rs.UnselectAllObjects()
        for bor in rs.ObjectsByName("bor")[0:]:
            off = rs.OffsetCurve( bor, [0,0,0], 0.01 )[0]
            #offi = rs.OffsetCurve( bor, [0,0,0], -0.1 )[0]
            rs.ObjectName(off, "off" )
            #rs.ObjectName(offa, "bor" )
            rs.UnselectAllObjects()
            rs.Command("selboundary SelectionMode=Crossing Precise=Yes -selID "+str(off)+" enter ", 0)
            rs.Command("selboundary SelectionMode=Crossing Precise=Yes -selID "+str(bor)+" enter ", 0)
            rs.UnselectObjects( rs.ObjectsByType( 4 ) )
            rs.Redraw()
            if len(rs.SelectedObjects()) > 1:
                for sel in rs.SelectedObjects():
                    rs.MoveObject( sel, [0,0,random.uniform(-1.0, 1.0)] )
                rs.BooleanUnion( rs.SelectedObjects(), delete_input=0)
            if len(rs.SelectedObjects()) == 1:
                rs.ObjectLayer(rs.CopyObject(rs.SelectedObjects()[0]), "booled")
                
    rs.DeleteObjects( rs.ObjectsByName("bor") )
    rs.DeleteObjects( rs.ObjectsByName("off") )
    rs.CurrentLayer( "Default" )
    currView = rs.CurrentView(currView,  return_name=True)
    currMode = rs.ViewDisplayMode(view=None, mode=currMode, return_name=True)
    rs.UnitAbsoluteTolerance( 0.00001 )
#USAge
#OSM_bool()


def OSM_bool(objects2bool=[], dele=0):
    lay = "_booled"
    rs.AddLayer (lay, [100, 0, 250])
    rs.CurrentLayer( lay )
    #rgbMat2Lay( lay, 100, 0, 250, 0.3, 0, 0.5, "_booled" )
    _2bool = []
    rs.UnitAbsoluteTolerance( 0.1 )
    if not objects2bool:
        objects2bool=rs.ObjectsByLayer("OSM::buildings::_bldg3D_srf")
    print "objects2bool =", len(objects2bool)
    rnd = 0.2
    for obj in objects2bool:
        if rs.ObjectType(obj)==16:# or (rs.ObjectType(obj)==8 and rs.IsSurfaceClosed(obj, 0) and rs.IsSurfaceClosed(obj, 1)):# 
            _2bool.append(obj)
            #rs.SelectObject(obj)
            rs.MoveObject( obj, [rand(-rnd, rnd),rand(-rnd, rnd), rand(rnd)] )
    print "_2bool", len( _2bool )
    #random.shuffle( _2bool )
    #booled = rs.BooleanUnion(_2bool, dele)
    rs.UnselectAllObjects()
    rs.SelectObjects( _2bool )
    rs.Command("_BooleanUnion enter enter", 1)
    rs.UnitAbsoluteTolerance( 0.00001 )
    cnt = 0
    for boo in rs.ObjectsByLayer("_booled"):
        rs.ObjectName( boo, "booled_"+str(cnt) )
        cnt+=1
        print cnt,
    return rs.ObjectsByLayer("_booled")


def OSM_buildingHeightByCurveDistance( baseCurves=[], bldgVon=0, bldgPlus=20, chkCurves=[], reverse=0, exponent=1, verbose=1):
    global maxHeight
    newEmptyLayer ("_newBuildings", [150, 110, 50])
    newEmptyLayer ("_newBuildings_crv", [250, 10, 10], parent="_newBuildings")
    newEmptyLayer ("_newBuildings_srf", [10, 10, 10],  parent="_newBuildings")
    if not baseCurves:
        baseCurves = rs.ObjectsByLayer("OSM::buildings")
        baseCurves.extend (rs.ObjectsByLayer("OSM::buildings::_bldg3D_crv"))
    distList = []
    centers  = []
    #for i, obj in enumerate(baseCurves[ bldgVon : bldgVon+bldgPlus]):
    for i, obj in enumerate(baseCurves):
        if rs.IsCurveClosed(obj):
            center = rs.CurveAreaCentroid(obj)[0] ### analog: CurveAreaCentroid(curve_id)
            centers.append(center)
            #rs.AddPoint( center )
            distances = []
            for crv in chkCurves:
                param = rs.CurveClosestPoint( crv, center )
                point = rs.EvaluateCurve( crv, param )
                dist = rs.Distance( center, point )
                distances.append( [dist, point] )
            if verbose: print i, rs.ObjectName(obj), "minDist = ", min(distances)[0]
            distList.append( [min(distances)[0], obj] )
            #rs.AddCurve( [center, min(distances)[1] ] )
    minH = min(distList)[0]
    maxH = max(distList)[0]
    
    if maxHeight < 1: maxHeight=100.1
    #print "maxHeight =", maxHeight
    cnt=0
    if 1:
        if verbose:print "len distList", len(distList)
        distList = sorted(distList)
        for entry in distList[ bldgVon : bldgVon+bldgPlus ]:
            minHig = 3.5
            hig = reMap( entry[0], minH, maxH, minHig, rand(maxHeight*.75, maxHeight) )
            hig = hig**exponent
            randX = (rand(100.0) < 15)
            hig *= 1+randX*0.5 # x% mal so hoch
            if reverse: hig /= 1+randX*0.5
            if reverse: hig = maxHeight - hig
            hig = round(hig, 2)
            if cnt==0 and verbose:
                print "minDist=",minH, ">", "maxDist=",maxH, " -- maxHeight:", maxHeight, "newHeight:",hig
            if hig < 1: hig = 1.0
            if 1 and hig>1:
                srf = rs.ExtrudeCurveStraight(entry[1], [0,0,0], [0,0,hig])
                rs.CapPlanarHoles( srf )
                nam = rs.ObjectName( entry[1] )
                tmp = nam.split("_")
                newNam = tmp[0]+"_"+tmp[1]+"_"+str(hig)+"_new"
                copy = rs.CopyObject(entry[1])
                rs.ObjectName(copy, "crv_"+tmp[1]+"_"+str(hig)+"_new")
                rs.ObjectLayer( copy, "_newBuildings::_newBuildings_crv")
                rs.ObjectName(srf, "srf_"+tmp[1]+"_"+str(hig)+"_new")
                col = reMap(entry[0], minH, maxH, 1,5)
                rgbMat2Obj(srf, 100+10*col, 100+15*col, 100+15*col, T=0.2)
                if randX: rgbMat2Obj(srf, 250,100,100, T=0.2)
            center = rs.CurveAreaCentroid(entry[1])[0]
            centerOben = [center[0], center[1], hig ]
            if verbose and cnt%20==0 or cnt%200==0: rs.Redraw()
            cnt+=1
    rs.CurrentLayer("Default")


def OSM_overpass_testAndChange(OSMpath, OSMfile, verbose):
    setTime()
    chgIt = 0
    with open(OSMpath+OSMfile, 'r') as fi:
        for line in fi:
            if "<note>" in line or "<meta osm_base=" in line:
                chgIt = 1
                break
    fi.close()
    if chgIt:
        lines=[]
        with open(OSMpath+OSMfile, 'r') as fi:
            for line in fi:
                if not "<note>" in line and not "<meta osm_base=" in line:
                    lines.append(line)
        fi.close()
        #rs.Sleep(3000)
        fo = open(OSMpath+OSMfile, 'w')
        for lin in lines: fo.write(lin)
        if verbose:
            print "*** file \""+OSMfile+"\" canged by OSMtestAndChange",
            print " in "+str(round(getTime(),2))+"secs"
        fo.close()



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



######## 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

echo(1)

###___GPX-----------------------------------------------------------------------

rs.EnableRedraw(0)
####################################################################
### version = "'''  ver 20221201 by _diag 4 DM* @ I OI III @ TUGraz '''"     #
version = "||| CC by-nc-sa agruber@tugraz.at ||| 4 DM* @ I OI III ||| ver 2022 12 03"     #
print     "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
print     "||| OSM_lib imported in "+ str(getTime(0)) +"s", version
print     "|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
####################################################################

