#-*- coding:utf-8 -*-
#
#
# Layout Module
#
# unittesting in tests/test_layout_u.py
#
"""
.. currentmodule:: pylayers.gis.layout
.. autosummary::
"""
from __future__ import print_function
try:
from tvtk.api import tvtk
from mayavi import mlab
except:
print('Layout:Mayavi is not installed')
import pdb
import sys
import os
import copy
import glob
import time
import pickle
import tqdm
import numpy as np
import numpy.random as rd
import scipy as sp
import scipy.sparse as sparse
import doctest
import triangle
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.colors as clr
import networkx as nx
import pandas as pd
from itertools import combinations, product
import ast
from networkx.readwrite import write_gpickle, read_gpickle
from mpl_toolkits.basemap import Basemap
import shapely.geometry as sh
import shapefile as shp
from shapely.ops import cascaded_union
from matplotlib.collections import PolyCollection
from numpy import array
import PIL.Image as Image
import hashlib
import pylayers.gis.kml as gkml
#from pathos.multiprocessing import ProcessingPool as Pool
#from pathos.multiprocessing import cpu_count
from functools import partial
if sys.version_info.major==2:
from urllib2 import urlopen
import ConfigParser
else:
from urllib.request import urlopen
import configparser as ConfigParser
# from cStringIO import StringIO
# from multiprocessing import Pool
def _pickle_method(method):
func_name = method.im_func.__name__
obj = method.im_self
cls = method.im_class
if func_name.startswith('__') and not func_name.endswith('__'): #deal with mangled names
cls_name = cls.__name__.lstrip('_')
func_name = '_' + cls_name + func_name
return _unpickle_method, (func_name, obj, cls)
def _unpickle_method(func_name, obj, cls):
for cls in cls.__mro__:
try:
func = cls.__dict__[func_name]
except KeyError:
pass
else:
break
return func.__get__(obj, cls)
import types
if sys.version_info.major==2:
import copy_reg
copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)
else:
import copyreg
copyreg.pickle(types.MethodType, _pickle_method, _unpickle_method)
import pylayers.antprop.slab as sb
from pylayers.util import geomutil as geu
from pylayers.util import plotutil as plu
from pylayers.util import pyutil as pyu
from pylayers.util import graphutil as gru
from pylayers.util import cone
# Handle furnitures
import pylayers.gis.furniture as fur
import pylayers.gis.osmparser as osm
from pylayers.gis.selectl import SelectL
import pylayers.util.graphutil as gph
import pylayers.util.project as pro
from pylayers.util.project import logger
[docs]def pbar(verbose,**kwargs):
if verbose:
pbar=tqdm.tqdm(**kwargs)
return pbar
[docs]class Layout(pro.PyLayers):
""" Handling Layout
Attributes
----------
Gs : Graph of points and segment (structure)
Gt : Graph of convex cycles (topology)
Gv : Graph of visibility (visibility)
Gi : Graph of interactions (interactions)
Gr : Graph of rooms (rooms)
Nnode : Number of nodes of Gs
Nedge : Number of edges of Gs
pt : points sequence
tahe : tail head
Notes
-----
This class uses `networkx` to store Layout information
Gs : structure
Gt : topology
Gv : visibility
Gi : interaction
Gr : room
Gm :
Gw : ways
Np
Ns
Nss
ax : (xmin,ymin,xmax,ymax)
axn : (0,Dx,0,Dy)
filefur
filegeom
filematini
fileslabini
hasboundary
segboundary
min_sx
min_sy
max_sx
max_sy
labels
lbltg
lboundary
listtransition
loadosm
lsss
name
normal
p2pc
pg
pt : points coordinates
tahe : segment tail head
tgs : graph to segment
tsg : segment to graph
upnt : array of point index
s2pc : segment to point coordinates
s2pu : segment to point index
sgsg
sl
typ : 'indoor' | 'outdoor'
coordinates : 'cart','lonlat'
version
_filename
_hash
_shseg : keys / segment index
values / shapely LineString
dca : keys / Gt node
values / list of air wall
degree : keys / point degree
values / array of index
display : dictionnary for controling various visualization
dsseg :
indoor : if True allow indoor penetration
isbuilt
diffraction
maxheight
zceil
zfloor
zmin
"""
def __init__(self,arg='',**kwargs):
""" object constructor
Parameters
----------
arg : string or tuple
layout file name, address or (lat,lon) or '(lat,lon)'
mat :
material dB file name
slab :
slab dB file name
fur :
furniture file name
force : boolean
check : boolean
build : boolean
verbose : boolean
bcartesian : boolean
xlim : '(xmin,xmax,ymin,ymax) | () default'
dist_m : int
typ : string
'indoor' | 'outdoor'
"""
self.arg = arg
self._filematini = kwargs.pop('mat','matDB.ini')
self._fileslabini = kwargs.pop('slab','slabDB.ini')
self._filefur = kwargs.pop('fur','')
self.bcheck = kwargs.pop('bcheck',False)
self.bbuild = kwargs.pop('bbuild',False)
self.bgraphs = kwargs.pop('bgraphs',False)
self.bverbose = kwargs.pop('bverbose',False)
self.bcartesian = kwargs.pop('bcartesian',True)
self.xlim = kwargs.pop('xlim',())
self.dist_m = kwargs.pop('dist_m',400)
self.typ = kwargs.pop('typ','outdoor')
self.bexcluded = kwargs.pop('bexcluded',False)
self.labels = {}
self.Np = 0
self.Ns = 0
self.Nss = 0
self.lsss = []
#
# Initializing graphs
# Gs : structure
# Gt : topology
# Gi : interaction
# Gr : rooms
# Gm : mobility
self.Gs = nx.Graph(name='Gs')
self.Gr = nx.Graph(name='Gr')
self.Gt = nx.Graph(name='Gt')
self.Gm = nx.Graph(name='Gm')
self.Gs.pos = {}
self.tahe = np.zeros(([2, 0]), dtype=int)
self.lbltg = []
self.Gt.pos = {}
self._shseg = {}
self.hasboundary = False
self.format = 'cart'
self.version = '1.3'
assert(self.typ in ['indoor','outdoor','floorplan'])
self.isbuilt = False
self.loadosm = False
#
# setting display option
self.display = {}
self.display['title'] = ''
self.display['ticksoff'] = True
self.display['nodes'] = False
self.display['ndsize'] = 10
self.display['ndlabel'] = False
self.display['ndlblsize'] = 20
self.display['edlblsize'] = 20
self.display['fontsize'] = 20
self.display['edlabel'] = False
self.display['edges'] = True
self.display['ednodes'] = False
self.display['subseg'] = True
self.display['isonb'] = True
self.display['transition'] = True
self.display['visu'] = False
self.display['thin'] = False
self.display['scaled'] = True
self.display['alpha'] = 0.5
self.display['layer'] = []
self.display['clear'] = False
self.display['activelayer'] = 'AIR'
self.display['layers'] = []
self.display['overlay'] = False
self.display['overlay_flip'] = ""
# self.display['overlay_file']="/home/buguen/Pyproject/data/image/"
self.display['overlay_file'] = ""
self.display['overlay_axis'] = ""
# self.display['layerset'] = self.sl.keys()
if self.xlim!=():
self.display['box']= self.xlim
else:
self.display['box'] = (-50, 50, -50, 50)
self.name = {}
self.ax = self.display['box']
self.zmin = 0
self.maxheight = 3.
newfile = False
loadlay = False
loadosm = False
loadres = False
#
# Layout main argument
#
if type(self.arg)==tuple:
self.arg = str(self.arg)
#
# Layout Point of Interest DataFrame
#
# A Layout is equipped with a DataFrame of Points of Interest
#
# dfpoi type =['tree','human','tx','rx','support']
#
self.dfpoi = pd.DataFrame(columns=['name','type','lon','lat','alt','x',',y','z','radius'])
if type(self.arg) is bytes:
self.arg = self.arg.decode('utf-8')
logger.info('analyze input string '+ self.arg)
arg, ext = os.path.splitext(self.arg)
if arg != '':
if ext == '.ini':
self._filename = self.arg
loadlay = True
if ext == '.lay':
self._filename = self.arg
loadlay = True
elif ext == '.osm':
self._filename = arg + '.lay'
loadosm = True
elif ext == '.res':
self._filename = arg + '.lay'
loadres = True
else:
self.typ = 'outdoor'
self._filename = arg.replace(' ','_')+'.lay'
else: # No argument new file
self._filename = 'newfile.lay'
newfile = True
self.sl = sb.SlabDB(fileslab=self._fileslabini, filemat=self._filematini)
self.zfloor = 0.
self.zceil = self.maxheight
#
# build directory to store graphs
#
if os.path.splitext(self._filename)[1] == '.lay':
dirname = self._filename.replace('.lay','')
path = os.path.join(pro.basename, 'struc', 'gpickle', dirname)
if not newfile:
if loadlay:
filename = pyu.getlong(self._filename, pro.pstruc['DIRLAY'])
if os.path.exists(filename): # which exists
# check the .lay hash
fd = open(filename,'rb')
self._hash = hashlib.md5(fd.read()).hexdigest()
fd.close()
# check existence of gpickle graphs
if os.path.exists(os.path.join(path,'Gs.gpickle')):
if os.path.exists(os.path.join(path,'.hash')):
fd = open(os.path.join(path,'.hash'),'r')
lines = fd.readlines()
fd.close()
hashGs = lines[0].replace('\n','')
self.segboundary = eval(lines[1])
self.typ = lines[2]
if hashGs==self._hash:
logger.info('load from Gs graph')
self.hasboundary = True
self.dumpr('s')
else:
logger.info('load from .lay file')
self.load_fast()
else:
logger.info('load from .lay file')
self.load_fast()
else:
logger.info('load from .lay file')
self.load_fast()
#self.load()
else: # which do not exist
newfile = True
print("new file - creating a void Layout", self._filename)
elif loadosm: # load .osm file
self.importosm(fileosm=self.arg, cart=self.bcartesian, typ=self.typ)
self.loadosm = True
elif loadres:
self.importres(_fileres=self.arg)
self.sl = sb.SlabDB()
elif '(' in str(arg): # load from osmapi latlon (string or tuple
latlon = eval(self.arg)
self.importosm(latlon=latlon,
dist_m=self.dist_m,
cart=self.bcartesian,
typ=self.typ)
self.loadosm = True
else: # load from address geocoding
self.importosm(address=self.arg,
dist_m=self.dist_m,
cart=self.bcartesian,
typ=self.typ)
self.loadosm = True
# add boundary if it not exist
if (not self.hasboundary) or (self.xlim != ()):
self.boundary(xlim = self.xlim)
logger.info('call subseg ')
self.subseg()
logger.info('call updateshseg ')
self.updateshseg()
try:
self.geomfile()
except:
print("problem to construct geomfile")
#
# check layout
#
self.bconsistent = True
if self.bcheck:
self.bconsistent, dseg = self.check()
# if Layout is correctly described
# check if the graph gpickle files have been built
if self.bconsistent:
#
# build and save graphs
#
if self.bbuild:
# ans = raw_input('Do you want to build the layout (y/N) ? ')
# if ans.lower()=='y'
self.build()
self.lbltg.append('s')
self.dumpw()
#
# load graphs from file
#
elif self.bgraphs:
if os.path.splitext(self._filename)[1]=='.lay':
dirname = self._filename.replace('.lay','')
path = os.path.join(pro.basename,
'struc',
'gpickle',
dirname)
if os.path.exists(path):
# load graph Gt
# and compare the self._hash from ini file
# with the hash store in node 0 of Gt at time of the last build
# If they are different a rebuild is needeed
# Otherwise all the stored graphs are loaded
#
self.dumpr('t')
# If node 0 exists : the layout has been built
# If .ini file has changed rebuild
if self._hash == self.Gt.node[0]['hash']:
self.dumpr('stvirw')
self.isbuilt = True
bbuild = False
else:
print(".lay file has changed you must rebuild the grahs")
else:
# if graph are requested and it not exists a pickle of a graph
# they are built
self.build()
self.lbltg.append('s')
self.dumpw()
#self.get_boundary()
logger.info('end of __init__')
def __repr__(self):
st = '\n'
st = st + "----------------\n"
home = os.path.expanduser('~')
with open(os.path.join(home, '.pylayers'),'r') as f:
paths = f.readlines()
uporj = paths.index('project\n')
project = paths[uporj+1]
st = st + "Project : " + project+'\n'
if hasattr(self, '_hash'):
st = st + self._filename + ' : ' + self._hash + "\n"
else:
st = st + self._filename + "\n"
if self.isbuilt:
st = st + 'Built with : ' + self.Gt.node[0]['hash'] + "\n"
st = st + 'Type : ' + self.typ+'\n'
if self.display['overlay_file'] != '':
filename = pyu.getlong(
self.display['overlay_file'], os.path.join('struc', 'images'))
st = st + "Image('" + filename + "')\n"
st = st + "Coordinates : " + self.format + "\n"
if hasattr(self,'extent'):
st = st + "----------------\n"
st = st+ str(self.extent)+'\n'
if hasattr(self,'extent_c'):
st = st + "----------------\n"
st = st+ str(self.extent_c)+'\n'
if hasattr(self, 'Gs'):
st = st + "----------------\n"
st = st + "Gs : "+str(len(self.Gs.node))+"("+str(self.Np)+'/'+str(self.Ns)+'/'+str(len(self.lsss))+') :'+str(len(self.Gs.edges()))+'\n'
if hasattr(self,'Gt'):
st = st + "Gt : "+str(len(self.Gt.node))+' : '+str(len(self.Gt.edges()))+'\n'
if hasattr(self,'Gv'):
st = st + "Gv : "+str(len(self.Gv.node))+' : '+str(len(self.Gv.edges()))+'\n'
if hasattr(self,'Gi'):
st = st + "Gi : "+str(len(self.Gi.node))+' : '+str(len(self.Gi.edges()))+'\n'
if hasattr(self,'Gr'):
st = st + "Gr : "+str(len(self.Gr.node))+' : '+str(len(self.Gr.edges()))+'\n'
if hasattr(self,'Gw'):
st = st + "Gw : "+str(len(self.Gw.node))+' : '+str(len(self.Gw.edges()))+'\n'
st = st + "----------------\n\n"
# if hasattr(self, 'degree'):
# for k in self.degree:
# if (k < 2) or (k > 3):
# st = st + 'degree ' + \
# str(k) + ' : ' + str(self.degree[k]) + "\n"
# else:
# st = st + 'number of node points of degree ' + \
# str(k) + ' : ' + str(len(self.degree[k])) + "\n"
st = st + "\n"
st = st + "xrange : " + str(self.ax[0:2]) + "\n"
st = st + "yrange : " + str(self.ax[2:]) + "\n"
if hasattr(self,'pg'):
st = st + "center : " + "( %.2f,%.2f)" % (self.pg[0],self.pg[1]) + "\n"
if hasattr(self,'radius'):
st = st + "radius : %.2f " % self.radius + "\n"
# st = st + "\nUseful dictionnaries" + "\n----------------\n"
# if hasattr(self,'dca'):
# st = st + "dca {cycle : []} cycle with an airwall" +"\n"
# if hasattr(self,'di'):
# st = st + "di {interaction : [nstr,typi]}" +"\n"
# if hasattr(self,'sl'):
# st = st + "sl {slab name : slab dictionary}" +"\n"
# if hasattr(self,'name'):
# st = st + "name : {slab :seglist} " +"\n"
# st = st + "\nUseful arrays"+"\n----------------\n"
# if hasattr(self,'pt'):
# st = st + "pt : numpy array of points " +"\n"
# if hasattr(self,'normal'):
# st = st + "normal : numpy array of normal " +"\n"
# if hasattr(self,'offset'):
# st = st + "offset : numpy array of offset " +"\n"
# if hasattr(self,'tsg'):
# st = st + "tsg : get segment index in Gs from tahe" +"\n"
# if hasattr(self,'isss'):
# st = st + "isss : sub-segment index above Nsmax"+"\n"
# if hasattr(self,'tgs'):
# st = st + "tgs : get segment index in tahe from self.Gs" +"\n"
# if hasattr(self,'upnt'):
# st = st + "upnt : get point id index from self.pt"+"\n"
# #if hasattr(self,'iupnt'):
# # st = st + "iupnt : get point index in self.pt from point id "+"\n"
# if hasattr(self,'lsss'):
# st = st + "lsss : list of segments with sub-segment"+"\n"
# if hasattr(self,'sridess'):
# st = st + "stridess : stride to calculate the index of a subsegment" +"\n"
# if hasattr(self,'sla'):
# st = st + "sla : list of all slab names (Nsmax+Nss+1)" +"\n"
# if hasattr(self,'degree'):
# st = st + "degree : degree of nodes " +"\n"
# st = st + "\nUseful tip" + "\n----------------\n"
# st = st + "Point p in Gs => p_coord:\n"
# #st = st + "p -> u = self.iupnt[-p] -> p_coord = self.pt[:,u]\n\n"
#st = st + "Segment s in Gs => s_ab coordinates \n"
#st = st + "s2pc : segment to point coordinates (sparse) [p1,p2] = L.s2pc.toarray().reshape(2,2).T \n"
#st = st + \
# "s -> u = self.tgs[s] -> v = self.tahe[:,u] -> s_ab = self.pt[:,v]\n\n"
return(st)
def __add__(self, other):
""" addition
One can add either a numpy array or an other layout
"""
Ls = copy.deepcopy(self)
if type(other) == np.ndarray:
for k in Ls.Gs.pos:
Ls.Gs.pos[k] = Ls.Gs.pos[k] + other[0:2]
else:
offp = -min(Ls.Gs.nodes())
offs = max(Ls.Gs.nodes())
other.offset_index(offp=offp, offs=offs)
Ls.Gs.node.update(other.Gs.node)
Ls.Gs.edge.update(other.Gs.edge)
Ls.Gs.adj.update(other.Gs.adj)
Ls.Gs.pos.update(other.Gs.pos)
Ls.Np = Ls.Np + other.Np
Ls.Ns = Ls.Ns + other.Ns
Ls.Nss = Ls.Nss + other.Nss
return(Ls)
def __mul__(self, alpha):
""" scale the layout
other : scaling factor (np.array or int or float)
Returns
-------
Ls : Layout
scaled layout
"""
Ls = copy.deepcopy(self)
Gs = Ls.Gs
if type(alpha) != np.ndarray:
assert((type(alpha) == float) or (
type(alpha) == int)), " not float"
alpha = np.array([alpha, alpha, alpha])
else:
assert(len(alpha) == 3), " not 3D"
#
# scaling x & y
#
x = np.array(Gs.pos.values())[:, 0]
x = x * alpha[0]
y = np.array(Gs.pos.values())[:, 1]
y = y * alpha[1]
xy = np.vstack((x, y)).T
Ls.Gs.pos = dict(zip(Gs.pos.keys(), tuple(xy)))
#
# scaling z
#
nseg = filter(lambda x: x > 0, Gs.nodes())
for k in nseg:
Ls.Gs.node[k]['z'] = tuple(
(np.array(Ls.Gs.node[k]['z']) - self.zmin) * alpha[2] + self.zmin)
if 'ss_z' in Ls.Gs.node[k]:
Ls.Gs.node[k]['ss_z'] = list(
(np.array(Ls.Gs.node[k]['ss_z']) - self.zmin) * alpha[2] + self.zmin)
#
# updating numpy array from graph
#
Ls.g2npy()
return Ls
def mapconv(xorlon,yorlat,inverse=False):
""" map converter spherical to cartesian (default)
Parameters
----------
lonorx : np.array of float
lon or x
latory : np.array of float
lat or y
inverse : boolean
True (cartesian -> spherical)
False (spherical -> cartesian)
Examples
--------
lon = np.array([])
lat = np.array([])
p = L.mapconv(lon,lat)
Info
----
Lambert 93 (France) : Proj(init='epsg:2154')
"""
# spherical projection
psph = Proj(init='epsg:4326')
# use Basemap (Deprecated)
if hasattr(self,'m'):
p = self.m(lonorx,latory,inverse=inverse)
# use pyproj
if hasattr(self,'cartproj'):
if inverse:
p = projection(self.cartproj,psph,lonorx,latory)
else:
p = projection(psph,self.cartproj,lonorx,latory)
def switch(self):
""" switch coordinates
Info
----
Use either basemap objet or pyproj object
"""
if hasattr(self,'m'):
if self.format == 'cart':
for k in self.Gs.pos.keys():
p = self.m( self.Gs.pos[k][0], self.Gs.pos[k][1], inverse=True)
self.Gs.pos[k] = p
if hasattr(self,'dpoly'):
if hasattr(self.dpoly,'_xy'):
for k in self.dpoly:
#self.dpoly[k].ndarray() = np.vstack(self.m(self.dpoly[k].ndarray()[0,:],self.dpoly[k].ndarray()[1,:],inverse=True))
self.dpoly[k]._xy = np.vstack(self.m(self.dpoly[k]._xy[0,:],self.dpoly[k]._xy[1,:],inverse=True))
self.format = 'latlon'
elif self.format == 'latlon':
for k in self.Gs.pos.keys():
p = self.m( self.Gs.pos[k][0], self.Gs.pos[k][1])
self.Gs.pos[k] = p
if hasattr(self,'dpoly'):
if hasattr(self.dpoly,'_xy'):
for k in self.dpoly:
#self.dpoly[k].ndarray() = np.vstack(self.m(self.dpoly[k].ndarray()[0,:],self.dpoly[k].ndarray()[1,:],inverse=True))
self.dpoly[k]._xy = np.vstack(self.m(self.dpoly[k]._xy[0,:],self.dpoly[k]._xy[1,:]))
self.format ='cart'
nodes = self.Gs.nodes()
upnt = [n for n in nodes if n < 0]
self.pt[0, :] = np.array([self.Gs.pos[k][0] for k in upnt])
self.pt[1, :] = np.array([self.Gs.pos[k][1] for k in upnt])
def _help(self):
st = ''
st = st + "\nUseful dictionnaries" + "\n----------------\n"
if hasattr(self,'dca'):
st = st + "dca {cycle : []} cycle with an airwall" +"\n"
if hasattr(self,'di'):
st = st + "di {interaction : [nstr,typi]}" +"\n"
if hasattr(self,'sl'):
st = st + "sl {slab name : slab dictionary}" +"\n"
if hasattr(self,'name'):
st = st + "name : {slab :seglist} " +"\n"
st = st + "\nUseful arrays"+"\n----------------\n"
if hasattr(self,'pt'):
st = st + "pt : numpy array of points " +"\n"
if hasattr(self,'normal'):
st = st + "normal : numpy array of normal " +"\n"
if hasattr(self,'offset'):
st = st + "offset : numpy array of offset " +"\n"
if hasattr(self,'tsg'):
st = st + "tsg : get segment index in Gs from tahe" +"\n"
if hasattr(self,'isss'):
st = st + "isss : sub-segment index above Nsmax"+"\n"
if hasattr(self,'tgs'):
st = st + "tgs : get segment index in tahe from self.Gs" +"\n"
if hasattr(self,'upnt'):
st = st + "upnt : get point id index from self.pt"+"\n"
st = st + "\nUseful Sparse arrays"+"\n----------------\n"
if hasattr(self,'sgsg'):
st = st + "sgsg : "+"get common point of 2 segment (usage self.sgsg[seg1,seg2] => return common point \n"
if hasattr(self,'s2pc'):
st = st + "s2pc : "+"from a Gs segment node to its 2 extremal points (tahe) coordinates\n"
if hasattr(self,'s2pu'):
st = st + "s2pu : "+"from a Gs segment node to its 2 extremal points (tahe) index\n"
if hasattr(self,'p2pu'):
st = st + "p2pu : "+"from a Gs point node to its coordinates\n"
st = st + "\nUseful lists"+"\n----------------\n"
#if hasattr(self,'iupnt'):
# st = st + "iupnt : get point index in self.pt from point id "+"\n"
if hasattr(self,'lsss'):
st = st + "lsss : list of segments with sub-segment"+"\n"
if hasattr(self,'sridess'):
st = st + "stridess : stride to calculate the index of a subsegment" +"\n"
if hasattr(self,'sla'):
st = st + "sla : list of all slab names (Nsmax+Nss+1)" +"\n"
if hasattr(self,'degree'):
st = st + "degree : degree of nodes " +"\n"
st = st + "\nUseful tip" + "\n----------------\n"
st = st + "Point p in Gs => p_coord: Not implemented\n"
# st = st + "p -> u = self.upnt[-p] -> p_coord = self.pt[:,-u]\n\n"
st = st + "Segment s in Gs => s_ab coordinates \n"
st = st + \
"s -> u = self.tgs[s] -> v = self.tahe[:,u] -> s_ab = self.pt[:,v]\n\n"
print(st)
[docs] def ls(self, typ='lay'):
""" list the available file in dirstruc
Parameters
----------
typ : string optional
{'lay'|'osm'|'wrl'}
Returns
-------
lfile_s : list
sorted list of all the .str file of strdir
Notes
-----
strdir is defined in the Project module
Examples
--------
Display all available structures
>>> from pylayers.gis.layout import *
>>> L = Layout()
>>> fillist = L.ls()
"""
if typ == 'lay':
pathname = os.path.join(pro.pstruc['DIRLAY'], '*.' + typ)
if typ == 'osm':
pathname = os.path.join(pro.pstruc['DIROSM'], '*.' + typ)
if typ == 'wrl':
pathname = os.path.join(pro.pstruc['DIRWRL'], '*.' + typ)
lfile_l = glob.glob(os.path.join(pro.basename, pathname))
lfile_s = []
for fi in lfile_l:
fis = pyu.getshort(fi)
lfile_s.append(fis)
lfile_s.sort()
return lfile_s
[docs] def offset_index(self, offp=0, offs=0):
""" offset points and segment index
Parameters
----------
offp : offset points
offs : offset segments
See Also
--------
Portage vers networkx 2. inacheve
__add__
"""
newpoint = dict((k - offp, v) for k, v in self.Gs.node.items() if k < 0)
assert (np.array(list(newpoint.keys())) < 0).all()
newseg = dict((k + offs, v) for k, v in self.Gs.node.items() if k > 0)
assert (np.array(list(newseg.keys())) > 0).all()
newpoint.update(newseg)
nx.set_node_attributes(self.Gs,newpoint)
#self.Gs.node = newpoint
newppoint = dict((k - offp, v) for k, v in self.Gs.pos.items() if k < 0)
newpseg = dict((k + offs, v) for k, v in self.Gs.pos.items() if k > 0)
newppoint.update(newpseg)
self.Gs.pos = newppoint
# adjascence list of segments
ladjs = [self.Gs.adj[k] for k in self.Gs.adj.keys() if k > 0]
# adjascence list of points
ladjp = [self.Gs.adj[k] for k in self.Gs.adj.keys() if k < 0]
nladjs = map(lambda x: dict((k - offp, v)
for k, v in x.items()), ladjs)
nladjp = map(lambda x: dict((k + offs, v)
for k, v in x.items()), ladjp)
lpt = [k - offp for k in self.Gs.adj.keys() if k < 0]
lseg = [k + offs for k in self.Gs.adj.keys() if k > 0]
dpt = dict(zip(lpt, nladjp))
dseg = dict(zip(lseg, nladjs))
dseg.update(dpt)
print("Todo create a dictionnary of edges")
nx.set_edge_attributes(self.Gs,dseg)
# self.Gs.adj = dseg
# self.Gs.edge = dseg
[docs] def check(self, level=0, epsilon = 0.64):
""" Check Layout consistency
Parameters
----------
level : int
Returns
-------
consistent : Boolean
True if consistent
dseg : dictionnary of segments
See Also
--------
GeomUtil.isBetween
Notes
-----
For all segments
get the 2 vertices
for all the other vertices
check if it belongs to segment
If there are points which are not valid they are displayed
In red point with degree == 1 , In black points with degree == 0
"""
bconsistent = True
nodes = self.Gs.nodes()
if len(nodes) > 0:
#
# points
# segments
# degree of segments
useg = [ x for x in nodes if x > 0 ]
upnt = [ x for x in nodes if x < 0 ]
degseg = [nx.degree(self.Gs, x) for x in useg ]
#
# 1) all segments have degree 2
#
assert(np.all(array(degseg) == 2))
#
# degree of points
# maximum degree of points
#
degpnt = [ nx.degree(self.Gs, x) for x in upnt ] # points absolute degrees
degmin = min(degpnt)
degmax = max(degpnt)
#
# No isolated points (degree 0)
# No points of degree 1
#
if (degmin <= 1):
f, a = self.showG('s', aw=1)
deg0 = [ x for x in upnt if nx.degree(self.Gs, x) == 0]
deg1 = [ x for x in upnt if nx.degree(self.Gs, x) == 1]
if len(deg0) > 0:
logger.critical( "It exists degree 0 points : %r", deg0 )
f, a = self.pltvnodes(deg0, fig=f, ax=a)
bconsistent = False
if len(deg1) > 0:
logger.critical( "It exists degree 1 points : %r", deg1 )
f, a = self.pltvnodes(deg1, fig=f, ax=a)
bconsistent = False
# self.deg = {}
# for deg in range(degmax + 1):
# num = filter(lambda x: degpnt[x] == deg, range(
# len(degpnt))) # position of degree 1 point
# npt = map(lambda x: upnt[x], num) # number of degree 1 points
# self.deg[deg] = npt
#
# check if there are duplicate points or segments
#
# TODO argsort x coordinate
#
# get all the nodes
ke = list(self.Gs.pos.keys())
lpos = list(self.Gs.pos.values())
x = np.array([ pp[0] for pp in lpos ] )
y = np.array([ pp[1] for pp in lpos ] )
p = np.vstack((x, y))
d1 = p - np.roll(p, 1, axis=1)
sd1 = np.sum(np.abs(d1), axis=0)
if not sd1.all() != 0:
lu = np.where(sd1 == 0)[0]
for u in lu:
# if ke[u]>0:
# self.del_segment(ke[u])
if ke[u] < 0:
self.del_points(ke[u])
nodes = self.Gs.nodes()
# useg = filter(lambda x : x>0,nodes)
upnt = filter(lambda x: x < 0, nodes)
# iterate on useg : list of segments
# s : n1 <--> n2
#
# Is there a point different from (n1-n2) in betweeen of an existing segment s ?
#
# Not scalable. Double for loop
dseg = {}
if (self.typ == 'indoor') or (self.typ=='outdoor'):
for s in useg:
# n1, n2 = np.array(self.Gs.neighbors(s)) # node s neighbors
n1, n2 = np.array(self.Gs[s]) # node s neighbors
p1 = np.array(self.Gs.pos[n1]) # p1 --- p2
p2 = np.array(self.Gs.pos[n2]) # s
#
# iterate on upnt : list of points
for n in upnt:
if (n1 != n) & (n2 != n):
p = np.array(self.Gs.pos[n])
if geu.isBetween(p1, p2, p,epsilon=epsilon):
if s in dseg:
dseg[s].append(n)
else:
dseg[s]=[n]
logger.critical("segment %d contains point %d", s, n)
bconsistent = False
if level > 0:
cycle = self.Gs.node[s]['ncycles']
if len(cycle) == 0:
logger.critical("segment %d has no cycle", s)
if len(cycle) == 3:
logger.critical(
"segment %d has cycle %s", s, str(cycle))
#
# check if Gs points are unique
# segments can be duplicated
#
P = np.array([self.Gs.pos[k] for k in upnt])
similar = geu.check_point_unicity(P)
if len(similar) != 0:
logger.critical("points at index(es) %s in self.Gs.pos are similar", str(similar))
bconsistent = False
return bconsistent, dseg
[docs] def clip(self, xmin, xmax, ymin, ymax):
""" return the list of edges which cross or belong to the clipping zone
Parameters
----------
xmin : float
xmax : float
ymin : float
ymax : float
Returns
-------
seglist : list of segment number
Notes
-----
1) Determine all segments outside the clipping zone
2) Union of the 4 conditions
3) setdiff1d between the whole array of segments and the segments outside
"""
p0 = self.pt[:, self.tahe[0, :]]
p1 = self.pt[:, self.tahe[1, :]]
maxx = np.maximum(p0[0, :], p1[0, :])
maxy = np.maximum(p0[1, :], p1[1, :])
minx = np.minimum(p0[0, :], p1[0, :])
miny = np.minimum(p0[1, :], p1[1, :])
nxp = np.nonzero(maxx < xmin)[0]
nxm = np.nonzero(minx > xmax)[0]
nyp = np.nonzero(maxy < ymin)[0]
nym = np.nonzero(miny > ymax)[0]
u = np.union1d(nxp, nxm)
u = np.union1d(u, nyp)
u = np.union1d(u, nym)
iseg = np.arange(self.Ns)
return np.setdiff1d(iseg, u)
[docs] def check_Gi(self):
for nit1 in self.Gi.nodes():
if len(nit1)>1:
cy1 = nit1[-1]
for nint2 in self.Gi[nit1].keys():
if len(nint2) > 1 :
assert nint2[1] == cy1
# for e0,e1 in self.Gi.edges():
[docs] def g2npy(self,verbose=False):
""" conversion from graphs to numpy arrays
Parameters
----------
verbose : boolean
Notes
-----
This function updates the following arrays in self:
+ pt (2xNp)
+ pg center of gravity
+ tahe (2xNs)
+ tgs : graph to segment
+ tsg : segment to graph
+ dca : dictionnary of cycle with an airwall (_AIR)
+ s2pu : sparse_lil_matrix
+ s2pc : sparse_lil_matrix
+ lsss : list of iso segments
+ maxheight :
+ normal :
assert self.pt[self.iupnt[-1]] == self.pt[:,self.iupnt[-1]]
See Also
--------
extrseg
"""
nodes = self.Gs.nodes()
# nodes include points and segments
# segment index
useg = [n for n in nodes if n > 0]
# points index
upnt = [n for n in nodes if n < 0]
# sparse matrix segment-segment
# usage
# self.sgsg[seg1,seg2] => return common point
mno = max(nodes)
#self.sgsg = sparse.lil_matrix((mno+1,mno+1),dtype='int')
# loop over segments
# a segment is always connected to 2 nodes
logger.info('g2npy : loop over segments')
for s in useg:
# get point index of the segment
# s > 0
# v1.1 lpts = [ x for x in nx.neighbors(self.Gs,s)]
lpts = [ x for x in self.Gs[s] ]
assert(len(lpts)==2)
assert(lpts[0]<0)
assert(lpts[1]<0)
# get point 0 neighbors
a = [ x for x in self.Gs[lpts[0]]]
# a = self.Gs.edge[lpts[0]].keys()
# get point 1 neighbors
#b = self.Gs.edge[lpts[1]].keys()
b = [ x for x in self.Gs[lpts[1]]]
nsa = np.setdiff1d(a,b)
nsb = np.setdiff1d(b,a)
u = np.hstack((nsa,nsb))
npta = [lpts[0]]*len(nsa)
nptb = [lpts[1]]*len(nsb)
ns = np.hstack((npta,nptb))
#self.sgsg[s,u]=ns
# conversion in numpy array
self.upnt = np.array((upnt))
self.useg = np.array((useg))
l1 = [(x, self.Gs.node[x]['name']) for x in self.useg ]
for l in l1:
try:
self.name[l[1]].append(l[0])
except:
self.name[l[1]] = [l[0]]
# association
# utmp = np.array(zip(-self.upnt,np.arange(len(self.upnt))))
# mutmp = max(utmp[:,0])
# self.iupnt = -np.ones((mutmp+1),dtype='int')
# self.iupnt[utmp[:,0]]=utmp[:,1]
# degree of segment nodes
degseg = [ nx.degree(self.Gs,x) for x in useg ]
assert(np.all(np.array(degseg) == 2)) # all segments must have degree 2
#
# self.degree : dictionnary (point degree : list of point index)
#
# points absolute degrees
degpnt = np.array([nx.degree(self.Gs, x) for x in upnt])
# lairwall : list of air wall segments
lairwall = []
if 'AIR' in self.name:
lairwall += self.name['AIR']
else:
self.name['AIR'] = []
if '_AIR' in self.name:
lairwall += self.name['_AIR']
else:
self.name['_AIR'] = []
# as self.name['AIR'] and self.name['_AIR'] are tested
# we define them as void list if not defined
#
# function to count airwall connected to a point
# probably this is not the faster solution
#
def nairwall(nupt):
#v1.1 lseg = nx.neighbors(self.Gs, nupt)
lseg = self.Gs[nupt]
n = 0
for ns in lseg:
if ns in lairwall:
n = n + 1
return n
nairwall = np.array([ nairwall(x) for x in upnt])
if verbose:
print('buildging nairwall : Done')
#
# if a node is connected to N air wall ==> deg = deg - N
#
degpnt = degpnt - nairwall
try:
degmax = max(degpnt)
except:
degmax = 1
self.degree = {}
logger.info('g2npy : Start node degree determination')
for deg in range(degmax + 1):
#num = filter(lambda x: degpnt[x] == deg, range(
# len(degpnt))) # position of degree 1 point
num = [ x for x in range(len(degpnt)) if degpnt[x] == deg ]
# number of degree 1 points
#npt = np.array(map(lambda x: upnt[x], num))
npt = np.array([upnt[x] for x in num])
self.degree[deg] = npt
logger.info('g2npy : convert geometric information in numpy array')
self.pt = np.array(np.zeros([2, len(upnt)]), dtype=float)
self.tahe = np.array(np.zeros([2, len(useg)]), dtype=int)
self.Np = len(upnt)
self.Ns = len(useg)
self.pt[0, :] = np.array([self.Gs.pos[k][0] for k in upnt])
self.pt[1, :] = np.array([self.Gs.pos[k][1] for k in upnt])
self.pg = np.sum(self.pt, axis=1) / np.shape(self.pt)[1]
ptc = self.pt-self.pg[:,None]
dptc = np.sqrt(np.sum(ptc*ptc,axis=0))
self.radius = dptc.max()
self.pg = np.hstack((self.pg, 0.))
if self.Ns>0:
ntahe = np.array([ [n for n in nx.neighbors(self.Gs,x) ] for x in useg ])
ntail = ntahe[:,0]
nhead = ntahe[:,1]
# create sparse matrix from a Gs segment node to its 2 extremal points (tahe) index
mlgsn = max(self.Gs.nodes())+1
self.s2pu = sparse.lil_matrix((mlgsn,2),dtype='int')
self.s2pu[useg,:] = ntahe
# convert to compressed row sparse matrix
# to be more efficient on row slicing
self.s2pu = self.s2pu.tocsr()
if self.Ns > 0:
aupnt = np.array(upnt)
logger.info('g2npy : build tail head tahe')
self.tahe[0, :] = np.array([np.where(aupnt==x)[0][0] for x in ntail ])
self.tahe[1, :] = np.array([np.where(aupnt==x)[0][0] for x in nhead ])
#
# transcoding array between graph numbering (discontinuous) and numpy numbering (continuous)
#
Nsmax = 0
self.tsg = np.array(useg)
try:
Nsmax = max(self.tsg)
except:
logger.warning("No segments in Layout yet")
#
# handling of segment related arrays
#
if Nsmax > 0:
self.tgs = -np.ones(Nsmax + 1, dtype=int)
rag = np.arange(len(useg))
self.tgs[self.tsg] = rag
#
# calculate normal to segment ta-he
#
# This could becomes obsolete once the normal will be calculated at
# creation of the segment
#
X = np.vstack((self.pt[0, self.tahe[0, :]],
self.pt[0, self.tahe[1, :]]))
Y = np.vstack((self.pt[1, self.tahe[0, :]],
self.pt[1, self.tahe[1, :]]))
normx = Y[0, :] - Y[1, :]
normy = X[1, :] - X[0, :]
scale = np.sqrt(normx * normx + normy * normy)
assert (scale.all() > 0), pdb.set_trace()
self.normal = np.vstack(
(normx, normy, np.zeros(len(scale)))) / scale
# for ks in ds:
#
# lsss : list of subsegment
#
# nsmax = max(self.Gs.node.keys())
# Warning
# -------
# nsmax can be different from the total number of segments
# This means that the numerotation of segments do not need to be
# contiguous.
# stridess : length is equal to nsmax+1
# sla is an array of string, index 0 is not used because there is
# no such segment number.
#
self.lsss = [x for x in useg if len(self.Gs.node[x]['iso']) > 0]
# self.isss = []
# self.stridess = np.array(np.zeros(nsmax+1),dtype=int)
# self.stridess = np.empty(nsmax+1,dtype=int)
# +1 is for discarding index 0 (unused here)
# self.offset = np.empty(nsmax+1+self.Nss,dtype=int)
# Storing segment normals
# Handling of subsegments
#
# index is for indexing subsegment after the nsmax value
#
# index = nsmax+1
# for ks in useg:
# k = self.tgs[ks] # index numpy
# self.offset[k] = self.Gs.node[ks]['offset']
# self.Gs.node[ks]['norm'] = self.normal[:,k] # update normal
# nameslab = self.Gs.node[ks]['name'] # update sla array
# assert nameslab!='', "segment "+str(ks)+ " is not defined"
# self.sla[ks] = nameslab
# # stridess is different from 0 only for subsegments
# self.stridess[ks] = 0 # initialize stridess[ks]
# #if index==155:
# if self.Gs.node[ks].has_key('ss_name'): # if segment has sub segment
# nss = len(self.Gs.node[ks]['ss_name']) # retrieve number of sseg
# self.stridess[ks]=index-1 # update stridess[ks] dict
# for uk,slabname in enumerate(self.Gs.node[ks]['ss_name']):
# self.lsss.append(ks)
# self.sla[index] = slabname
# self.isss.append(index)
# self.offset[index] = self.Gs.node[ks]['ss_offset'][uk]
# index = index+1
# append sub segment normal to normal
# create sparse matrix from a Gs segment node to its 2 extremal points (tahe) coordinates
if self.Ns >0:
self.s2pc = sparse.lil_matrix((mlgsn,4))
ptail = self.pt[:,self.tahe[0,:]]
phead = self.pt[:,self.tahe[1,:]]
A = np.vstack((ptail,phead)).T
self.s2pc[self.tsg,:]=A
# convert to compressed row sparse matrix
# to be more efficient on row slicing
self.s2pc = self.s2pc.tocsr()
# for k in self.tsg:
# assert(np.array(self.s2pc[k,:].todense())==self.seg2pts(k).T).all(),pdb.set_trace()
#
# This is wrong and asume a continuous indexation of points
# TODO FIX : This problem cleanly
#
# self.p2pc is only used in Gspos in outputGi_func only caled in case of
# multiprocessing
#
# The temporary fix is to comment the 5 next lines
#
# mino = -min(self.Gs.nodes())+1
# self.p2pc = sparse.lil_matrix((mino,2))
# self.p2pc[-self.upnt,:]=self.pt.T
# self.p2pc = self.p2pc.tocsr()
# normal_ss = self.normal[:,self.tgs[self.lsss]]
# self.normal = np.hstack((self.normal,normal_ss))
# if problem here check file format 'z' should be a string
lheight = array([v[1] for v in
nx.get_node_attributes(self.Gs, 'z').values()
if v[1] < 2000 ])
#assert(len(lheight)>0),logger.error("no valid heights for segments")
if len(lheight)>0:
self.maxheight = np.max(lheight)
else:
self.maxheight = 3
# self.maxheight=3.
# calculate extremum of segments
self.extrseg()
[docs] def importshp(self, **kwargs):
""" import layout from shape file
Parameters
----------
_fileshp :
"""
pref = kwargs.pop('pref', [np.array([25481100, 6676890]), np.array([60.2043716, 24.6591147])])
dist_m = kwargs.pop('dist_m',250)
latlon = kwargs.pop('latlon',True)
bd = kwargs.pop('bd', [24, 60, 25, 61])
fileshp = pyu.getlong(kwargs['_fileshp'], os.path.join('struc', 'shp'))
polys = shp.Reader(fileshp)
verts = []
for poly in polys.iterShapes():
verts.append(poly.points)
npt = -1
ns = 0
xmin = 1e16
ymin = 1e16
xmax = -1e16
ymax = -1e16
self.name['WALL'] = []
for p in verts:
v = np.array(p) - pref[0][None, :]
nv = np.sqrt(np.sum(v * v, axis=1))
# if at least one point is in the radius the poygon is kept
if (nv < dist_m).any():
npoint = len(p)
for k, point in enumerate(p):
# add a new node unless it is the last already existing
# point
if k != (npoint - 1):
if k == 0:
np0 = npt
self.Gs.add_node(npt)
x = point[0]
y = point[1]
xmin = min(x, xmin)
xmax = max(x, xmax)
ymin = min(y, ymin)
ymax = max(y, ymax)
self.Gs.pos[npt] = (x, y)
npt = npt - 1
# add a new segment from the second point
if (k > 0) & (k < npoint - 1):
ns = ns + 1
self.Gs.add_node(ns, name='WALL', z=[
0, 10], offset=0, transition=False, connect=[npt + 1, npt + 2])
self.Gs.add_edge(npt + 1, ns)
self.Gs.add_edge(ns, npt + 2)
self.Gs.pos[ns] = tuple(
(np.array(self.Gs.pos[npt + 1]) + np.array(self.Gs.pos[npt + 2])) / 2.)
# add a new segment closing the polygon
if k == npoint - 1:
ns = ns + 1
self.Gs.add_node(ns, name='WALL', z=[
0, 10], offset=0, transition=False, connect=[np0, npt + 1])
self.Gs.add_edge(np0, ns)
self.Gs.add_edge(ns, npt + 1)
self.Gs.pos[ns] = tuple(
(np.array(self.Gs.pos[npt + 1]) + np.array(self.Gs.pos[np0])) / 2.)
#
# TODO change lon_0 and lat_0 hard coded
#
self.m = Basemap(llcrnrlon=kwargs['bd'][0], llcrnrlat=kwargs['bd'][1],
urcrnrlon=kwargs['bd'][2], urcrnrlat=kwargs['bd'][3],
resolution='i', projection='cass', lon_0=24.5, lat_0=60.5)
if latlon:
lat_ref = pref[1][0]
lon_ref = pref[1][1]
x_ref, y_ref = self.m(lon_ref, lat_ref)
Dx = pref[0][0] - x_ref
Dy = pref[0][1] - y_ref
pos = np.array(self.Gs.pos.values())
for k, keys in enumerate(self.Gs.pos.keys()):
self.Gs.pos[keys] = self.m( pos[k, 0] - Dx, pos[k, 1] - Dy, inverse=True)
self.format = 'latlon'
[docs] def importres(self,_fileres,**kwargs):
""" import res format
col1 : x1 coordinates
col2 : y1 coordinates
col3 : x2 coordinates
col4 : y2 coordinates
col5 : building height
col6 : building number
col7 : building class
col8 : ground height
Notes
-----
COST231 data Munich_buildings.res
"""
fileres = pyu.getlong(_fileres, os.path.join('struc', 'res'))
D = np.fromfile(fileres,dtype='int',sep=' ')
self.typ = 'outdoor'
# number of integer
N1 = len(D)
# number of lines
N2 = N1//8
D = D.reshape(N2,8)
# list of coordinates
lcoords = []
# list of ring
lring = []
# list of (z_ground, height_building)
zring = []
#
bdg_old = 1
self.zfloor=-1000
self.zceil = 4000
for e in range(N2):
# p1 point coordinate
p1 = ([D[e,0],D[e,1]])
# p2 point coordinate
p2 = ([D[e,2],D[e,3]])
# (ground height,building height+ground_height)
z = (D[e,7],D[e,4]+D[e,7])
# building number
bdg = D[e,5]
# building class
bdc = D[e,6]
# detect change of building
if (bdg_old-bdg)!=0:
ring = sh.LinearRing(lcoords)
poly = sh.Polygon(ring)
if poly.area>0:
lring.append(ring)
zring.append(z)
lcoords = []
bdg_old=bdg
# update lcoords
if p1 not in lcoords:
lcoords.append(p1)
if p2 not in lcoords:
lcoords.append(p2)
npt = 1
self.dpoly = {}
for kpol,(r1,z1) in enumerate(zip(lring,zring)):
x,y = r1.xy
lseg = []
for k2 in range(len(x)):
new_pt = (x[k2],y[k2])
kpos = list(self.Gs.pos.keys())
vpos = list(self.Gs.pos.values())
if new_pt not in vpos:
#
# add node point nde <0 and position
#
current_node_index = -npt
self.Gs.add_node(current_node_index)
self.Gs.pos[-npt] = new_pt
npt = npt + 1
else:
u = [k for k in range(len(vpos)) if (vpos[k] == new_pt)]
current_node_index = kpos[u[0]]
if k2>0: # at least already one point
ns = self.add_segment(current_node_index,
previous_node_index,
name='WALL',
z=z1)
lseg.append(ns)
else:
starting_node_index = current_node_index
previous_node_index = current_node_index
self.dpoly[kpol+1] = {'connect':lseg, 'z':z1, 'name':''}
# last segment
#ns = self.add_segment(previous_node_index, starting_node_index, name='WALL', z=z1)
[docs] def importosm(self, **kwargs):
""" import layout from osm file or osmapi
Parameters
----------
fileosm : string
address : string
address to be geocoded
latlon : tuple
(latitude,longitude) degrees
dist_m : float
distance in meter from the geocoded address (def 200 m )
cart : boolean
conversion in cartesian coordinates
Notes
-----
The best and recommended manner to edit a layout is to use the
josm editor in association with the piclayer plugin.
This plugin allows to place a geo-adjusted image in the background
which is very convenient for editing floorplan of buildings.
In josm editor, nodes are numbered with negative indexes, while in
pylayers they have a positive index.
See Also
--------
pylayers.gis.osmparser.osmparse
"""
self._fileosm = kwargs.pop('fileosm','')
cart = kwargs.pop('cart',False)
#
# zceil ansd zfloor are obtained from actual data
#
# indoor default (0,3)
# outdoor default (0,3000)
#if self.typ=='indoor':
self.zceil = -1e10
self.zfloor = 1e10
if self._fileosm == '': # by using osmapi address or latlon
logger.info('load from osmapi')
self.typ = kwargs.pop('typ','indoor')
address = kwargs.pop('address','Rennes')
latlon = kwargs.pop('latlon',0)
if type(latlon) == 'str':
latlon = eval(latlon)
dist_m = kwargs.pop('dist_m',200)
coords, nodes, ways, m , latlon , dpoly = osm.getosm(address = address,
latlon = latlon,
dist_m = dist_m,
bcart = cart,
typ = self.typ)
self.typ = 'outdoor'
if cart:
self.format = 'cart'
else:
self.format = 'latlon'
if latlon == '0':
self._filename = kwargs['address'].replace(' ', '_') + '.lay'
else:
lat = latlon[0]
lon = latlon[1]
self._filename = 'lat_' + \
str(lat).replace('.', '_') + '_lon_' + \
str(lon).replace('.', '_') + '.ini'
else: # by reading an osm file
logger.info('load from osm file')
# The osm file is supposed to be in $PROJECT/struc/osm directory
fileosm = pyu.getlong(self._fileosm, os.path.join('struc', 'osm'))
#coords, nodes, ways, relations, m = osm.osmparse(fileosm, typ=self.typ)
# typ outdoor parse ways.buildings
# typ indoor parse ways.ways
# coords, nodes, ways, relations, m = osm.osmparse(fileosm)
coords, nodes, ways, m , (lat,lon) , dpoly = osm.getosm(cart = cart,
filename = fileosm,
typ = self.typ,
bexcluded = self.bexcluded)
if cart:
self.format = 'cart'
else:
self.format = 'latlon'
self._filename = self._fileosm.replace('osm', 'lay')
self.dpoly = dpoly
_np = 0 # _ to avoid name conflict with numpy alias
_ns = 0
ns = 0
nss = 0
# Reading points (<0 index)
# Reorganize points coordinates for detecting
# duplicate nodes
# duplicate nodes are saved in dict dup
kp = [k for k in coords.xy]
x = np.array([ coords.xy[x][0] for x in kp ])
y = np.array([ coords.xy[x][1] for x in kp ])
ux = np.argsort(x)
x_prev = -100
y_prev = -100
dup = {} # dictionnary of duplicate nodes
for u in ux:
# if node is not already a duplicate
if x[u] == x_prev:
# 2 consecutive points with same lon => check lat
if y[u] == y_prev:
# node u is a duplicate
# udate dup dictionnary
# printu_prev ,k_prev, x_prev,y_prev
# print" ",u ,kp[u], x[u],y[u]
dup[kp[u]] = k_prev
else:
x_prev = x[u]
y_prev = y[u]
u_prev = u
k_prev = kp[u]
for npt in coords.xy:
# if node is not duplicated add node
if npt not in dup:
self.Gs.add_node(npt)
self.Gs.pos[npt] = tuple(coords.xy[npt])
_np += 1
# Reading segments
#
# ways of osm
#
for k, nseg in enumerate(ways.way):
tahe = ways.way[nseg].refs
for l in range(len(tahe) - 1):
nta = tahe[l]
nhe = tahe[l + 1]
#
# if a node is duplicated recover the original node
#
if nta in dup:
nta = dup[nta]
if nhe in dup:
nhe = dup[nhe]
d = ways.way[nseg].tags
#
# Convert string to integer if possible
#
for key in d:
try:
d[key] = eval(d[key])
except:
pass
# getting segment slab information
if 'slab' in d:
slab = d['slab']
else: # the default slab name is WALL
slab = "WALL"
if 'z' in d:
z = d['z']
else:
if self.typ == 'indoor':
z = (0, 3)
if self.typ == 'outdoor':
z = (0, 3000)
if type(z[0])==str:
zmin = eval(z[0])
else:
zmin = z[0]
if type(z[1])==str:
zmax = eval(z[1])
else:
zmax = z[1]
#zmin = z[0]
#zmax = z[1]
if zmin < self.zfloor:
self.zfloor = zmin
if zmax > self.zceil:
self.zceil = zmax
if 'offset' in d:
offset = d['offset']
else:
offset = 0
#
# get the common neighbor of nta and nhe if it exists
#
#v1.1 u1 = np.array(nx.neighbors(self.Gs, nta))
#v1.1 u2 = np.array(nx.neighbors(self.Gs, nhe))
# import ipdb
# u1 = np.array(self.Gs.node[nta])
# u2 = np.array(self.Gs.node[nhe])
# inter_u1_u2 = np.intersect1d(u1, u2)
#
# Create a new segment (iso segments are managed in add_segment)
#
ns = self.add_segment(nta, nhe, name=slab, z=z, offset=offset)
self.Np = _np
#self.Ns = _ns
self.Nss = nss
#
#
lon = array([self.Gs.pos[k][0] for k in self.Gs.pos])
lat = array([self.Gs.pos[k][1] for k in self.Gs.pos])
# bd = [lon.min(), lat.min(), lon.max(), lat.max()]
# lon_0 = (bd[0] + bd[2]) / 2.
# lat_0 = (bd[1] + bd[3]) / 2.
# self.m = Basemap(llcrnrlon=bd[0], llcrnrlat=bd[1],
# urcrnrlon=bd[2], urcrnrlat=bd[3],
# resolution='i', projection='cass', lon_0=lon_0, lat_0=lat_0)
self.m = m
self.extent = (m.lonmin,m.lonmax,m.latmin,m.latmax)
self.pll = self.m(self.extent[0],self.extent[2])
self.pur = self.m(self.extent[1],self.extent[3])
self.extent_c = (self.pll[0],self.pur[0],self.pll[1],self.pur[1])
#
# TODO use conversion function
#
if (cart and (self.format != 'cart')):
x, y = self.m(lon, lat)
self.Gs.pos = {k: (x[i], y[i]) for i, k in enumerate(self.Gs.pos)}
self.format = 'cart'
# del coords
# del nodes
# del ways
# del relations
#
# get slab and materials DataBase
#
# 1) create material database
# 2) load materials database
# 3) create slabs database
# 4) add materials database to slab database
# 5) load slabs database
mat = sb.MatDB()
mat.load(self._filematini)
self.sl = sb.SlabDB()
self.sl.mat = mat
self.sl.load(self._fileslabini)
#
# update self.name with existing slabs database entries
#
for k in self.sl.keys():
if k not in self.name:
self.name[k] = []
# convert graph Gs to numpy arrays for speed up post processing
self.g2npy()
#
# add boundary
#
self.boundary()
# save ini file
self.save()
#
[docs] def exportosm(self):
""" export layout in osm file format
Parameters
----------
_filename : string
Notes
-----
See Also
--------
layout.loadosm
layout.loadini
layout.check
"""
# export Layout in osm format
# The osm filename basenam is the same as the _filename ini file
_filename, ext = os.path.splitext(self._filename)
filename = pyu.getlong(_filename + '.osm', 'struc/osm')
if os.path.exists(filename):
filename = pyu.getlong(_filename + '_.osm', 'struc/osm')
fd = open(filename, "w")
fd.write("<?xml version='1.0' encoding='UTF-8'?>\n")
fd.write("<osm version='0.6' upload='false' generator='PyLayers'>\n")
# creating points
for n in self.Gs.pos:
if n < 0:
if n not in self.lboundary:
if self.format == 'latlon':
lon, lat = self.Gs.pos[n]
if self.format == 'cart':
x, y = self.Gs.pos[n]
lon, lat = self.m(x, y, inverse=True)
fd.write("<node id='" + str(n) + "' action='modify' visible='true' lat='" +
str(lat) + "' lon='" + str(lon) + "' />\n")
for n in self.Gs.pos:
if n > 0:
#
# Conditions pour ajout segments
#
# _AIR are not added
#
# outdoor AIR wall above buildings are not added
# cond1 is wrong
cond1 = (self.Gs.node[n]['name'] != '_AIR')
cond2 = (self.Gs.node[n]['name'] == 'AIR')
cond3 = (self.Gs.node[n]['z'][1] == self.zceil)
cond4 = (self.Gs.node[n]['z'][0] == self.zfloor)
cond5 = (cond2 and cond3)
cond6 = (cond2 and cond4)
cond7 = (cond2 and cond3 and cond4)
if (cond1 and (not cond5) and (not cond6)) or cond7:
#v1.1 neigh = nx.neighbors(self.Gs, n)
neigh = self.Gs[n].keys()
d = self.Gs.node[n]
#
noden = -10000000 - n
fd.write("<way id='" + str(noden) +
"' action='modify' visible='true'>\n")
fd.write("<nd ref='" + str(neigh[0]) + "' />\n")
fd.write("<nd ref='" + str(neigh[1]) + "' />\n")
fd.write("<tag k='name' v='" + str(d['name']) + "' />\n")
fd.write("<tag k='z' v=\"" + str(d['z']) + "\" />\n")
fd.write("<tag k='transition' v='" +
str(d['transition']) + "' />\n")
fd.write("</way>\n")
fd.write("</osm>\n")
fd.close()
def savepickle(self):
""" save graph in pickle format
"""
pass
[docs] def save(self):
""" save Layout structure in a .lay file
"""
current_version = 1.4
if os.path.splitext(self._filename)[1]=='.ini':
self._filename = self._filename.replace('.ini','.lay')
#
# version 1.3 : suppression of index in slab and materials
#
config = ConfigParser.RawConfigParser()
config.optionxform = str
config.add_section("info")
config.add_section("points")
config.add_section("segments")
if hasattr(self,'dpoly'):
config.add_section("polygons")
config.add_section("files")
config.add_section("slabs")
config.add_section("materials")
if self.format == 'latlon':
config.set("info", "format", "latlon")
else:
config.set("info", "format", "cart")
config.set("info", "version", current_version)
config.set("info", "type", self.typ)
if self.typ == 'indoor':
config.add_section("indoor")
config.set("indoor", "zceil", self.zceil)
config.set("indoor", "zfloor", self.zfloor)
if self.typ == 'outdoor':
config.add_section("outdoor")
#
# save bounding box in latlon for reconstruction of self.m
#
if hasattr(self,"m"):
config.add_section("latlon")
config.set("latlon","llcrnrlon",self.m.llcrnrlon)
config.set("latlon","llcrnrlat",self.m.llcrnrlat)
config.set("latlon","urcrnrlon",self.m.urcrnrlon)
config.set("latlon","urcrnrlat",self.m.urcrnrlat)
config.set("latlon","projection",self.m.projection)
# config.set("info",'Nsegments',self.Ns)
# config.set("info",'Nsubsegments',self.Nss)
#for k in self.display:
# config.set("display", k, self.display[k])
# iterate on points
# boundary nodes and air walls are not saved
for n in self.Gs.pos:
if n < 0:
if n not in self.lboundary:
config.set("points", str(n), (self.Gs.pos[n][0], self.Gs.pos[n][1]))
# iterate on segments
for n in self.Gs.pos:
if n > 0:
cond1 = (self.Gs.node[n]['name'] != '_AIR')
cond2 = (self.Gs.node[n]['name'] == 'AIR')
cond3 = (self.Gs.node[n]['z'][1] == self.zceil)
cond4 = (self.Gs.node[n]['z'][0] == self.zfloor)
cond5 = (cond2 and cond3)
cond6 = (cond2 and cond4)
cond7 = (cond2 and cond3 and cond4)
#
# _AIR are not stored (cond1)
# AIR segment reaching zceil are not stored (cond4)
# AIR segment reaching zfloor are not stored (cond5)
#
if (cond1 and (not cond5) and (not cond6)) or cond7:
d = copy.deepcopy(self.Gs.node[n])
# v1.1 d['connect'] = nx.neighbors(self.Gs, n)
d['connect'] = list(self.Gs[n].keys())
try:
if d['transition']:
pass
except:
d['transition'] = False
try:
if 'DOOR' in d['ss_name']:
d['transition'] = True
except:
pass
# remove normal information from the strucure
try:
d.pop('norm')
except:
pass
# remove iso information from the strucure
try:
d.pop('iso')
except:
pass
# remove ncycles information from the strucure
try:
d.pop('ncycles')
except:
pass
# transition are saved only if True
if not d['transition']:
d.pop('transition')
# offset are saved only if not zero
if 'offset' in d:
if d['offset']==0:
d.pop('offset')
config.set("segments", str(n), d)
#
# [polygon]
# 1 = { 'connect':[1,2,3,4], 'z':(100,115),name:''}
#
if hasattr(self,'dpoly'):
for k in self.dpoly:
config.set("polygons", str(k), self.dpoly[k])
#
# [ slabs ]
#
# get the list of used slabs
lslab = [x for x in self.name if len(self.name[x]) > 0]
lmat = []
#
# In case an osm file has been read; there is no .sl
# By default all the available slabs and materials are provided
#
if not hasattr(self,'sl'):
self.sl = sb.SlabDB(filemat='matDB.ini', fileslab='slabDB.ini')
for s in lslab:
ds = {}
if s not in self.sl:
if s not in self.sl.mat:
self.sl.mat.add(name=s,cval=6,sigma=0,typ='epsr')
self.sl.add(s,[s],[0.1])
#ds['index'] = self.sl[s]['index']
ds['color'] = self.sl[s]['color']
ds['lmatname'] = self.sl[s]['lmatname']
for m in ds['lmatname']:
if m not in lmat:
lmat.append(m)
ds['lthick'] = self.sl[s]['lthick']
ds['linewidth'] = self.sl[s]['linewidth']
config.set("slabs", s, ds)
if "_AIR" not in lslab:
air = {'color': 'white', 'linewidth': 1,
'lthick': [0.1], 'lmatname': ['AIR']}
config.set("slabs", "_AIR", air)
if "AIR" not in lslab:
air = {'color': 'white', 'linewidth': 1,
'lthick': [0.1], 'lmatname': ['AIR']}
config.set("slabs", "AIR", air)
if "CEIL" not in lslab:
ceil = {'color': 'grey20', 'linewidth': 1,
'lthick': [0.1], 'lmatname': ['REINFORCED_CONCRETE']}
config.set("slabs", "CEIL", ceil)
if "FLOOR" not in lslab:
floor = {'color': 'grey40', 'linewidth': 1,
'lthick': [0.1], 'lmatname': ['REINFORCED_CONCRETE']}
config.set("slabs", "FLOOR", floor)
#
# [ materials ]
#
for m in lmat:
dm = self.sl.mat[m]
try:
dm.pop('name')
except:
pass
# store UIT format only if it is used
if 'a' in dm:
if dm['a'] ==None:
dm.pop('a')
dm.pop('b')
dm.pop('c')
dm.pop('d')
config.set("materials", m, dm)
if "REINFORCED_CONCRETE" not in lmat:
reic = {'mur': (
1 + 0j), 'epr': (8.69999980927 + 0j), 'roughness': 0.0, 'sigma': 3.0}
config.set("materials", "REINFORCED_CONCRETE", reic)
# config.set("files",'materials',self.filematini)
# config.set("files",'slab',self.fileslabini)
#
# [ furniture ]
#
config.set("files", 'furniture', self._filefur)
#
# handling olf format ( to be removed later)
#
if os.path.splitext(self._filename)[1]=='.ini':
fileout = self._filename.replace('.ini','.lay')
else:
fileout = self._filename
filelay = pyu.getlong(fileout, pro.pstruc['DIRLAY'])
print(filelay)
fd = open(filelay, "w")
config.write(fd)
fd.close()
# convert graph Gs to numpy arrays for speed up post processing
# ideally an edited Layout should be locked while not saved.
# self.g2npy()
self._hash = hashlib.md5(open(filelay, 'rb').read()).hexdigest()
def load_fast(self):
""" load a layout from a .lay file
The filename is in self._filename
Format version 1.3
------------------
[info]
format = {cart | latlon}
version =
type = {indoor | outdoor}
[points]
-1 = (x,y)
[segments]
1 = {'slab':'',transition:boolean,'connect:[-1,-2],'z':(0,3)}
[slabs]
WALL = {'lthick':[,],'lmat':[,],'color:'','linewidth':float}
[materials]
BRICK = {'mur':complex,'epsr':complex,'sigma':float,'roughness':}
[polygons]
1 = {'connect':[1,2,3,4],'name':NAME,'z':(zmin,zmax)}
[indoor]
zceil =
zfloor =
[latlon]
llcrnrlon =
llcrnrlat =
urcrnrlon =
urcrnrlat =
projection =
"""
logger.info('load lay file in load fast')
# di : dictionnary which reflects the content of ini file
di = {}
config = ConfigParser.RawConfigParser()
config.optionxform = str
filelay = pyu.getlong(self._filename, pro.pstruc['DIRLAY'])
config.read(filelay)
sections = config.sections()
for section in sections:
di[section] = {}
options = config.options(section)
for option in options:
try:
di[section][option] = config.get(section, option)
except:
print(section, option)
self.Np = len(di['points'])
self.Ns = len(di['segments'])
#
# Ng : number of polygons
# polygons introduced in 1.4 format
#
if config.has_section('polygons'):
self.Ng = len(di['polygons'])
self.Gs = nx.Graph(name='Gs')
self.Gs.pos = {}
self.labels = {}
#
# [info]
# format {cart,latlon}
# version int
# type {'indoor','outdoor'}
if 'version' in di['info']:
self.version = di['info']['version']
if 'type' in di['info']:
self.typ = di['info']['type']
self.name = {}
if ((self.typ!='indoor') &
(self.typ!='outdoor') &
(self.typ!='floorplan')):
print("invalid file type in ",self._filename)
return(None)
#
# [indoor]
# zceil
# zfloor
#
if self.typ == 'indoor':
self.zceil = eval(di['indoor']['zceil'])
self.zfloor = eval(di['indoor']['zfloor'])
# old format
if self.typ == 'floorplan':
self.zceil = eval(di['floorplan']['zceil'])
self.zfloor = eval(di['floorplan']['zfloor'])
# from format 1.3 floorplan is call indoor
if self.typ=='floorplan':
self.typ = 'indoor'
#
# [outdoor]
# TODO add a DEM file
#
if self.typ == 'outdoor':
if 'outdoor' in di:
if 'zceil' in di['outdoor']:
self.zceil = eval(di['outdoor']['zceil'])
else:
self.zceil = 3000 # upper limit for AIR wall
if 'zfloor' in di['outdoor']:
self.zfloor = eval(di['outdoor']['zfloor'])
else:
self.zfloor = 0
else:
self.zfloor = 0
self.zceil = 3000 # upper limit for AIR walls
#
#
# manage ini file with latlon coordinates
#
# if the format is latlon, coordinates are converted into
# cartesian coordinates with the coords.cartesian method
#
logger.info('load latlon coordinates and convert')
if 'format' in di['info']:
if di['info']['format'] == 'latlon':
or_coord_format = 'latlon'
coords = osm.Coords()
coords.clean()
coords.latlon = {eval(i): np.array( eval(di['points'][i])) for i in di['points']}
coords.boundary = np.hstack((np.min(np.vstack(coords.latlon.values()), axis=0),
np.max(np.vstack(coords.latlon.values()), axis=0)))
assert(len(coords.boundary)==4)
coords.cartesian(cart=True)
else:
or_coord_format = 'cart'
else:
or_coord_format = 'cart'
#
# update display section
#
logger.info('load_fast : update display section')
if 'display' in di:
for k in di['display']:
try:
self.display[k] = eval(di['display'][k])
except:
self.display[k] = di['display'][k]
# self.ax = self.display['box']
#
# [points]
#
# update points section
logger.info('load_fast : reading points')
lnodeindex = [ eval(x) for x in di['points']]
self.Gs.add_nodes_from(lnodeindex) # add point node
if self.format=='cart':
self.Gs.pos = { eval(i) : eval(di['points'][i]) for i in di['points']}
else:
self.Gs.pos = { i : coords.xy[i] for i in coords.xy}
# #
# # limitation of point precision is important for avoiding
# # topological problems in shapely.
# # Layout precision is hard limited to millimeter precision.
# #
#self.Gs.pos[nodeindex] = (
# round(1000 * x) / 1000., round(1000 * y) / 1000.)
#self.labels[nodeindex] = nn
#
# [segments]
#
# update segments section
self.name['AIR'] = []
self.name['_AIR'] = []
#
# get the maximum index
#
maxnum = max([eval(x) for x in di['segments'].keys()])
logger.info('load_fast : reading segments')
lsegnum = np.sort([ eval(x) for x in di['segments'].keys() ])
maxnum = lsegnum[-1]
for k in lsegnum:
d = eval(di['segments'][str(k)])
nta = d['connect'][0]
nhe = d['connect'][1]
name = d['name']
z = d['z']
if not 'transition' in d:
transition = False
else:
transition = d['transition']
if not 'offset' in d:
offset = 0
else:
offset = d['offset']
# add new segment
#
# The segment number is the same as in the .lay file
#
# Very useful feature
#
if self.typ=='indoor':
boutdoor = False
else:
boutdoor = True
num = self.add_segment(nta, nhe,
num = k,
name = name,
transition = transition,
offset = offset,
z = z,
maxnum = maxnum,
boutdoor = boutdoor)
# only for indoor
# exploit iso for segment completion (AIR type)
# Complement single segment which do not reach zceil or zfloor with
# an iso segment with AIR property
#
#if (self.typ == 'indoor') or (self.typ == 'outdoor'):
if (self.typ == 'indoor'):
segdone = []
logger.info('segments completion')
for key in di['segments']:
iseg = eval(key)
d = eval(di['segments'][key])
nta = d['connect'][0]
nhe = d['connect'][1]
# if not already done
if iseg not in segdone:
# get all the iso from the segment key
iso = copy.copy(self.Gs.node[iseg]['iso'])
# append key to iso
iso.append(iseg)
# stack all the intervals in increasing order
ziso = []
for ns in iso:
ziso.append(self.Gs.node[ns]['z'])
# get the complementary intervals
if self.typ == 'outdoor':
zmin = 1e6
zmax = -1e6
for iz in ziso:
zmin = np.minimum(zmin,min(iz))
zmax = np.maximum(zmax,max(iz))
ziso = [(zmin,zmax)]
# pyutil compint (get complementary interval)
zair = pyu.compint(ziso,self.zfloor,self.zceil)
# add AIR wall in the intervals
for za in zair:
num = self.add_segment(nta, nhe,
name='AIR',
offset=0,
z=(za[0], za[1]))
segdone = segdone + iso
#
# add _AIR wall around the layout
#
self.boundary(bg2npy = False)
# load poygons
if config.has_section('polygons'):
logger.info("reading polygons")
self.dpoly = { k : eval(di['polygons'][k]) for k in di['polygons']}
#
# TODO convert keys into int
# compliant with config file without material/slab information
#
# {latlon]
#
if config.has_section('latlon'):
llcrnrlon = eval(config.get('latlon', 'llcrnrlon'))
llcrnrlat = eval(config.get('latlon', 'llcrnrlat'))
urcrnrlon = eval(config.get('latlon', 'urcrnrlon'))
urcrnrlat = eval(config.get('latlon', 'urcrnrlat'))
projection = config.get('latlon','projection')
lon_0 = (llcrnrlon+urcrnrlon)/2.
lat_0 = (llcrnrlat+urcrnrlat)/2.
# Construction of Basemap for coordinates transformation
self.m = Basemap(llcrnrlon=llcrnrlon,
llcrnrlat=llcrnrlat,
urcrnrlon=urcrnrlon,
urcrnrlat=urcrnrlat,
resolution='i',
projection=projection,
lon_0=lon_0,
lat_0=lat_0)
self.extent = (llcrnrlon,urcrnrlon,llcrnrlat,urcrnrlat)
self.pll = self.m(self.extent[0],self.extent[2])
self.pur = self.m(self.extent[1],self.extent[3])
self.extent_c = (self.pll[0],self.pur[0],self.pll[1],self.pur[1])
if config.has_section('files'):
# self.filematini=config.get('files','materials')
# self.fileslabini=config.get('files','slab')
self.filefur = config.get('files', 'furniture')
if config.has_section('slabs'):
#filemat = self._filename.replace('ini', 'mat')
#fileslab = self._filename.replace('ini', 'slab')
ds = di['slabs']
dm = di['materials']
for k in ds:
ds[k] = eval(ds[k])
for k in dm:
dm[k] = eval(dm[k])
self.sl = sb.SlabDB(ds=ds, dm=dm)
# In this section we handle the ini file format evolution
if 'fileoverlay' in self.display:
self.display['overlay_file'] = self.display.pop('fileoverlay')
self.display['overlay_axis'] = self.display['box']
self.save()
if 'inverse' in self.display:
self.display['overlay_flip'] = ""
self.display.pop('inverse')
self.save()
# convert graph Gs to numpy arrays for faster post processing
logger.info('graph 2 numpy : g2npy')
self.g2npy()
# This hash should be saved with the gpickle file
logger.info('save the hash')
dirname = self._filename.replace('.lay','')
path = os.path.join(pro.basename, 'struc', 'gpickle', dirname)
if not os.path.exists(path):
os.mkdir(path)
fd = open(os.path.join(path,'.hash'),'w')
fd.write(self._hash)
fd.write('\n'+str(self.segboundary))
fd.write('\n'+self.typ)
fd.close()
logger.info('dump a pickle of Gs')
self.lbltg = ['s']
self.dumpw()
[docs] def load(self):
""" load a layout from a .lay file
The filename is in self._filename
Format version 1.4
------------------
[info]
format = {cart | latlon}
version =
type = {indoor | outdoor}
[points]
-1 = (x,y)
[segments]
1 = {'slab':'',transition:boolean,'connect:[-1,-2],'z':(0,3)}
[slabs]
WALL = {'lthick':[,],'lmat':[,],'color:'','linewidth':float}
[materials]
BRICK = {'mur':complex,'epsr':complex,'sigma':float,'roughness':}
[polygons]
1 = {'connect':[1,2,3,4],'name':NAME,'z':(zmin,zmax)}
[indoor]
zceil =
zfloor =
[latlon]
llcrnrlon =
llcrnrlat =
urcrnrlon =
urcrnrlat =
projection =
"""
logger.info('load lay file')
# di : dictionnary which reflects the content of ini file
di = {}
config = ConfigParser.RawConfigParser()
config.optionxform = str
filelay = pyu.getlong(self._filename, pro.pstruc['DIRLAY'])
config.read(filelay)
sections = config.sections()
for section in sections:
di[section] = {}
options = config.options(section)
for option in options:
try:
di[section][option] = config.get(section, option)
except:
print(section, option)
self.Np = len(di['points'])
self.Ns = len(di['segments'])
#
# Ng : number of polygons
# polygons introduced in 1.4 format
#
if config.has_section('polygons'):
self.Ng = len(di['polygons'])
self.Gs = nx.Graph(name='Gs')
self.Gs.pos = {}
self.labels = {}
#
# [info]
# format {cart,latlon}
# version int
# type {'indoor','outdoor'}
if 'version' in di['info']:
self.version = di['info']['version']
if 'type' in di['info']:
self.typ = di['info']['type']
self.name = {}
if ((self.typ!='indoor') &
(self.typ!='outdoor') &
(self.typ!='floorplan')):
print("invalid file type in ",self._filename)
return(None)
#
# [indoor]
# zceil
# zfloor
#
if self.typ == 'indoor':
self.zceil = eval(di['indoor']['zceil'])
self.zfloor = eval(di['indoor']['zfloor'])
# old format
if self.typ == 'floorplan':
self.zceil = eval(di['floorplan']['zceil'])
self.zfloor = eval(di['floorplan']['zfloor'])
# from format 1.3 floorplan is call indoor
if self.typ=='floorplan':
self.typ = 'indoor'
#
# [outdoor]
# TODO add a DEM file
#
if self.typ == 'outdoor':
if 'outdoor' in di:
if 'zceil' in di['outdoor']:
self.zceil = eval(di['outdoor']['zceil'])
else:
self.zceil = 3000 # upper limit for AIR wall
if 'zfloor' in di['outdoor']:
self.zfloor = eval(di['outdoor']['zfloor'])
else:
self.zfloor = 0
else:
self.zfloor = 0
self.zceil = 3000 # upper limit for AIR walls
#
#
# manage ini file with latlon coordinates
#
# if the format is latlon, coordinates are converted into
# cartesian coordinates with the coords.cartesian method
#
logger.info('load coordinates')
if 'format' in di['info']:
if di['info']['format'] == 'latlon':
or_coord_format = 'latlon'
coords = osm.Coords()
coords.clean()
coords.latlon = {i: np.array( eval(di['points'][i])) for i in di['points']}
coords.boundary = np.hstack((np.min(np.array(coords.latlon.values()), axis=0),
np.max(np.array(coords.latlon.values()), axis=0)))
coords.cartesian(cart=True)
else:
or_coord_format = 'cart'
else:
or_coord_format = 'cart'
#
# update display section
#
logger.info('update display section')
if 'display' in di:
for k in di['display']:
try:
self.display[k] = eval(di['display'][k])
except:
self.display[k] = di['display'][k]
# self.ax = self.display['box']
#
# [points]
#
# update points section
logger.info('reading points')
for nn in di['points']:
nodeindex = eval(nn)
if or_coord_format == 'latlon':
x, y = coords.xy[nn]
else:
x, y = eval(di['points'][nn])
#
# limitation of point precision is important for avoiding
# topological problems in shapely.
# Layout precision is hard limited to millimeter precision.
#
self.Gs.add_node(nodeindex) # add point node
self.Gs.pos[nodeindex] = ( round(1000 * x) / 1000., round(1000 * y) / 1000.)
self.labels[nodeindex] = nn
#
# [segments]
#
# update segments section
self.name['AIR'] = []
self.name['_AIR'] = []
#
# get the maximum index
#
maxnum = max([eval(x) for x in di['segments'].keys()])
logger.info('reading segments')
for key in di['segments']:
d = eval(di['segments'][key])
nta = d['connect'][0]
nhe = d['connect'][1]
#print(key,nta,nhe)
name = d['name']
z = d['z']
if not 'transition' in d:
transition = False
else:
transition = d['transition']
if not 'offset' in d:
offset = 0
else:
offset = d['offset']
# add new segment
#
# The segment number is the same as in the .lay file
#
# Very useful feature
#
num = self.add_segment(nta, nhe,
num = eval(key),
name = name,
transition = transition,
offset = offset,
z = z)
# exploit iso for segment completion (AIR type)
#
# Complement single segment which do not reach zceil or zfloor with
# an iso segment with AIR property
#
segdone = []
logger.info('segments completion')
for key in di['segments']:
iseg = eval(key)
d = eval(di['segments'][key])
nta = d['connect'][0]
nhe = d['connect'][1]
# if not already done
if iseg not in segdone:
# get all the iso from the segment key
iso = copy.copy(self.Gs.node[iseg]['iso'])
# append key to iso
iso.append(iseg)
# stack all the intervals in increasing order
ziso = []
for ns in iso:
ziso.append(self.Gs.node[ns]['z'])
# get the complementary intervals
if self.typ == 'outdoor':
zmin = 1e6
zmax = -1e6
for iz in ziso:
zmin = np.minimum(zmin,min(iz))
zmax = np.maximum(zmax,max(iz))
ziso = [(zmin,zmax)]
# pyutil compint (get complementary interval)
zair = pyu.compint(ziso,self.zfloor,self.zceil)
# add AIR wall in the intervals
for za in zair:
num = self.add_segment(nta, nhe,
name='AIR',
offset=0,
z=(za[0], za[1]))
segdone = segdone + iso
#
# add _AIR wall around the layout
#
self.boundary()
if config.has_section('polygons'):
logger.info("reading polygons")
self.dpoly = di['polygons']
# compliant with config file without material/slab information
#
# {latlon]
#
if config.has_section('latlon'):
llcrnrlon = eval(config.get('latlon', 'llcrnrlon'))
llcrnrlat = eval(config.get('latlon', 'llcrnrlat'))
urcrnrlon = eval(config.get('latlon', 'urcrnrlon'))
urcrnrlat = eval(config.get('latlon', 'urcrnrlat'))
projection = config.get('latlon','projection')
lon_0 = (llcrnrlon+urcrnrlon)/2.
lat_0 = (llcrnrlat+urcrnrlat)/2.
# Construction of Basemap for coordinates transformation
self.m = Basemap(llcrnrlon=llcrnrlon,
llcrnrlat=llcrnrlat,
urcrnrlon=urcrnrlon,
urcrnrlat=urcrnrlat,
resolution='i',
projection=projection,
lon_0=lon_0,
lat_0=lat_0)
self.extent = (llcrnrlon,urcrnrlon,llcrnrlat,urcrnrlat)
self.pll = self.m(self.extent[0],self.extent[2])
self.pur = self.m(self.extent[1],self.extent[3])
self.extent_c = (self.pll[0],self.pur[0],self.pll[1],self.pur[1])
if config.has_section('files'):
# self.filematini=config.get('files','materials')
# self.fileslabini=config.get('files','slab')
self._filefur = config.get('files', 'furniture')
if config.has_section('slabs'):
#filemat = self._filename.replace('ini', 'mat')
#fileslab = self._filename.replace('ini', 'slab')
ds = di['slabs']
dm = di['materials']
for k in ds:
ds[k] = eval(ds[k])
for k in dm:
dm[k] = eval(dm[k])
self.sl = sb.SlabDB(ds=ds, dm=dm)
# In this section we handle the ini file format evolution
if 'fileoverlay' in self.display:
self.display['overlay_file'] = self.display.pop('fileoverlay')
self.display['overlay_axis'] = self.display['box']
self.save()
if 'inverse' in self.display:
self.display['overlay_flip'] = ""
self.display.pop('inverse')
self.save()
# convert graph Gs to numpy arrays for faster post processing
logger.info('g2npy')
self.g2npy()
#
fd = open(filelay,'rb')
self._hash = hashlib.md5(fd.read()).hexdigest()
fd.close()
[docs] def loadfur(self, _filefur):
""" loadfur load a furniture file
Parameters
----------
_filefur : string
short name of the furniture ini file
Notes
-----
Furniture objects are stored in self.lfur list
Examples
--------
Load a Layout file and an associated furniture ini file
.. plot::
:include-source:
>>> import matplotlib.pyplot as plt
>>> from pylayers.gis.layout import *
>>> L = Layout('WHERE1.lay')
>>> L.loadfur('Furw1.ini')
>>> fig = plt.figure()
>>> ax = fig.gca()
>>> fig,ax = L.showGs(fig=fig,ax=ax,furniture=True)
>>> ti = plt.title('loadfur')
>>> plt.show()
"""
filefur = pyu.getlong(_filefur, pro.pstruc['DIRFUR'])
config = ConfigParser.ConfigParser()
config.read(filefur)
furname = config.sections()
self.lfur = []
for name in furname:
F = fur.Furniture()
F.load(_filefur, name)
self.lfur.append(F)
self.filefur = _filefur
[docs] def load_modif(self, _filename, build=True, cartesian=False, dist_m=400):
""" load a Layout in different formats
Parameters
----------
_filename : string
Notes
-----
+ .lay : ini file format (natural one) DIRLAY
"""
newfile = False
filename = pyu.getlong(_filename, pro.pstruc['DIRLAY'])
if os.path.exists(filename): # which exists
self.loadini(arg)
else: # which do not exist
self._filename = _filename
newfile = True
print("new file", self._filename)
# construct geomfile (.off) for vizualisation with geomview
self.subseg()
if not newfile:
try:
self.geomfile()
except:
print("problem to construct geomfile")
# if check:
# self.check()
self.boundary(dx=10, dy=10)
# create shapely polygons L._shseg
[docs] def subseg(self):
""" establishes the association : name <-> edgelist
Returns
-------
dico : dict
sub segment name as key and segment number as value
"""
dico = {}
listtransition = []
for k in self.Gs.node.keys():
dk = self.Gs.node[k]
if 'transition' in dk:
transition = dk['transition']
if transition:
listtransition.append(k)
if 'ss_name' in dk:
lname = dk['ss_name']
for j, name in enumerate(lname):
if name in dico:
dico[name].append((k, j))
else:
dico[name] = [(k, j)]
self.dsseg = dico
self.listtransition = listtransition
return(dico)
[docs] def add_pnod(self, p, e1, e2):
""" Project point p on segment e1 along segment e2
Parameters
----------
p : ndarray
point
e1 : int
edge number 1
e2 : int
edge number 2
..todo
This function is void
"""
#p1 = p + alpha*ve2
#p1 = pa + beta * (pb-pa)
pass
[docs] def add_fnod(self, p=(0.0, 0.0)):
""" add free node p
Parameters
----------
p : (1x2) tuple
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('defstr.lay')
>>> L.add_fnod((10.0,10.0))
-13
"""
# next free node
if len(self.Gs.node)>0:
num = -( -min(self.Gs.node) + 1 )
else:
num = -1
self.Gs.add_node(num)
self.Gs.pos[num] = p
self.Np = self.Np + 1
# update labels
self.labels[num] = str(num)
return(num)
[docs] def add_nfpe(self, np0, s1, s2):
""" Add node on s1 from projection of np0 along s2
Parameters
----------
np0 : point number
s1 : edge number 1
s2 : edge number 2
"""
np1 = list(self.Gs[s1].keys())
np2 = list(self.Gs[s2].keys())
xA = self.Gs.pos[np1[0]][0]
yA = self.Gs.pos[np1[0]][1]
xB = self.Gs.pos[np1[1]][0]
yB = self.Gs.pos[np1[1]][1]
xC = self.Gs.pos[np2[0]][0]
yC = self.Gs.pos[np2[0]][1]
xD = self.Gs.pos[np2[1]][0]
yD = self.Gs.pos[np2[1]][1]
xP = self.Gs.pos[np0][0]
yP = self.Gs.pos[np0][1]
A = np.array([[xB - xA, xD - xC], [yB - yA, yD - yC]])
b = np.array([xP - xA, yP - yA])
x = sp.linalg.solve(A, b)
if ((x[0] > 0.) & (x[0] < 1.0)):
self.add_pons(s1, 1 - x[0])
[docs] def add_pons(self, ns, alpha=0.5):
""" add point on segment
Parameters
----------
ns : int
segment number
alpha : parameterization of the point
alpha = 0 (tail) alpha = 1 (head)
Notes
-----
delete segment ns
create 2 segments with same properties
"""
# v1.1 nop = self.Gs.neighbors(ns)
nop = list(self.Gs[ns])
namens = self.Gs.node[ns]['name']
zminns = self.Gs.node[ns]['z'][0]
zmaxns = self.Gs.node[ns]['z'][1]
p1 = np.array([self.Gs.pos[nop[0]][0], self.Gs.pos[nop[0]][1]])
p2 = np.array([self.Gs.pos[nop[1]][0], self.Gs.pos[nop[1]][1]])
p = tuple(alpha * p1 + (1 - alpha) * p2)
num = self.add_fnod(p)
# delete old edge ns
self.del_segment(ns)
# add new edge np[0] num
self.add_segment(nop[0], num, name=namens, z=[
zminns, zmaxns], offset=0)
# add new edge num np[1]
self.add_segment(num, nop[1], name=namens, z=[
zminns, zmaxns], offset=0)
[docs] def add_segment(self,n1,n2,**kwargs):
""" add segment between node n1 and node n2
Parameters
----------
n1 : integer < 0
n2 : integer < 0
num : segment index (-1 default not given)
maxnum : maximum number (-1 default not given)
name : string
layer name 'PARTITION'
z : tuple of 2 floats
default = (0,40000000)
offset : float
[-1,1] default (0)
bootdoor : boolean
if outdoor add an _AIR wall above the segment
Returns
-------
num : segment number (>0)
Notes
-----
A segment dictionnary has the following mandatory attributes
name : slab name associated with segment
z : list (zmin,zmax) (meters)
norm : array (1x3) segment normal
transition : boolean
ncycles : list of involved cycles
connect : list of point number
iso : list of isosegment
If a segment is _AIR it cannnot be duplicated
"""
num = kwargs.pop('num', -1)
maxnum = kwargs.pop('maxnum', -1)
transition = kwargs.pop('transition', False)
name = kwargs.pop('name', 'PARTITION')
offset = kwargs.pop('offset', 0)
verbose = kwargs.pop('verbose', True)
boutdoor = kwargs.pop('boutdoor', False)
zmax = kwargs.pop('zmax', 3000)
z = kwargs.pop('z', (0.0, zmax))
# if 2 points are selected
if ((n1 < 0) & (n2 < 0) & (n1 != n2)):
nseg = [s for s in self.Gs.node if s > 0]
if num==-1:
if len(nseg) > 0:
num = max(maxnum+1, max(nseg) + 1) # index not given
else: # first segment index not given
num = 1
else:
pass # segment index given
else:
if verbose:
print("add_segment : error not a node", n1, n2)
return
# transition = False
if (name == '_AIR'):
# if name == 'AIR':
transition = True
#
# unit vector along horizontal segment
#
p1 = np.array(self.Gs.pos[n1])
p2 = np.array(self.Gs.pos[n2])
p2mp1 = p2 - p1
t = p2mp1 / np.sqrt(np.dot(p2mp1, p2mp1))
#
# n = t x z (2D)
#
norm = np.array([t[1], -t[0], 0])
#
# Two segments with the same end points are iso segments
#
# Determine if there are existing segments with the same neighbors ?
nbnta = self.Gs[n1].keys()
nbnhe = self.Gs[n2].keys()
#v1.1 nbnta = self.Gs.neighbors(n1)
#nbnhe = self.Gs.neighbors(n2)
#
# add a segment node to Gs
#
if boutdoor == True:
self.Gs.add_node(num, name=name,
z = z,
norm = norm,
transition = transition,
offset = offset,
connect = [n1, n2],
iso = [num + maxnum],
ncycles = []
)
self.Gs.add_node(num + maxnum, name='AIR',
z = (z[1], zmax),
norm = norm,
transition = True,
offset = offset,
connect = [n1, n2],
iso = [num],
ncycles = [])
else:
#
# BAD IDEA : Not scalable
#
same_seg = list(set(nbnta).intersection(nbnhe))
#
# Impossible to have duplicated _AIR
#
# Warning : The 3 following lines are very important
# it breaks buildGt if commented
# Please do not comment them.
#
if (name == '_AIR'):
if len(same_seg) > 0:
return None
self.Gs.add_node(num, name=name,
z = z,
norm = norm,
transition = transition,
offset = offset,
connect = [n1, n2],
iso = [],
ncycles = []
)
#
# update iso of the 2 segments
#
for k in same_seg:
if num not in self.Gs.node[k]['iso']:
self.Gs.node[k]['iso'].append(num)
if k not in self.Gs.node[num]['iso']:
self.Gs.node[num]['iso'].append(k)
#
# Segment point position is placed at the middle of segment
#
self.Gs.pos[num] = tuple((p1 + p2) / 2.)
#
# Connectivity between segment node num and points nodes n1 and n2
#
self.Gs.add_edge(n1, num)
self.Gs.add_edge(n2, num)
if boutdoor:
self.Gs.add_edge(n1, num + maxnum)
self.Gs.add_edge(n2, num + maxnum)
#
# Update current total number of segments
#
self.Ns = self.Ns + 2
try:
self.name[name].append(num)
self.name['AIR'].append(num + maxnum)
except:
self.name[name] = [num]
self.name['AIR'] = [num+ maxnum]
# update label
self.labels[num] = str(num)
self.labels[num + maxnum] = str(num + maxnum)
else:
self.Ns = self.Ns + 1
# update slab name <-> edge number dictionnary
try:
self.name[name].append(num)
except:
self.name[name] = [num]
# update label
self.labels[num] = str(num)
if name not in self.display['layers']:
self.display['layers'].append(name)
# update shseg
self._shseg.update({num:sh.LineString((self.Gs.pos[n1], self.Gs.pos[n2]))})
return(num)
[docs] def merge_segment(self,n1,n2):
""" merge segment n2 included in n1
Parameters
----------
n1 : int
segment 1 (the larger) index
n2 : int
segment 2 (the smaller) index
"""
# get height/slabname information from segment n1
zn1 = self.Gs.node[n1]['z']
namen1 = self.Gs.node[n1]['name']
# get height/slabname information from segment n2
zn2 = self.Gs.node[n2]['z']
namen2 = self.Gs.node[n2]['name']
if min(zn1)<min(zn2):
znlow = (min(zn1),min(zn2))
if max(zn1)>max(zn2):
znhigh = (max(zn2),max(zn1))
# get termination points of segment n1 (p1 -- p4)
conn_n1 = self.Gs.node[n1]['connect']
conn_n2 = self.Gs.node[n2]['connect']
p1_index = conn_n1[0]
p4_index = conn_n1[1]
p2_index = conn_n2[0]
p3_index = conn_n2[1]
p1 = np.r_[self.Gs.pos[p1_index]]
p2 = np.r_[self.Gs.pos[p2_index]]
p3 = np.r_[self.Gs.pos[p3_index]]
p4 = np.r_[self.Gs.pos[p4_index]]
# determine point order p1 - p2 - p3 - p4
v14 = p4 - p1
v23 = p3 - p2
if np.dot(v14,v23)<0:
p2_index, p3_index = p3_index, p2_index
p2, p3 = p3, p2
# 1 delete segment n1
self.del_segment([n1])
# create new segment p1 - p2
self.add_segment(p1_index, p2_index, z=zn1, name=namen1)
# create new segment p3 - p4
self.add_segment(p3_index, p4_index, z=zn1, name=namen1)
# create new segment p2 - p3 with complementary heights
if 'zlow' in locals():
self.add_segment(p2_index, p3_index, z=znlow, name=namen1)
if 'zhigh' in locals():
self.add_segment(p2_index, p3_index, z=znhigh, name=namen1)
[docs] def repair(self,dseg):
""" repair layout
Parameters
----------
dseg : dict
{ns : [np1,np2]}
Notes
-----
Merge the superposed segments which has been determined by the check
method.
"""
for nseg in dseg:
num_p = dseg[nseg]
if len(num_p)==2:
ns1 = np.r_[nx.neighbors(self.Gs,num_p[0])]
ns2 = np.r_[nx.neighbors(self.Gs,num_p[1])]
ns_inter = np.intersect1d(ns1,ns2)
for nseg2 in ns_inter:
if ((self.Gs.node[nseg2]['name']!='AIR')
and ((self.Gs.node[nseg2]['name']!='_AIR'))):
self.merge_segment(nseg,nseg2)
[docs] def wedge2(self, apnt):
""" calculate wedge angle of a point
Parameters
----------
lpnt : array int
list of point number
"""
if isinstance(apnt, list):
apnt = np.array(apnt)
# 0. Find the position of diffraction point
ptdiff = self.pt[:, self.iupnt[-apnt]]
# 1. Find the associated segments and positions of a diff points
#v1.1 aseg = map(lambda x: filter(lambda y: y not in self.name['AIR'],
# nx.neighbors(self.Gs, x)),
# apnt)
aseg = map(lambda x: filter(lambda y: y not in self.name['AIR'],
self.Gs[x].keys()),apnt)
# manage flat angle : diffraction by flat segment e.g. door limitation)
[aseg[ix].extend(x) for ix, x in enumerate(aseg) if len(x) == 1]
# get points positions
pts = np.array(map(lambda x: self.seg2pts([x[0], x[1]]), aseg))
pt1 = pts[:, 0:2, 0] # tail seg1
ph1 = pts[:, 2:4, 0] # head seg1
pt2 = pts[:, 0:2, 1] # tail seg2
ph2 = pts[:, 2:4, 1] # head seg2
# 2. Make the correct association
# pts is (nb_diffraction_points x 4 x 2)
# - The dimension 4 represent the 2x2 points: t1,h1 and t2,h2
# tail and head of segemnt 1 and 2 respectively
# a segment
# - The dimension 2 is x,y
#
# The following aims to determine which tails and heads of
# segments associated to a give diffraction point
# are connected
# point diff is pt1
updpt1 = np.where(np.sum(ptdiff.T == pt1, axis=1) == 2)[0]
# point diff is ph1
updph1 = np.where(np.sum(ptdiff.T == ph1, axis=1) == 2)[0]
# point diff is pt2
updpt2 = np.where(np.sum(ptdiff.T == pt2, axis=1) == 2)[0]
# point diff is ph2
updph2 = np.where(np.sum(ptdiff.T == ph2, axis=1) == 2)[0]
pa = np.empty((len(apnt), 2))
pb = np.empty((len(apnt), 2))
# seg 1 :
# if pt1 diff point => ph1 is the other point
pa[updpt1] = ph1[updpt1]
# if ph1 diff point => pt1 is the other point
pa[updph1] = pt1[updph1]
# seg 2 :
# if pt2 diff point => ph2 is the other point
pb[updpt2] = ph2[updpt2]
# if ph2 diff point => pt2 is the other point
pb[updph2] = pt2[updph2]
# pt is the diffraction point
pt = ptdiff.T
vptpa = pt - pa
vptpan = vptpa.T / np.sqrt(np.sum((vptpa) * (vptpa), axis=1))
vptpb = pt - pb
vptpbn = vptpb.T / np.sqrt(np.sum((vptpb) * (vptpb), axis=1))
v1 = vptpan
v2 = vptpbn
ang = geu.vecang(vptpbn, vptpan)
ang[~uleft] = geu.vecang(vptpan, vptpan)
[docs] def wedge(self, lpnt):
""" calculate wedge angle of a point
Parameters
----------
lpnt : list of int
list of point number
"""
#v1.1 aseg = map(lambda x: filter(lambda y: y not in
# self.name['AIR'],
# nx.neighbors(self.Gs, x)),
# lpnt)
aseg = map(lambda x: filter(lambda y: y not in
self.name['AIR'],
self.Gs[x]), lpnt)
pts = np.array(map(lambda x: self.seg2pts([x[0], x[1]]).reshape(4, 2), aseg))
#map(lambda x: pt ,pts)
N = np.shape(pts)[0]
sector = []
for k in range(N):
pt1 = pts[k, 0:2, 0]
ph1 = pts[k, 2:4, 0]
pt2 = pts[k, 0:2, 1]
ph2 = pts[k, 2:4, 1]
if (pt1 == pt2).all():
pa = ph1
pb = ph2
pt = pt1
ang = geu.sector(pa, pb, pt)
if (pt1 == ph2).all():
pa = ph1
pb = pt2
pt = pt1
ang = geu.sector(pa, pb, pt)
if (ph1 == pt2).all():
pa = pt1
pb = ph2
pt = ph1
ang = geu.sector(pa, pb, pt)
if (ph1 == ph2).all():
pa = pt1
pb = pt2
pt = ph1
ang = geu.sector(pa, pb, pt)
sector.append(ang)
return(sector)
[docs] def add_furniture(self, name='R1_C', matname='PARTITION', origin=(0., 0.),
zmin=0., height=0., width=0., length=0., angle=0.):
""" add piece of furniture
Parameters
----------
name : string
default = 'R1_C'
matname : string
default = 'PARTITION'
origin : tuple of floats
height : float
default = 0
width : float
default = 0
length : float
default = 0
angle : float
default = 0
"""
# compute the four points
p0 = origin
u = np.array([np.cos(angle * np.pi / 180),
np.sin(angle * np.pi / 180)])
v = np.array([-np.sin(angle * np.pi / 180),
np.cos(angle * np.pi / 180)])
p1 = p0 + u * length
p2 = p1 + v * width
p3 = p2 - u * length
# adding free nodes
n0 = self.add_fnod(p0)
n1 = self.add_fnod(p1)
n2 = self.add_fnod(p2)
n3 = self.add_fnod(p3)
# adding segments
self.add_segment(n0, n1, name=matname, z=(zmin, zmin + height))
self.add_segment(n1, n2, name=matname, z=(zmin, zmin + height))
self.add_segment(n2, n3, name=matname, z=(zmin, zmin + height))
self.add_segment(n3, n0, name=matname, z=(zmin, zmin + height))
[docs] def add_furniture_file(self, _filefur, typ=''):
""" add pieces of furniture from .ini files
Parameters
----------
_filefur : string
"""
filefur = pyu.getlong(_filefur, pro.pstruc['DIRFUR'])
config = ConfigParser.ConfigParser()
config.read(filefur)
furname = config.sections()
for fur in furname:
name = config.get(fur, "name")
matname = config.get(fur, "matname")
origin = tuple(ast.literal_eval(config.get(fur, "origin")))
height = config.getfloat(fur, "height")
width = config.getfloat(fur, "width")
length = config.getfloat(fur, "length")
angle = config.getfloat(fur, "angle")
thickness = config.getfloat(fur, "thickness")
# ~ if matname=='WOOD':
# ~ zmin = height
# ~ height=thickness
# ~ else:
# ~ zmin=0.0
# .. todo: be more generic relate to floor level
zmin = 0.0
if typ == '':
self.add_furniture(name, matname, origin,
zmin, height, width, length, angle)
else:
try:
self.add_furniture(name, matname, origin,
zmin, height, width, length, angle)
except:
raise NameError('No such furniture type - ' + typ + '-')
[docs] def del_points(self, lp):
""" delete points in list lp
Parameters
----------
lp : list
node list
"""
# test if array
if (type(lp) == np.ndarray):
ln = list(ln)
# test if list
if (type(lp) != list):
lp = [lp]
print("lp : ", lp)
# get segments involved in points list
ls = self.nd2seg(lp)
print("ls : ", ls)
# 1) delete involved segments
for k in ls:
assert(k > 0)
self.del_segment(k)
print('del ', k)
# 2) delete involved points
for n1 in lp:
assert(n1 < 0)
# v1.1 nbrs = self.Gs.neighbors(n1)
nbrs = self.Gs[n1].keys()
self.Gs.remove_node(n1)
del self.Gs.pos[n1]
self.labels.pop(n1)
self.Np = self.Np - 1
# 3) updating structures
self.g2npy()
[docs] def del_segment(self, le, verbose=True, g2npy=True):
""" delete segments in le
Parameters
----------
le : list of segments number
See Also
--------
pylayers.gis.layout.Layout.del_node
Notes
-----
100% of time is in g2npy
"""
if (type(le) == np.ndarray):
le = list(le)
if (type(le) != list):
le = [le]
for e in le:
assert(e > 0)
name = self.Gs.node[e]['name']
iso = self.Gs.node[e]['iso']
[self.Gs.node[i]['iso'].remove(e) for i in iso
if e in self.Gs.node[i]['iso']]
del self.Gs.pos[e] # delete edge position
self.Gs.remove_node(e)
self.labels.pop(e)
self.Ns = self.Ns - 1
# update slab name <-> edge number dictionnary
self.name[name].remove(e)
# delete iso if required
try:
# remove shapely seg
self._shseg.pop(e)
except:
pass
if g2npy:
self.g2npy()
[docs] def point_touches_seg(self,pt,lseg=[],segtol=1e-2,tahetol=1e-2):
""" determine if a point is touching a segment
Parameters
----------
pt : a point (2,)
seg : a list of segments to test.
if [] => all Gs segments are tested
segdtol : distance tolerance point to segment
tahetol : distance tolerance point to segment extremeties
=> a point on segment extremeties is considered
not touching the segseg
Return
------
ltseg : lsit of touched segments (by the point)
"""
if lseg == []:
lseg = self.Gs.nodes()
ltseg = []
allnodes = self.Gs.nodes()
for s in lseg :
if s > 0 and s in allnodes:
n0,n1 = self.Gs.node[s]['connect']
dta,dhe,h = geu.dptseg(np.array(pt)[:,None],
np.array(self.Gs.pos[n0])[:,None],
np.array(self.Gs.pos[n1])[:,None])
if (h <= segtol) and ((dta > tahetol) and (dhe > tahetol)):
ltseg.append(s)
return ltseg
[docs] def seg_intersection(self,**kwargs):
''' determine if a segment intersects any other segment of the layout
Parameters
----------
shLine : a shapely LineString
or
ta,he : tail/head of a segment
Returns
-------
llay_seg : list of layout's segments intersected
lshP : list of shapely points of intersections.
See Also
--------
editor.py
'''
if ('ta' in kwargs) and ('he' in kwargs):
seg = sh.LineString((kwargs['ta'],kwargs['he']))
elif 'shLine' in kwargs:
seg = kwargs['shLine']
# WARNING : use crosses instead of interesects
# otherwise 2 segments connected to a same node
# are considered as intersecting
binter = [seg.crosses(x) for x in list(self._shseg.values())]
if np.sum(binter) > 0:
uinter = np.where(binter)[0]
llay_seg = []
lshP = []
for k in uinter:
# layout segment
llay_seg.append(list(self._shseg.keys())[k])
lay_shseg = self._shseg[llay_seg[-1]]
# intersection shapely point
lshP.append(seg.intersection(lay_shseg))
return(llay_seg,lshP)
else:
return ([],[])
[docs] def mask(self):
""" returns the polygonal mask of the building
Returns
-------
mask : geu.Polygon
Notes
-----
This function assumes graph Gt has been generated
"""
if hasattr(self,Gt):
# takes the 1st cycle polygon
p = self.Gt.node[1]['polyg']
# get the exterior of the polygon
ps = sh.Polygon(p.exterior)
# make the union of the exterior of all the cycles
#
# cycle : -1 exterior
# 0 ??
#
for k in self.Gt.node:
if (k != 0) & (k != -1):
p = self.Gt.node[k]['polyg']
ps = ps.union(sh.Polygon(p.exterior))
mask = geu.Polygon(ps)
mask.setvnodes(self)
return(mask)
else:
print("Gt not built")
[docs] def translate(self, vec):
""" translate layout
Parameters
----------
loa vec :
"""
for k in self.Gs.pos:
pt = self.Gs.pos[k]
self.Gs.pos[k] = (pt[0] + vec[0], pt[1] + vec[1])
[docs] def rotate(self, angle=90):
""" rotate the layout
Parameters
----------
angle : float
(degrees)
"""
a = angle * np.pi / 180
for k in self.Gs.pos:
pt = self.Gs.pos[k]
ptr = np.dot(
array([[np.cos(a), -np.sin(a)], [np.sin(a), np.cos(a)]]), array(pt))
self.Gs.pos[k] = (ptr[0], ptr[1])
self.g2npy()
[docs] def check2(self):
""" Layout checking
Returns
-------
tseg ; list of segment shapely
"""
tseg = []
for k in list(self.Gs.node.keys()):
if k > 0:
#v1.1 lnp = self.Gs.neighbors(k)
lnp = list(self.Gs[k].keys())
p1 = self.Gs.pos[lnp[0]]
p2 = self.Gs.pos[lnp[1]]
tseg.append(sh.LineString([(p1[0], p1[1]), (p2[0], p2[1])]))
N = len(tseg)
for k in combinations(range(N), 2):
seg1 = tseg[k[0]]
seg2 = tseg[k[1]]
if seg1.crosses(seg2):
print("crosses :", k[0], k[1])
if seg1.contains(seg2):
print("contains :", k[0], k[1])
if seg2.contains(seg1):
print("contains :", k[0], k[1])
if seg1.overlaps(seg2):
print("overlaps :", k[0], k[1])
if seg2.overlaps(seg1):
print("overlaps :", k[0], k[1])
return(tseg)
[docs] def cleanup(self):
""" cleanup the Layout
Notes
-----
1. Remove nodes which are not connected
2. Remove supperimposed segments
"""
lk = list(self.Gs.node.keys())
for n in lk:
if ((n < 0) & (self.Gs.degree(n) == 0)):
self.Gs.remove_node(n)
del self.Gs.pos[n]
try:
self.Gv.remove_node(n)
except:
pass
self.Np = len(np.nonzero(np.array(list(self.Gs.node.keys())) < 0)[0])
aseg_conn=[]
for seg in self.Gs.nodes():
if seg >0:
n0,n1 = list(nx.neighbors(self.Gs,seg))
aseg_conn.append([seg,n0,n1])
aseg_conn = np.array(aseg_conn)
# aseg_conn=np.array([[list(nx.neighbors(self.Gs,x))] for x in self.Gs.nodes() if x >0])
uni,upos=np.unique(aseg_conn[:,1:],axis=0,return_index=True)
utbd = [x for x in range(len(aseg_conn)) if not x in upos]
tbd = aseg_conn[utbd,0]
for k in tbd:
self.del_segment(k)
self.g2npy()
[docs] def info_segment(self, s1):
""" information about segment
Parameters
----------
s1 : segment number
"""
# v1.1 nebd = self.Gs.neighbors(s1)
nebd = self.Gs[s1].keys()
n1 = nebd[0]
n2 = nebd[1]
#v1.1 nns1 = self.Gs.neighbors(n1)
#nns2 = self.Gs.neighbors(n2)
nns1 = self.Gs[n1].keys()
nns2 = self.Gs[n2].keys()
ds1 = self.Gs.node[s1]
print(n1, ' : ', nns1)
print(n2, ' : ', nns2)
print('------------')
print('Slab : ', ds1['name'])
print('zmin (m) : ', ds1['z'][0])
print('zmax (m) : ', ds1['z'][1])
try:
print('------------')
a = ds1['ss_name']
print('subseg Slabs : ', ds1['ss_name'])
print('subseg (zmin,zmax) (m) : ', ds1['ss_z'])
except:
pass
[docs] def edit_seg(self, e1, data={}):
""" edit segment
Parameters
----------
e1 : integer
edge number
data : dict
dictionnary of value of seg or subseg
Notes
-----
A segment has the following properties :
+ name : string
+ z : tuple
+ transition : boolean (default FALSE)
+ offset : [-1,1]
If a segment has subsegments attached the following properties are
added :
+ ss_name : list of string
+ ss_z : list of subsegment e.q. [(min height (meters),max height (meters))]
+ ss_offset : list of offset in [0,1]
"""
if data == {}:
pass
else:
ename = self.Gs.node[e1]['name']
# manage self.name
self.name[ename].pop(self.name[ename].index(e1))
# manage self.display['name']
if len(self.name[ename]) == 0:
try:
self.display['layers'].pop(
self.display['layers'].index(ename))
except:
pass
for k in data:
self.Gs.node[e1][k] = data[k]
if data['name'] in self.name:
self.name[data['name']].append(e1)
else:
self.name[data['name']]=[e1]
if data['name'] not in self.display['layers']:
self.display['layers'].append(data['name'])
return data
[docs] def have_subseg(self, e1):
""" check if edge e1 have subseg
Parameters
----------
e1 : int
Returns
-------
have_subseg_bool : boolean
"""
dk = self.Gs.node[e1]
if len(dk['iso'])>0:
return True
else:
return False
[docs] def find_edgelist(self, edgelist, nodelist):
"""
edgelist = find_edgelist(edgelist,nodelist)
edgelist : input edgelist
nodelist : input nodelist
return the subset of edgelist
Not Finished :
"""
tail = self.tahe[0, edgelist]
head = self.tahe[1, edgelist]
nt = np.intersect1d_nu[tail, nodelist]
nh = np.intersect1d_nu[head, nodelist]
edgelist = edgelist[np.unique(ed_t, ed_h)]
return(edgelist)
[docs] def diag(self, p1, p2, l, al1, al2, quadsel=0):
""" return edge list from a diagonal zone
Parameters
-----------
p1 : np.array
p2 : np.array
tol :
al1 :
al2 :
quadsel : 0 all quadrant
2 1
3 4
Returns
-------
edgelist
"""
x = self.pt[0, :]
y = self.pt[1, :]
#
# selection du quadran
#
if (quadsel == 0):
u0 = np.arange(self.Np)
if (quadsel == 1):
u0 = np.nonzero((y > p1[1]) & (x > p1[0]))[0]
if (quadsel == 2):
u0 = np.nonzero((y > p1[1]) & (x <= p1[0]))[0]
if (quadsel == 3):
u0 = np.nonzero((y <= p1[1]) & (x <= p1[0]))[0]
if (quadsel == 4):
u0 = np.nonzero((y <= p1[1]) & (x > p1[0]))[0]
x_u0 = x[u0]
y_u0 = y[u0]
#
# Permutation points
#
if (p1[0] > p2[0]):
pt = p2
p2 = p1
p1 = pt
#
# Box length
#
Dx = p2[0] - p1[0]
Dy = p2[1] - p1[1]
L = np.sqrt(Dx ** 2 + Dy ** 2)
#
# p1 p2
#
if ((abs(Dx) > finfo(float).eps) & (abs(Dy) > finfo(float).eps)):
a = Dy / Dx
b = p1[1] - a * p1[0]
b1 = p1[1] + p1[0] / a
b2 = p2[1] + p2[0] / a
delta_b = tol * L / abs(Dx)
delta_b1 = al1 * L * L / abs(Dy)
delta_b2 = al2 * L * L / abs(Dy)
u1 = np.nonzero(y_u0 < a * x_u0 + b + delta_b / 2.)[0]
x_u1 = x_u0[u1]
y_u1 = y_u0[u1]
u2 = np.nonzero(y_u1 > a * x_u1 + b - delta_b / 2.)[0]
x_u2 = x_u1[u2]
y_u2 = y_u1[u2]
if (a > 0):
u3 = np.nonzero(y_u2 > -x_u2 / a + b1 - delta_b1)[0]
x_u3 = x_u2[u3]
y_u3 = y_u2[u3]
u4 = np.nonzero(y_u3 < -x_u3 / a + b2 + delta_b2)[0]
else:
u3 = np.nonzero(y_u2 < -x_u2 / a + b1 + delta_b1)[0]
x_u3 = x_u2[u3]
y_u3 = y_u2[u3]
u4 = np.nonzero(y_u3 > -x_u3 / a + b2 - delta_b2)[0]
x_u4 = x_u3[u4]
y_u4 = y_u3[u4]
#
# p1 p2 vertical
#
if (abs(Dx) <= finfo(float).eps):
u1 = np.nonzero(x < p1[0] + tol / 2.)[0]
x_u1 = x[u1]
y_u1 = y[u1]
u2 = np.nonzero(x_u1 > p1[0] - tol / 2.)[0]
y_u2 = y[u2]
if (p1[1] > p2[1]):
u3 = np.nonzero(y_u2 < p1[1] + al1 * L)[0]
y_u3 = y[u3]
u4 = np.nonzero(y_u3 > p2[1] - al2 * L)[0]
else:
u3 = np.nonzero(y_u2 < p2[1] + al2 * L)[0]
y_u3 = y[u3]
u4 = np.nonzero(y_u3 > p1[1] - al1 * L)[0]
#
# p1 p2 horizontal
#
if (abs(Dy) <= finfo(float).eps):
u1 = np.nonzero(y < p1[1] + tol / 2.)[0]
y_u1 = y[u1]
u2 = np.nonzero(y_u1 > p1[1] - tol / 2.)[0]
x_u2 = x[u2]
if (p1(1) > p2(1)):
u3 = np.nonzero(x_u2 < p1[0] + al1 * L)[0]
x_u3 = x[u3]
u4 = np.nonzero(x_u3 > p2[0] - al2 * L)[0]
else:
u3 = np.nonzero(x_u2 < p2[0] + al2 * L)[0]
x_u3 = x[u3]
u4 = np.nonzero(x > p1[0] - al1 * L)[0]
nodelist = u0[u1[u2[u3[u4]]]]
edgelist = np.arange(self.Ns)
edgelist = self.find_edge_list(edgelist, nodelist)
return(edgelist)
[docs] def nd2seg(self, ndlist):
""" convert node list to edge list
Parameters
----------
ndlist : list or ndarray
node list
Returns
-------
seglist : ndarray
edge list
Notes
-----
previously nd2ed
"""
if isinstance(ndlist, np.ndarray):
ndlist = ndlist.tolist()
seglist = []
# for n in ndlist:
# seglist = seglist + self.Gs.adj[n].keys()
#l = map(lambda x: self.Gs.adj[x].keys(), ndlist)
l = [ list(dict(self.Gs.adj[x]).keys()) for x in ndlist ]
seglist = []
for y in l :
seglist = seglist + y
#reduce(lambda x, y: x + y, l)
return(np.unique(np.array(seglist)))
[docs] def ed2nd(self, edlist):
""" convert edgelist to nodelist
Parameters
----------
edlist : list or ndarray
edge list
Returns
-------
ndlist : ndarray
node list
"""
if isinstance(edlist, np.ndarray):
edlist = edlist.tolist()
# mecanisme de concatenation de listes
ndlist = []
for e in edlist:
ndlist = ndlist + self.Gs.adj[e].keys()
return(np.unique(ndlist))
[docs] def get_zone(self, ax):
""" get point list and segment list in a rectangular zone
Parameters
----------
ax : list ot tuple
[xmin,xmax,ymin,ymax]
Returns
-------
ptlist,seglist
"""
xmin = ax[0]
xmax = ax[1]
ymin = ax[2]
ymax = ax[3]
ptlist = []
for n in self.Gs.node.keys():
if n < 0:
x = self.Gs.pos[n][0]
y = self.Gs.pos[n][1]
if ((x > xmin) & (x < xmax) & (y > ymin) & (y < ymax)):
ptlist.append(n)
seglist = self.nd2seg(ptlist)
return ptlist, seglist
[docs] def get_points(self, boxorpol , tol = 0.05):
""" get points list and segments list in a polygonal zone
Parameters
----------
boxorpol : list or tuple
[xmin,xmax,ymin,ymax]
or shapely Polygon
Returns
-------
(pt,ke) : points coordinates and index
pt : (2xn)
ke : (,n)
Notes
-----
This method returns all the existing Layout points inside a box zone or
the boundary of a polygon
"""
if type(boxorpol) == geu.Polygon:
N = len(boxorpol.vnodes)/2
eax = boxorpol.bounds
xmin = eax[0] - tol
xmax = eax[2] + tol
ymin = eax[1] - tol
ymax = eax[3] + tol
else:
xmin = boxorpol[0]
xmax = boxorpol[1]
ymin = boxorpol[2]
ymax = boxorpol[3]
#
# layout points
#
x = self.pt[0,:]
y = self.pt[1,:]
uxmin = (x>= xmin)
uymin = (y>= ymin)
uxmax = (x<= xmax)
uymax = (y<= ymax)
#
# k True when all conditons are True simultaneously
#
k = np.where(uxmin*uymin*uxmax*uymax==1)[0]
#pt = np.array(zip(x[k],y[k])).T
# pt (2 x N )
pt = np.vstack((x[k],y[k]))
ke = self.upnt[k]
# if(pt.shape[1]<N):
# plt.ion()
# fig,a=self.showG('s')
# a.plot(pt[0,:],pt[1,:],'or')
# a.plot(eax[0],eax[1],'or')
# plt.show()
# ux = ((x>=xmin).all() and (x<=xmax).all())
# uy = ((y>=ymin).all() and (y<=ymax).all())
return((pt,ke))
[docs] def angleonlink3(self, p1=np.array([0, 0, 1]), p2=np.array([10, 3, 1])):
""" returns (seglist,angle) in retangular area defined by p1 and p2
Parameters
----------
p1 : np.array (3 x N) or (3,)
p2 : np.array (3 x N) or (3,)
Returns
-------
data : structured array x N
'i' : index
's' : slab
'a' : angle (in radians)
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('DLR2.lay')
>>> p1 = np.array([0,0,1])
>>> p2 = np.array([10,3,2])
>>> data = L.angleonlink3(p1,p2)
#array([(0, 141, 1.2793395519256592), (0, 62, 0.29145678877830505),
(0, 65, 0.29145678877830505)],
dtype=[('i', '<i8'), ('s', '<i8'), ('a', '<f4')])
See Also
--------
antprop.loss.Losst
geomutil.intersect3
"""
sh1 = np.shape(p1)
sh2 = np.shape(p2)
assert sh1[0] == 3, pdb.set_trace()
assert sh2[0] == 3, pdb.set_trace()
# p1 (1 axe) and p2 (2 or 3 axes)
if (len(sh1) < 2) & (len(sh2) > 1):
p1 = np.outer(p1, np.ones(sh2[1]))
# p2 (1 axe) and p1 (2 or 3 axes)
if (len(sh2) < 2) & (len(sh1) > 1):
p2 = np.outer(p2, np.ones(sh1[1]))
if (len(sh2) < 2) & (len(sh1) < 2):
p1 = np.outer(p1, np.ones(1))
p2 = np.outer(p2, np.ones(1))
# 3 x N
u = p1 - p2
# 1 x N
nu = np.sqrt(np.sum(u * u, axis=0))
# 3 x N
un = u / nu[np.newaxis, :]
#
# warning : seglist contains the segment number in tahe not in Gs
#
seglist = self.seginframe2(p1[0:2], p2[0:2])
useglist = np.unique(seglist)
#seglist = np.unique(self.seginframe(p1[0:2], p2[0:2]))
upos = np.nonzero(useglist >= 0)[0]
uneg = np.nonzero(useglist < 0)[0]
# nNLOS = len(uneg) + 1
# # retrieve the number of segments per link
# if nNLOS > 1:
# llink = np.hstack(
# (uneg[0], np.hstack((uneg[1:], array([len(seglist)]))) - uneg - 1))
# else:
# llink = np.array([len(seglist)])
# [(link id,number of seg),...]
# nl = zip(np.arange(nlink),llink)n
useglist = useglist[upos]
npta = self.tahe[0, useglist]
nphe = self.tahe[1, useglist]
Pta = self.pt[:, npta]
Phe = self.pt[:, nphe]
Nscreen = len(npta)
# get segment height bounds
zmin = np.array([self.Gs.node[x]['z'][0]
for x in self.tsg[useglist]])
zmax = np.array([self.Gs.node[x]['z'][1]
for x in self.tsg[useglist]])
# centroid of the screen
Pg = np.vstack(((Phe + Pta) / 2., (zmax + zmin) / 2.))
Ptahe = Phe - Pta
L1 = np.sqrt(np.sum(Ptahe * Ptahe, axis=0))
# 3 x Nscreen U1 is in plane xy
U1 = np.vstack((Ptahe / L1, np.zeros(Nscreen)))
L2 = zmax - zmin
U2 = np.array([0, 0, 1])[:, None] # 3 x 1 U2 is along z
#
# p1 : 3 x Ng
# p2 : 3 x Ng
# Pg : 3 x Nscreen
# U1 : 3 x Nscreen
# U2 : 3 x 1
# L1 : ,Nscreen
# L2 : ,Nscreen
bo, pt = geu.intersect3(p1, p2, Pg, U1, U2, L1, L2)
ubo = np.where(bo)
Nseg = len(ubo[0])
data = np.zeros(Nseg, dtype=[('i', 'i8'), ('s', 'i8'), ('a', np.float32)])
data['i'] = ubo[0]
data['s'] = self.tsg[useglist[ubo[1]]]
#
# Calculate angle of incidence refered from segment normal
#
norm = self.normal[:, useglist[ubo[1]]]
# vector along the link
uu = un[:, ubo[0]]
unn = abs(np.sum(uu * norm, axis=0))
angle = np.arccos(unn)
data['a'] = angle
return(data)
[docs] def angleonlink(self, p1=np.array([0, 0]), p2=np.array([10, 3])):
""" angleonlink(self,p1,p2) return (seglist,angle) between p1 and p2
Parameters
----------
p1 : np.array (2 x Np) or (2,)
p2 : np.array (2 x Np) or (2,)
Returns
-------
data['i']
data['s'] : list of segment number
data['a'] : angle (in radians) between segment and LOS axis
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('DLR.lay')
>>> p1 = np.array([0,0])
>>> p2 = np.array([10,3])
>>> alpha = L.angleonlink(p1,p2)
#array([(0, 141, 1.2793395519256592), (0, 62, 0.29145678877830505),
(0, 65, 0.29145678877830505)],
dtype=[('i', '<i8'), ('s', '<i8'), ('a', '<f4')])
"""
sh1 = np.shape(p1)
sh2 = np.shape(p2)
assert sh1[0] == 2
assert sh2[0] == 2
if (len(sh1) < 2) & (len(sh2) > 1):
p1 = np.outer(p1, np.ones(sh2[1]))
if (len(sh2) < 2) & (len(sh1) > 1):
p2 = np.outer(p2, np.ones(sh1[1]))
if (len(sh2) < 2) & (len(sh1) < 2):
p1 = np.outer(p1, np.ones(1))
p2 = np.outer(p2, np.ones(1))
# 2 x N
u = p1 - p2
# 1 x N
nu = np.sqrt(np.sum(u * u, axis=0))
# 2 x N
un = u / nu[np.newaxis, :]
#seglist = self.seginframe2(p1, p2)
seglist = self.seginframe(p1, p2)
upos = np.nonzero(seglist >= 0)[0]
uneg = np.nonzero(seglist < 0)[0]
nNLOS = len(uneg) + 1
# retrieve the number of segments per link
if nNLOS > 1:
llink = np.hstack(
(uneg[0], np.hstack((uneg[1:], array([len(seglist)]))) - uneg - 1))
else:
llink = np.array([len(seglist)])
# llink : list of link length
npta = self.tahe[0, seglist[upos]]
nphe = self.tahe[1, seglist[upos]]
Pta = self.pt[:, npta]
Phe = self.pt[:, nphe]
#
# This part should possibly be improved
#
for i, nl in enumerate(llink):
try:
P1 = np.hstack((P1, np.outer(p1[:, i], np.ones(nl))))
P2 = np.hstack((P2, np.outer(p2[:, i], np.ones(nl))))
ilink = np.hstack(
(ilink, array([-1]), i * np.ones(nl, dtype='int')))
except:
P1 = np.outer(p1[:, i], np.ones(nl))
P2 = np.outer(p2[:, i], np.ones(nl))
ilink = i * np.ones(nl, dtype='int')
bo = geu.intersect(P1, P2, Pta, Phe)
upos_intersect = upos[bo]
seglist2 = seglist[upos_intersect]
idxlnk = ilink[upos_intersect]
#
# Calculate angle of incidence refered from segment normal
#
norm = self.normal[0:2, seglist2]
# vector along the linkco
uu = un[:,idxlnk]
unn = abs(np.sum(uu * norm, axis=0))
angle = np.arccos(unn)
# seglist = seglist+1
seglist = np.array([self.tsg[x] for x in seglist2])
data = np.zeros(len(seglist), dtype=[
('i', 'i8'), ('s', 'i8'), ('a', np.float32)])
#
# update subsegment in seglist
#
# self.lsss
data['i'] = idxlnk
data['s'] = seglist
data['a'] = angle
return data
[docs] def angleonlinkold(self, p1=np.array([0, 0]), p2=np.array([10, 3])):
""" angleonlink(self,p1,p2) returns seglist between p1 and p2
Parameters
----------
p1 : (1 x 2 )
[0,0]
p2 : (1 x 2 )
[10,3]
Returns
-------
seglist : list
list of segment number on the link
theta
Examples
--------
#>>> from pylayers.gis.layout import *
#>>> L = Layout('DLR.lay','matDB.ini','slabDB.ini')
#>>> p1 = np.array([0,0])
#>>> p2 = np.array([10,3])
#>>> L.angleonlinkold(p1,p2)
#(array([59, 62, 65]), array([ 1.27933953, 0.29145679, 0.29145679]))
"""
logger.warning('This function is deprecated use')
u = p1 - p2
nu = np.sqrt(np.dot(u, u))
un = u / nu
seglist = self.seginframe(p1, p2)
# new implementation of seginframe is faster
#
#seglist = self.seginframe2(p1, p2)
npta = self.tahe[0, seglist]
nphe = self.tahe[1, seglist]
Pta = self.pt[:, npta]
Phe = self.pt[:, nphe]
P1 = np.outer(p1, np.ones(len(seglist)))
P2 = np.outer(p2, np.ones(len(seglist)))
bo = geu.intersect(P1, P2, Pta, Phe)
seglist = seglist[bo]
#
# Calculate normal angle angle of incidence
#
tail = self.tahe[0, seglist]
head = self.tahe[1, seglist]
vn = np.vstack((self.pt[1, head] - self.pt[1, tail],
self.pt[0, head] - self.pt[0, tail]))
mvn = np.outer(np.ones(2), np.sqrt(np.sum(vn * vn, axis=0)))
n = vn / mvn
uu = np.outer(un, np.ones(len(seglist)))
unn = abs(np.sum(uu * n, axis=0))
theta = np.arccos(unn)
# printvn
# printmvn
# print'n :',n
# print'un : ',unn
# print'theta (deg)',the*180./pi
# seglist = seglist+1
seglist = np.array([self.tsg[x] for x in seglist])
return(seglist, theta)
[docs] def layeronlink(self, p1, p2):
"""
layeronlink(self,p1,p2) return seglist between p1 and p2
p1 : (1 x 2 )
p2 : (1 x 2 )
"""
seglist = self.seginframe(p1, p2)
npta = self.tahe[0, seglist]
nphe = self.tahe[1, seglist]
Pta = self.pt[:, npta]
Phe = self.pt[:, nphe]
P1 = np.outer(p1, np.ones(len(seglist)))
P2 = np.outer(p2, np.ones(len(seglist)))
bool = np.intersect(P1, P2, Pta, Phe)
seglist = seglist[bool]
return seglist
[docs] def seguv(self, iseg):
""" returns unitary vector along segments
Parameters
----------
iseg : np.array
index of segments
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('DLR.lay')
>>> idx = np.array([1,2,3,17])
>>> v1 = L.seguv(idx)
>>> idx = np.array([1])
>>> v2= L.seguv(idx)
"""
# idx : npt
idx = self.tgs[iseg]
# tahe : 2 x npt
tahe = self.tahe[:, idx]
if len(iseg) > 1:
ta = tahe[0, :]
he = tahe[1, :]
else:
ta = tahe[0]
he = tahe[1]
pta = self.pt[:, ta]
phe = self.pt[:, he]
# v : 2 x npt
v = pta - phe
# mv : npt
mv = np.sqrt(np.sum(v * v, axis=0))
# vn : 2 x npt
if len(idx) > 1:
vn = v / mv[np.newaxis, :]
else:
vn = (v / mv).reshape(2)
return(vn)
[docs] def seg2pts(self, aseg):
""" convert segments array from Gs numerotation
to corresponding termination points array in pt
Parameters
----------
aseg : np.array (,Ns) or int for single value:w
array of segment number (>0)
Returns
-------
pth : np.array (4 x Ns)
pth is a vstacking of tail point (2,Ns) and head point (2,Ns)
Examples
--------
>>> from pylayers.gis.layout import *
>>> import numpy as np
>>> L = Layout('defstr.lay')
>>> aseg = np.array([1,3,6])
>>> pt = L.seg2pts(aseg)
Notes
-----
surprisingly self.s2pc is slower than this function
"""
if not isinstance(aseg, np.ndarray):
aseg = np.array([aseg])
assert(len(np.where(aseg < 0)[0]) == 0)
utahe = self.tgs[aseg]
#if (utahe>=0).all():
tahe = self.tahe[:, utahe]
ptail = self.pt[:, tahe[0, :]]
phead = self.pt[:, tahe[1, :]]
pth = np.vstack((ptail, phead))
pth = pth.reshape(pth.shape[0], pth.shape[-1])
return pth
#else:
# pdb.set_trace()
[docs] def segpt(self, ptlist=np.array([0])):
""" return the seg list of a sequence of point number
Parameters
----------
ptlist array(1xNp)
point number array
Returns
-------
seglist
array seglist associated with ptlist
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('TA-Office.lay')
>>> ptlist = np.array([0,1])
>>> seg = L.segpt(ptlist)
Notes
-----
"""
seglist = np.array([], dtype=int)
for i in ptlist:
ut = np.nonzero(self.tahe[0, :] == i)[0]
uv = np.nonzero(self.tahe[1, :] == i)[0]
seglist = np.hstack((seglist, ut, uv))
seglist = np.unique(seglist)
return(seglist)
[docs] def extrseg(self):
""" calculate extremum of segments
Notes
-----
update the following members
`min_sx`
`max_sx`
`min_sy`
`max_sy`
Used in seginframe
"""
# 2 x Np
pt = self.pt
# tahe 2 x Nseg
#th = zip(self.tahe[0, :], self.tahe[1, :])
ta = self.tahe[0,:]
he = self.tahe[1,:]
self.max_sx = np.maximum(pt[0,ta],pt[0,he])
self.min_sx = np.minimum(pt[0,ta],pt[0,he])
self.max_sy = np.maximum(pt[1,ta],pt[1,he])
self.min_sy = np.minimum(pt[1,ta],pt[1,he])
#self.max_sx = np.array([ np.maximum(pt[0, x[0]], pt[0, x[1]]) for x in th ])
#self.min_sx = np.array([ np.minimum(pt[0, x[0]], pt[0, x[1]]) for x in th ])
#self.max_sy = np.array([ np.maximum(pt[1, x[0]], pt[1, x[1]]) for x in th ])
#self.min_sy = np.array([ np.minnimum(pt[1, x[0]], pt[1, x[1]]) for x in th ])
[docs] def seginframe2(self, p1, p2):
""" returns the seglist of a given zone defined by two points
(vectorised version)
Parameters
----------
p1 array (2 x N)
array of N 2D points
p2 array (2 x N)
array of N 2D points
Returns
-------
seglist
list of segment number inside a planar region defined by p1 an p2
separated by -1
Examples
--------
.. plot::
:include-source:
>>> from pylayers.gis.layout import *
>>> L = Layout('TA-Office.lay')
>>> p1 = np.array([[0,0,0],[0,0,0]])
>>> p2 = np.array([[10,10,10],[10,10,10]])
>>> seglist = L.seginframe2(p1,p2)
>>> edlist = [ L.tsg[x] for x in seglist ]
>>> fig,ax = L.showG('s',edlist=edlist)
"""
sh1 = np.shape(p1)
sh2 = np.shape(p2)
assert sh1[0] == 2
assert sh2[0] == 2
if (len(sh1) < 2) & (len(sh2) > 1):
p1 = np.outer(p1, np.ones(sh2[1]))
if (len(sh2) < 2) & (len(sh1) > 1):
p2 = np.outer(p2, np.ones(sh1[1]))
if (len(sh2) < 2) & (len(sh1) < 2):
p1 = np.outer(p1, np.ones(1))
p2 = np.outer(p2, np.ones(1))
# clipping conditions to keep segment
#
# max_sx > min_x
# min_sx < max_x
# max_sy > min_y
# min_sy < max_y
# N x 1
#max_x = [ max(x[1], x[0]) for x in zip(p1[0, :], p2[0, :]) ]
#min_x = [ min(x[1], x[0]) for x in zip(p1[0, :], p2[0, :]) ]
#max_y = [ max(x[1], x[0]) for x in zip(p1[1, :], p2[1, :]) ]
#min_y = [ min(x[1], x[0]) for x in zip(p1[1, :], p2[1, :]) ]
max_x = np.maximum(p1[0,:],p2[0,:])
min_x = np.minimum(p1[0,:],p2[0,:])
max_y = np.maximum(p1[1,:],p2[1,:])
min_y = np.minimum(p1[1,:],p2[1,:])
seglist = [ np.nonzero((self.max_sx > x[0]) &
(self.min_sx < x[1]) &
(self.max_sy > x[2]) &
(self.min_sy < x[3]))[0]
for x in zip(min_x, max_x, min_y, max_y) ]
# np.array stacking
# -1 acts as a deliminiter (not as a segment number)
# seglist = reduce(lambda x, y: np.hstack((x, array([-1]), y)), seglist)
x = np.array([]).astype(int)
for y in seglist:
x = np.hstack((x, np.array([-1]), y))
return(x)
[docs] def seginframe(self, p1, p2):
""" return the seg list of a given zone defined by two points
Parameters
----------
p1
array (1 x 2)
p2
array (1 x 2)
Returns
-------
seglist
list of segment number inside a planar region defined by p1 an p2
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('TA-Office.lay')
>>> p1 = np.array([0,0])
>>> p2 = np.array([10,10])
>>> L.seginframe(p1,p2)
array([ 1, 3, 7, 8, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 30,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 46, 47, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 81, 82, 85, 86])
"""
#assert( (p1.shape==(1,2)) or (p1.shape==(2)))
#assert( (p2.shape==(1,2)) or (p2.shape==(2)))
max_x = max(p1[0], p2[0])
min_x = min(p1[0], p2[0])
max_y = max(p1[1], p2[1])
min_y = min(p1[1], p2[1])
Dx = max_x - min_x
Dy = max_y - min_y
if Dx < 0.5:
max_x = max_x + 0.5
min_x = min_x - 0.5
if Dy < 0.5:
max_y = max_y + 0.5
min_y = min_y - 0.5
if (Dy < Dx):
up = np.nonzero((self.pt[0, :] < max_x) &
(self.pt[0, :] > min_x))[0]
else:
up = np.nonzero((self.pt[1, :] < max_y) &
(self.pt[1, :] > min_y))[0]
seglist = self.segpt(up)
return(seglist)
[docs] def layerongrid(self, grid, Tx):
""" grid Nx,Ny,2
Tx 1x2
.. todo:: layeron grid Not finished
"""
Nx = grid.shape[0]
Ny = grid.shape[1]
for ix in range(Nx):
for iy in range(Ny):
p = grid[ix, iy, :]
seglist, theta = self.layeronlink(p, Tx)
[docs] def cycleinline(self, c1, c2):
""" returns the intersection between a given line and all segments
Parameters
----------
c1 : int
point
c2 : int
point
Returns
-------
I : numpy.ndarray
See Also
--------
pylayers.antprop.signature.Signatures.rays
pylayers.gis.layout.Layout.seginframe2
Notes
-----
This function is used to detect LOS conditions
"""
I = np.array([]).reshape(3, 0)
# polygon cycle 1
poly1 = self.Gt.node[c1]['polyg']
p1t = poly1.centroid.xy
# polygon cycle 2
poly2 = self.Gt.node[c2]['polyg']
p2t = poly2.centroid.xy
# centroid of cycle 1 and 2
p1 = np.array([p1t[0][0], p1t[1][0]])
p2 = np.array([p2t[0][0], p2t[1][0]])
line = sh.LineString((p1, p2))
# els = self.seginframe(p1,p2)
# new implementation of seginframe is faster
els = self.seginframe2(p1, p2)
elg = self.tsg[els]
lc = []
ls = []
I = np.array([]).reshape(2, 0)
for seg in elg:
#v1.1 ta, he = self.Gs.neighbors(seg)
ta, he = self.Gs[seg]
pa = np.array(self.Gs.pos[ta])
pb = np.array(self.Gs.pos[he])
segline = sh.LineString((pa, pb))
if line.intersects(segline):
lc.extend(self.Gs.node[seg]['ncycles'])
# printseg,self.Gs.node[seg]['ncycles']
ls.append(seg)
psh = line.intersection(segline)
I = np.hstack((I, np.array([[psh.x], [psh.y]])))
v = (I - p1[:, np.newaxis])
dv = np.sum(v * v, axis=0)
u = np.argsort(dv)
lss = np.array(ls)[u]
lc = [c1]
for s in lss:
cy1, cy2 = self.Gs.node[s]['ncycles']
if cy1 not in lc:
lc.append(cy1)
elif cy2 not in lc:
lc.append(cy2)
else:
assert NameError('Bad transisiton in Layout.cycleinline')
return lc
[docs] def seginline(self, p1, p2):
""" returns the intersection between a given line and all segments
Parameters
----------
p1 : numpy.ndarray
p2 : numpy.ndarray
Returns
-------
I : numpy.ndarray
"""
I = np.array([]).reshape(3, 0)
line = sh.LineString((p1, p2))
for seg in self.Gs.nodes():
if seg > 0:
# v1.1 ta, he = self.Gs.neighbors(seg)
ta, he = self.Gs[seg]
pa = np.array(self.Gs.pos[ta])
pb = np.array(self.Gs.pos[he])
else:
pa = np.array(self.Gs.pos[seg])
pb = pa
segline = sh.LineString((pa, pb))
if line.intersects(segline):
psh = line.intersection(segline)
liseg = np.array([[psh.x], [psh.y]])
I = np.hstack((I, np.vstack(([[seg]], liseg))))
return I
[docs] def visilist(self, p):
""" returns the list of nodes which are visible from point p
Parameters
----------
p
np.array point
Returns
-------
Notes
-----
AAS = [0:2pi]
While (AAS != void set)
1) Find segment ns either
i) the closest segment from p in AAS
ii) neighbor of prec(ns)
2) Find the edgelist visible from ns
edgelist = vedgelist(ns)
3) Check_occultation(p,ns,edgelist)
Occultation 8 situations
[p1,pM,p2] = [T,T,T] : fully occulted
[ ] partially visible
[F,F,F] : fully visible
4) Update Allowed Angular Sector (AAS)
"""
AAS = Intvl([0, 2 * pi])
nsprev = np.inf
edgelist = np.array([])
while AAS.measure() != 0:
if nsprev == np.inf:
ns = self.closest(p, AAS)
else:
ns = self.neighbors(nsprev)
edgelist = self.vedgelist(ns)
[b1, bM, b2] = self.check - occultation(p, ns, edgelist)
AAS = self.update(AAS,)
[docs] def closest_edge(self, p, AAS):
""" not implemented
Parameters
----------
This function return the closest segment from p which belong to
the AAS (Allowed Angular Sector)
[ns] = closest_edge(self,p,AAS)
"""
pass
# not implemented
[docs] def visi_papb(self, pa, pb, edgelist=np.array([])):
"""
visi_papb : determine if pa and pb are in visibility for the structure graph
visi_papb(pa,pb,edgelist)
pa : 1x2
pb : 1x2
edgelist : exclusion edge list
"""
#
# .. todo: avoid utilisation tahe
#
x = self.pt[0, :]
y = self.pt[1, :]
ta = self.tahe[0, :]
he = self.tahe[1, :]
x1 = x[ta]
y1 = y[ta]
x2 = x[he]
y2 = y[he]
den = (pb[1] - pa[1]) * (x2 - x1) - (pb[0] - pa[0]) * (y2 - y1)
w = np.nonzero(abs(den) < 1e-12)[0]
den[w] = 1e-12
numa = (pb[0] - pa[0]) * (y1 - pa[1]) - (pb[1] - pa[1]) * \
(x1 - pa[0])
numb = (x2 - x1) * (y1 - pa[1]) - (y2 - y1) * (x1 - pa[0])
ua = numa / den
ub = numb / den
#ua[edgelist] = 1000
u = np.nonzero((ua >= 0) & (ua <= 1) & (ub >= 0) & (ub <= 1))[0]
# Si le segment de droite pa-pb intercepte des paroies de la structure
if (u != []):
visi = 0
else:
visi = 1
return(visi)
[docs] def show_nodes(self, ndlist=[1e8], size=10, color='b', dlabels=False, font_size=15, alpha=1, node_shape='o', fig=[], ax=[]):
""" show nodes
Parameters
----------
ndlist
size : int
default 10
color : 'b'
dlabels : Boolean
False
font_size : int
15
alpha : float
transparancy
See Also
--------
show_segment
showGs
"""
if fig == []:
fig = plt.figure()
if ax == []:
ax = fig.add_subplot(111)
if type(ndlist) == np.ndarray:
ndlist = list(ndlist)
if len(ndlist) == 0:
# ndlist.append(1e8)
dlabels = False
elif ndlist[0] == 1e8:
ndlist = self.Gs.node.keys()
# elif ndlist[0]==1e8:
# ndlist = self.Gs.node.keys()
# printndlist
Z = nx.draw_networkx_nodes(self.Gs, self.Gs.pos, node_color=color,
node_size=size, nodelist=ndlist, alpha=alpha,
node_shape=node_shape, fig=fig, ax=ax)
try:
fig = Z.figure
ax = Z.axes
except:
pass
if dlabels:
dicopos = {}
dicolab = {}
for n in ndlist:
dicopos[n] = np.array(self.Gs.pos[n])
dicolab[n] = self.labels[n]
Z = nx.draw_networkx_labels(self.Gs, dicopos, dicolab,
font_size=font_size, font_color=color, fig=fig, ax=ax)
try:
fig = Z.figure
ax = Z.axes
except:
pass
return fig, ax
[docs] def show_seg1(self, edlist=[], alpha=1, width=1, size=2, color='black', font_size=15, dlabels=False):
""" show segment
Parameters
----------
edlist
alpha
width
size
color
font_size
dlabels
"""
if type(edlist) == 'ndarray':
edlist = edlist.tolist()
elif type(edlist) == int:
edlist = [edlist]
# printndlist
nx.draw_networkx_nodes(
self.Gs, self.Gs.pos, node_size=size, nodelist=edlist)
if dlabels:
dicopos = {}
dicolab = {}
for n in ndlist:
# dicopos[n]=tuple(np.array(self.Gs.pos[n])+np.array((0.8,0.2)))
dicopos[n] = np.array(self.Gs.pos[n])
dicolab[n] = self.labels[n]
nx.draw_networkx_labels(
self.Gs, dicopos, dicolab, font_size=font_size)
[docs] def show_segment(self, **kwargs):
""" show segment
Parameters
----------
edlist : list
segment list
alpha : float
transparency 0< alpha < 1
width : float
line width (default 1)
color : string
default 'black'
dnodes : boolean
display nodes ( Default False)
dlabels : boolean
display labels ( Default False)
font_size : int
Default 15
See Also
--------
show_nodes
"""
defaults = {'fig': [],
'ax': [],
'edlist': [],
'alpha': 1,
'width': 1,
'color': 'black',
'dnodes': False,
'dlabels': False,
'font_size': 15,
'node_shape': 'o'
}
for key, value in defaults.items():
if key not in kwargs:
kwargs[key] = value
if kwargs['fig'] == []:
fig = plt.figure()
else:
fig = kwargs['fig']
if kwargs['ax'] == []:
ax = fig.add_subplot(111)
else:
ax = kwargs['ax']
clrlist = []
cold = pyu.coldict()
# html color or string
if kwargs['color'][0] != '#':
clrlist.append(cold[kwargs['color']])
else:
if color == '#FFFFF0':
color = '#00000F'
clrlist.append(color)
ecmap = clr.ListedColormap(clrlist)
U = self.Gs.edges(kwargs['edlist'])
# ue = (np.ones(2 * len(kwargs['edlist']))).astype('int').tolist()
ue = np.ones(len(U),dtype='int').tolist()
if len(U) > 0:
Z = nx.draw_networkx_edges(self.Gs, self.Gs.pos, edgelist=U,
edge_color=ue, edge_cmap=ecmap,
alpha=kwargs['alpha'], width=kwargs['width'], fig=fig, ax=ax)
try:
fig = Z.figure
ax = Z.axes
except:
pass
if kwargs['dlabels']:
# printedlist
# nodelist = self.ed2nd(edlist)
fig, ax = self.show_nodes(ndlist=kwargs['edlist'], dlabels=kwargs['dlabels'],
color='b', font_size=kwargs['font_size'],
node_shape=kwargs['node_shape'], fig=fig, ax=ax)
if kwargs['dnodes']:
fig, ax = self.show_nodes(ndlist=kwargs['edlist'], color='b', fig=fig, ax=ax)
return fig, ax
[docs] def show_layer(self, name, edlist=[], alpha=1, width=0,
color='black', dnodes=False, dthin=False,
dlabels=False, font_size=15, fGHz=[], fig=[], ax=[]):
""" show layer
Parameters
----------
name :
edlist : []
alpha : float
transparency
width : int
if width = 0 width depends on slab property
color : string
default black'
dnodes :
display nodes (False )
dthin :
display thin ( False )
dlabels :
display labels ( False )
font_size
See Also
--------
show_segment
"""
if fig == []:
fig = plt.figure()
if ax == []:
ax = fig.add_subplot(111)
if edlist == []:
edlist = self.name[name]
else:
# intersect layer edge list with local zone edge list (in function
# argument)
a1 = np.array(self.name[name])
a2 = np.array(edlist)
edlist = list(np.intersect1d(a1, a2))
if self.display['thin']:
fig, ax = self.show_segment(edlist=edlist,
alpha=1,
width=1,
color=color,
dlabels=dlabels,
font_size=font_size, fig=fig, ax=ax)
else:
slab = self.sl[name]
if width == 0:
linewidth = slab['linewidth'] / 3.
else:
linewidth = width
if fGHz == []:
color = slab['color']
else:
if (name != 'METAL') & (name != 'METALIC'):
color = slab.tocolor
else:
color = 'black'
fig, ax = self.show_segment(edlist=edlist, alpha=1,
width=linewidth, color=color, dnodes=dnodes,
dlabels=dlabels, font_size=font_size, fig=fig, ax=ax)
return fig, ax
def _showGi(self, **kwargs):
""" show graph of interactions Gi
Parameters
----------
seed : float
alpha : float
transparency
sig : list of signatures (isequence of Gi nodes format)
cycles : list
[cystart,cyend]
ninter : int
interaction index
inter : tuple
interaction tuple
See Also
--------
Signatures.siginter
"""
defaults = {'seed':1,
'alpha':0.4,
'sig':[],
'cycles':[],
'ninter':0,
'node_size':30,
'fontsize':18,
'labels':False,
'inter':[]}
for k in defaults:
if k not in kwargs:
kwargs[k]=defaults[k]
edges = self.Gi.edges()
cy = kwargs['cycles']
if cy!=[]:
pstart = self.Gt.pos[cy[0]]
pstop = self.Gt.pos[cy[1]]
if kwargs['sig']!=[]:
lsig = kwargs['sig']
edgelist = []
startlist = []
stoplist = []
phe_start = np.array([])
phe_stop = np.array([])
phe_start.shape = (2,0)
phe_stop.shape = (2,0)
for sig in lsig:
edgelist = edgelist + list(zip(sig[0:-1],sig[1:]))
if cy!=[]:
p1 = np.array(self.Gi.pos[sig[0]])[:,None]
p2 = np.array(self.Gi.pos[sig[-1]])[:,None]
phe_start=np.hstack((phe_start,p1))
phe_stop=np.hstack((phe_stop,p2))
elif kwargs['inter']!=[]:
edinter = kwargs['inter']
outlist = self.Gi[edinter[0]][edinter[1]]['output']
outprob = outlist.values()
edgelist = [(edinter[1],x) for x in outlist]
dprob = dict(zip(edgelist,[str(x) for x in outprob]))
elif kwargs['ninter']!=[]:
edinter = [ e for e in edges][kwargs['ninter']]
outlist = self.Gi[edinter[0]][edinter[1]]['output']
outprob = outlist.values()
edgelist = [(edinter[1],x) for x in outlist]
dprob = dict(zip(edgelist,[str(x) for x in outprob]))
else:
pass
ns = kwargs['node_size']
np.random.seed(kwargs['seed'])
fig = plt.figure(figsize=(20,10))
ax1 = plt.subplot(121)
pos = nx.spring_layout(self.Gi)
nx.draw_networkx_nodes(self.Gi,pos,nodelist=[x for x in self.Gi.nodes() if len(x)==1],
node_color='r',node_size=ns,ax=ax1,alpha=kwargs['alpha'])
nx.draw_networkx_nodes(self.Gi,pos,nodelist=[x for x in self.Gi.nodes() if len(x)==2],
node_color='b',node_size=ns,ax=ax1,alpha=kwargs['alpha'])
nx.draw_networkx_nodes(self.Gi,pos,nodelist=[x for x in self.Gi.nodes() if len(x)==3],
node_color='g',node_size=ns,ax=ax1,alpha=kwargs['alpha'])
nx.draw_networkx_edges(self.Gi,pos,edgelist=self.Gi.edges(),width=.1,edge_color='k',arrow=False,ax=ax1)
if (kwargs['sig']==[]):
nx.draw_networkx_edges(self.Gi,pos,edgelist=[edinter],width=2,edge_color='g',arrow=False,ax=ax1)
nx.draw_networkx_edges(self.Gi,pos,edgelist=edgelist,width=2,edge_color='r',arrow=False,ax=ax1)
ax2 = plt.subplot(122)
fig,ax2 = self.showG('s',aw=1,ax=ax2)
nx.draw_networkx_nodes(self.Gi,self.Gi.pos,nodelist=[x for x in self.Gi.nodes() if len(x)==1],
node_color='r',node_size=ns,ax=ax2,alpha=kwargs['alpha'])
nx.draw_networkx_nodes(self.Gi,self.Gi.pos,nodelist=[x for x in self.Gi.nodes() if len(x)==2],
node_color='b',node_size=ns,ax=ax2,alpha=kwargs['alpha'])
nx.draw_networkx_nodes(self.Gi,self.Gi.pos,nodelist=[x for x in self.Gi.nodes() if len(x)==3],
node_color='g',node_size=ns,ax=ax2,alpha=kwargs['alpha'])
nx.draw_networkx_edges(self.Gi,self.Gi.pos,edgelist=self.Gi.edges(),width=.1,edge_color='k',arrow=False,ax=ax2)
if kwargs['labels']:
nx.draw_networkx_labels(self.Gi,self.Gi.pos,labels=[str(x) for x in self.Gi.nodes()],ax=ax2,fontsize=kwargs['fontsize'])
if (kwargs['sig']==[]):
nx.draw_networkx_edges(self.Gi,self.Gi.pos,edgelist=[edinter],width=2,edge_color='g',arrow=False,ax=ax2)
nx.draw_networkx_edges(self.Gi,self.Gi.pos,edgelist=edgelist,width=2,edge_color='r',arrow=False,ax=ax2)
if (kwargs['sig']==[]):
nx.draw_networkx_edge_labels(self.Gi,self.Gi.pos,edge_labels=dprob,ax=ax2,fontsize=kwargs['fontsize'])
if cy!=[]:
ptstart = pstart[:,None]*np.ones(phe_start.shape[1])[None,:]
ptstop = pstop[:,None]*np.ones(phe_start.shape[1])[None,:]
plu.displot(ptstart,phe_start,ax=ax2,arrow=True)
plu.displot(phe_stop,ptstop,ax=ax2,arrow=True)
# interactions corresponding to edge en
# int0, int1 = self.Gi.edges()[kwargs['en']]
#
# print("int0 : ", int0)
# print("int1 : ", int1)
#
# # if interaction is tuple (R or T)
# if ((len(int0) > 1) & (len(int1) > 1)):
# nstr0 = int0[0]
# nstr1 = int1[0]
# e01 = self.Gi.edge[int0][int1]
# lseg = []
# if e01.has_key('output'):
# output = e01['output']
# print(" output ", output)
# ltup = filter(lambda x: type(x) == tuple, output.keys())
# lref = filter(lambda x: len(x) == 2, ltup)
# ltran = filter(lambda x: len(x) == 3, ltup)
# lseg = np.unique(np.array(map(lambda x: x[0], output.keys())))
# probR = np.array(map(lambda x: output[x], lref))
# segR = np.array(map(lambda x: x[0], lref))
# probT = np.array(map(lambda x: output[x], ltran))
# segT = np.array(map(lambda x: x[0], lref))
# dprobR = dict(zip(segR, probR))
# dprobT = dict(zip(segT, probT))
# # print" Sum pR : ",sum(dprobR.values())
# # print" Sum pT : ",sum(dprobT.values())
# # print"lseg", lseg
# # termination points from seg0 and seg1
# pseg0 = self.s2pc[nstr0].toarray().reshape(2, 2).T
# pseg1 = self.s2pc[nstr1].toarray().reshape(2, 2).T
# #
# # create the cone seg0 seg1
# #
# cn = cone.Cone()
# cn.from2segs(pseg0, pseg1)
# # show cone
# # show Gt
# self.display['thin'] = True
# self.display['subseg'] = False
# fig, ax = self.showG('s',aw=1,labels=True)
# fig, ax = cn.show(fig=fig, ax=ax)
# for nse in lseg:
# ta, he = self.Gs.neighbors(nse)
# pta = np.array(self.Gs.pos[ta])
# phe = np.array(self.Gs.pos[he])
#
# try:
# pR = dprobR[nse]
# except:
# pR = 0
#
# try:
# pT = dprobT[nse]
# except:
# pT = 0
#
# alpha = (pR + pT) / 2.
# segment = ax.plot([pta[0], phe[0]],
# [pta[1], phe[1]],
# 'g', linewidth=7, visible=True, alpha=alpha)
#
return(fig, ax1)
def _showGt(self, ax=[], roomlist=[], mode='indoor'):
""" show topological graph Gt
Parameters
-----------
ax : matlplotlib axes
roomlist : list
list of room numbers
mode : string
'indoor','open','area','start'
"""
if not isinstance(ax, plt.Axes):
fig = plt.gcf()
ax = fig.gca()
G = self.Gt
for k, nc in enumerate(G.node.keys()):
if nc!=0:
poly = G.node[nc]['polyg']
a = poly.signedarea()
if mode == 'area':
if a < 0:
poly.plot(color='red', alpha=0.5, fig=fig, ax=ax)
else:
poly.plot(color='green', alpha=0.5, fig=fig, ax=ax)
if mode == 'start':
if poly.vnodes[0] < 0:
poly.plot(color='blue', alpha=0.5, fig=fig, ax=ax)
else:
poly.plot(color='yellow', alpha=0.5, fig=fig, ax=ax)
if mode == 'indoor':
if G.node[nc]['indoor']:
poly.plot(color='green', alpha=0.5, fig=fig, ax=ax)
else:
poly.plot(color='blue', alpha=0.5, fig=fig, ax=ax)
if mode == 'open':
if G.node[nc]['isopen']:
poly.plot(color='green', alpha=0.5, fig=fig, ax=ax)
# else:
# poly.plot(color='blue', alpha=0.5,fig=fig,ax=ax)
ax.axis('scaled')
[docs] def showGs(self, **kwargs):
""" show structure graph Gs
Parameters
----------
ndlist : np.array
set of nodes to be displayed
edlist : np.array
set of edges to be displayed
roomlist : list
default : []
axis :
width : int
2
fGHz : float
show : boolean
default True
furniture : boolean
default False
display parameters are defined in display dictionnary
Returns
-------
ax
See Also
--------
pylayers.gis.layout.showG
"""
defaults = {'ndlist': [],
'edlist': [],
'roomlist': [],
'axis': [],
'width': 2,
'fGHz': [],
'show': False,
'furniture': False,
}
for k in defaults:
if k not in kwargs:
kwargs[k] = defaults[k]
args = {}
for k in kwargs:
if k not in defaults:
args[k] = kwargs[k]
if 'fig' not in kwargs:
fig = plt.figure()
else:
fig = kwargs['fig']
if 'ax' not in kwargs:
ax = fig.add_subplot(111)
else:
ax = kwargs['ax']
if self.display['clear']:
ax.cla()
# display overlay image
if self.display['overlay']:
# imok : Image is OK
imok = False
if len(self.display['overlay_file'].split('http:')) > 1:
#img_file = urllib.urlopen(self.display['overlay_file'])
img_file = urlopen(self.display['overlay_file'])
#im = StringIO(img_file.read())
image = Image.open(im)
imok = True
else:
if self.display['overlay_file'] != '':
image = Image.open(os.path.join(
pro.basename, pro.pstruc['DIRIMAGE'], self.display['overlay_file']))
imok = True
if imok:
if 'v' in self.display['overlay_flip']:
image = image.transpose(Image.FLIP_LEFT_RIGHT)
if 'h' in self.display['overlay_flip']:
image = image.transpose(Image.FLIP_TOP_BOTTOM)
ax.imshow(image, extent=self.display[
'overlay_axis'], alpha=self.display['alpha'], origin='lower')
if kwargs['ndlist'] == []:
tn = np.array(list(self.Gs.node.keys()))
u = np.nonzero(tn < 0)[0]
ndlist = tn[u]
if kwargs['edlist'] == []:
tn = self.Gs.node.keys()
#u = np.nonzero(tn > 0)[0]
#edlist = tn[u]
edlist = filter(lambda x: (x > 0), tn)
#& (not self.Gs.node[x].has_key('ss_name')),tn)
else:
edlist = kwargs['edlist']
if self.display['nodes']:
dlabels = self.display['ndlabel']
fig, ax = self.show_nodes(
ndlist, size=30, color='k', dlabels=dlabels, node_shape='s', fig=fig, ax=ax)
if self.display['isonb']:
if hasattr(self,'lsss'):
seg = [x for x in self.Gs.nodes() if x >0]
# psseg = np.array([[self.Gs.pos[x][0],self.Gs.pos[x][1]] for x in seg])
# nbsseg = np.array([len(self.Gs.node[x]['iso']) for x in seg],dtype='int')
try:
psseg = np.array([[self.Gs.pos[x][0],self.Gs.pos[x][1]] for x in seg
if len(self.Gs.node[x]['iso']) >1])
except:
import ipdb
ipdb.set_trace()
# [ax.text(psseg[x,0]+0.2,psseg[x,1]+0.2,str(nbsseg[x]),
# fontdict={'size':8},ha='center') for x in range(len(seg))]
[ax.text(psseg[x,0]+0.2,psseg[x,1]+0.2,'+',
fontdict={'size':8},ha='center') for x in range(len(psseg))]
if self.display['transition']:
try:
segwtrans = [y for y in [x for x in self.Gs.nodes() if x > 0]if self.Gs.node[
y]['transition']]
posseg = np.array([self.Gs.pos[x] for x in segwtrans])
normseg = np.array([self.Gs.node[x]['norm']
for x in segwtrans])[:, :2]
b1 = (posseg - normseg / 2)
b2 = (posseg + normseg / 2)
[ax.annotate('', xy=b1[x],
xycoords='data',
xytext=b2[x],
textcoords='data',
arrowprops={'arrowstyle': '<->'})
for x in range(len(segwtrans))]
except:
pass
slablist = self.name.keys()
if self.display['edges']:
dlabels = self.display['edlabel']
font_size = self.display['fontsize']
dnodes = self.display['ednodes']
dthin = self.display['thin']
alpha = self.display['alpha']
for nameslab in self.name:
color = self.sl[nameslab]['color']
edlist = self.name[nameslab]
fig, ax = self.show_layer(nameslab, edlist=edlist, alpha=alpha,
dthin=dthin, dnodes=dnodes, dlabels=dlabels,
color=color,
font_size=font_size,
width=kwargs['width'],
fGHz=kwargs['fGHz'],
fig=fig, ax=ax)
if self.display['subseg']:
dico = self.subseg()
for k in dico.keys():
if kwargs['fGHz'] == []:
color = self.sl[k]['color']
else:
if (k != 'METAL') & (k != 'METALIC'):
color = self.sl[k].tocolor(fGHz)
#color = 'red'
else:
color = 'black'
# printk,color
edlist2 = []
for ts in dico[k]:
edlist2.append(ts[0])
# edlist2.append(ts)
edlist3 = list(set(edlist2).intersection(set(edlist)))
# printk , color , edlist
fig, ax = self.show_segment(
edlist=edlist3, color=color, alpha=1.0, width=2, fig=fig, ax=ax)
if self.display['scaled']:
ax.axis('scaled')
ax.set_title(self.display['title'])
#fig = plt.gcf()
#ax = fig.axes[0]
#
# TODO Not working in python 3
#if self.display['ticksoff']:
# ax.xaxis.set_ticks([])
# for loc, spine in ax.spines.iteritems():
# spine.set_color('none')
if kwargs['furniture']:
if 'lfur' in self.__dict__:
for fur1 in self.lfur:
if fur1.Matname == 'METAL':
fig, ax = fur1.show(fig, ax)
else:
print("Warning : no furniture file loaded")
for nr in kwargs['roomlist']:
ncy = self.Gr.node[nr]['cycle']
fig, ax = self.Gt.node[ncy]['polyg'].plot(fig=fig, ax=ax)
if kwargs['axis'] == []:
ax.axis('scaled')
else:
ax.axis(kwargs['axis'])
if kwargs['show']:
plt.show()
return fig, ax
#@profile
[docs] def build(self, graph='tvirw', verbose=False, difftol=0.15, multi=False):
""" build graphs
Parameters
----------
graph : string composed of
't' : Gt
'v' : Gv
'i' : Gi
'r' : Gr
'w" : Gw
verbose : boolean
difftol : diffraction tolerance
multi : boolean
enable multi processing
Notes
-----
This function builds all the graph associated with the Layout.
Warning : by default the layout is saved (dumpw) after each build
"""
# list of built graphs
if not self.hasboundary:
self.boundary()
# to save graoh Gs
self.lbltg.extend('s')
Buildpbar = pbar(verbose,total=5,desc='Build Layout',position=0)
if verbose:
Buildpbar.update(1)
if 't' in graph:
logger.info('buildGt')
self.buildGt(difftol=difftol, verbose=verbose, tqdmpos=1)
self.lbltg.extend('t')
if verbose:
Buildpbar.update(1)
if 'v' in graph:
logger.info('buildGv')
self.buildGv(verbose=verbose, tqdmpos=1)
self.lbltg.extend('v')
if verbose:
Buildpbar.update(1)
if 'i' in graph:
logger.info('buildGi')
self.buildGi(verbose=verbose, tqdmpos=1)
if not multi:
logger.info('outputGi')
self.outputGi(verbose=verbose,tqdmpos=1)
else:
self.outputGi_mp()
self.lbltg.extend('i')
if verbose:
Buildpbar.update(1)
# if 'r' in graph:
# if verbose:
# print"Gr"
# self.buildGr()
# self.lbltg.extend('r')
# if 'w' in graph and len(self.Gr.nodes())>1:
# self.buildGw()
# self.lbltg.extend('w')
# add hash to node 0 of Gs
filelay = pyu.getlong(self._filename, pro.pstruc['DIRLAY'])
fd = open(filelay,'rb')
_hash = hashlib.md5(fd.read()).hexdigest()
fd.close()
self.Gt.add_node(0, hash=_hash)
# There is a dumpw after each build
self.dumpw()
self.isbuilt = True
if verbose:
Buildpbar.update(1)
[docs] def dumpw(self):
""" pickle dump of specified Graphs
Notes
-----
graphs which are in lbltg are saved in pickle format
't' : Gt
's' : Gs
'v' : Gv
'i' : Gi
'r' : Gr
"""
# create layout directory
if os.path.splitext(self._filename)[1]=='.ini':
dirname = self._filename.replace('.ini','')
if os.path.splitext(self._filename)[1]=='.lay':
dirname = self._filename.replace('.lay','')
path = os.path.join(pro.basename, 'struc', 'gpickle', dirname)
if not os.path.isdir(path):
os.mkdir(path)
for g in self.lbltg:
try:
# if g in ['v','i']:
# gname1 ='G'+g
# write_gpickle(getattr(self,gname1),os.path.join(basename,'struc','gpickle','G'+g+'_'+self._filename+'.gpickle'))
# else:
gname = 'G' + g
write_gpickle(getattr(self, gname), os.path.join(
path, 'G' + g + '.gpickle'))
except:
raise NameError(
'G' + g + ' graph cannot be saved, probably because it has not been built')
if 's' in self.lbltg:
if hasattr(self,'sl'):
write_gpickle(getattr(self, 'sl'),
os.path.join(path, 'sl.gpickle'))
if hasattr(self,'dpoly'):
with open(os.path.join(path, 'dpoly.pickle'),'wb') as fd:
pickle.dump(getattr(self,'dpoly'),fd)
# save dictionnary which maps string interaction to
# [interaction node, interaction type]
if 't' in self.lbltg:
if hasattr(self,'ddiff'):
write_gpickle(getattr(self, 'ddiff'),
os.path.join(path, 'ddiff.gpickle'))
if hasattr(self,'lnss'):
write_gpickle(getattr(self, 'lnss'),
os.path.join(path, 'lnss.gpickle'))
if hasattr(self,'dca'):
write_gpickle(getattr(self, 'dca'), os.path.join(path, 'dca.gpickle'))
# write_gpickle(getattr(self,'sla'),os.path.join(path,'sla.gpickle'))
if hasattr(self, 'm'):
write_gpickle(getattr(self, 'm'), os.path.join(path, 'm.gpickle'))
[docs] def dumpr(self, graphs='stvirw'):
""" read of given graphs
Notes
-----
graph : string
's' : Gv
't' : Gt
'r' : Gr
'v' : Gv
'i' : Gi
.gpickle files are store under the struc directory of the project
specified by the $BASENAME environment variable
"""
if os.path.splitext(self._filename)[1]=='.ini':
dirname = self._filename.replace('.ini','')
if os.path.splitext(self._filename)[1]=='.lay':
dirname = self._filename.replace('.lay','')
path = os.path.join(pro.basename, 'struc', 'gpickle', dirname)
for g in graphs:
try:
# if g in ['v','i']:
# gname1 ='G'+g
# setattr(self, gname1, read_gpickle(os.path.join(basename,'struc','gpickle','G'+g+'_'+self._filename+'.gpickle')))
# else:
gname = 'G' + g
filename = os.path.join(path, 'G' + g + '.gpickle')
G = read_gpickle(filename)
setattr(self, gname, G)
self.lbltg.extend(g)
except:
print("Warning Unable to read graph G"+g)
pass
# retrieve md5 sum of the original ini file
if 's' in graphs:
#self._hash = self.Gs.node.pop(0)['hash']
# self._hash = self.Gs.node[0]['hash']
# update self.name
lseg = [x for x in self.Gs.node if x > 0]
for name in self.name:
self.name[name] = [
x for x in lseg if self.Gs.node[x]['name'] == name]
# TODO not necessary useful to call g2npy
self.g2npy()
# TODO use a pickle file instead of gpickle
filesl = os.path.join(path, 'sl.gpickle')
if os.path.isfile(filesl):
sl = read_gpickle(filesl)
setattr(self, 'sl', sl)
filediff = os.path.join(path, 'ddiff.gpickle')
if os.path.isfile(filediff):
ddiff = read_gpickle(filediff)
setattr(self, 'ddiff', ddiff)
else:
self.ddiff={}
filelnss = os.path.join(path, 'lnss.gpickle')
if os.path.isfile(filelnss):
lnss = read_gpickle(filelnss)
setattr(self, 'lnss', lnss)
else :
self.lnss=[]
filedpoly = os.path.join(path, 'dpoly.pickle')
if os.path.isfile(filedpoly):
fd = open(filedpoly,'rb')
dpoly = pickle.load(fd)
setattr(self, 'dpoly', dpoly)
#self.dpoly = {k:eval(self.dpoly[k]) for k in self.dpoly}
self.dpoly = {k:self.dpoly[k] for k in self.dpoly}
else :
self.dpoly = {}
filedca = os.path.join(path, 'dca.gpickle')
if os.path.isfile(filedca):
dca = read_gpickle(filedca)
setattr(self, 'dca',dca)
#
# TODO Replace self.m by pyproj
#
filem = os.path.join(path, 'm.gpickle')
if os.path.isfile(filem):
setattr(self, 'm', read_gpickle(filem))
self.extent = (self.m.lonmin,self.m.lonmax,self.m.latmin,self.m.latmax)
self.pll = self.m(self.extent[0],self.extent[2])
self.pur = self.m(self.extent[1],self.extent[3])
self.extent_c = (self.pll[0],self.pur[0],self.pll[1],self.pur[1])
[docs] def polysh2geu(self, poly):
""" transform sh.Polygon into geu.Polygon
"""
try:
Gsnodes = np.array(self.Gs.nodes())
# get node coordinates
nodept = [self.Gs.pos[i] for i in Gsnodes]
# transform into shapely points
shpt = [sh.Point(pt) for pt in nodept]
# IV 1 get nodes and vnodes
# Create a ring to avoid taking points inside the polygon.
# This helps to avoid polygon inside polygons
# take exterior of polygon. embose it with buffer and find difference with original polygon*.
# polye = poly.intersection((poly.exterior).buffer(1e-3))
uvn = np.where([poly.exterior.buffer(1e-3).contains(p)
for p in shpt])[0]
vnodes = Gsnodes[uvn]
# IV 1.b transform vnodes to an ordered cycle with Cycle class
# NOTE ! Using class cycle is MANDATORY
# because, some extra vnodes can be pickup during the contain
# process before
S = nx.subgraph(self.Gs, vnodes)
cycle = nx.cycle_basis(S)
if len(cycle) > 1:
lc = np.array([len(c) for c in cycle])
dif = abs(lc - len(vnodes))
ud = np.where(dif == min(dif))[0]
cycle = cycle[ud]
else:
cycle = cycle[0]
if cycle[0] > 0:
cycle = np.roll(cycle, -1)
pos = [self.Gs.pos[c] for c in cycle if c < 0]
# IV 1.c create a new polygon with correct vnodes and correct
# points
P = geu.Polygon(p=pos, vnodes=cycle)
except:
import ipdb
ipdb.set_trace()
return P
[docs] def getangles(self, poly, unit='rad', inside=True):
""" find angles of a polygon
Parameters
----------
poly : geu.Polygon or sh.Polygon
unit : str
'deg' : degree values
'rad' : radian values
inside : boolean
True : compute the inside angles of the cycle.
(a.k.a. the interior of the polygon)
False : compute the outside angles of the cycle.
(a.k.a. the exterior of the polygon)
Returns
-------
(u,a)
u : int (Np)
point number
a : float (Np)
associated angle to the point
Notes
-----
http://www.mathopenref.com/polygonexteriorangles.html
TODO : This function should be moved in geomutil.py (NOT USED)
"""
if isinstance(poly, sh.Polygon):
poly = polysh2geu(poly)
cycle = poly.vnodes
upt = cycle[cycle < 0]
# rupt=np.roll(upt,1) # for debug
# rupt2=np.roll(upt,-1) # for debug
#
# See OSM bug fix
#
pt = self.pt[:, self.iupnt[-upt]]
if geu.SignedArea(pt) < 0:
upt = upt[::-1]
pt = pt[:, ::-1]
ptroll = np.roll(pt, 1, axis=1)
v = pt - ptroll
v = np.hstack((v, v[:, 0][:, None]))
vn = v / np.sqrt(np.sum((v) * (v), axis=0))
v0 = vn[:, :-1]
v1 = vn[:, 1:]
cross = np.cross(v0.T, v1.T)
dot = np.sum(v0 * v1, axis=0)
ang = np.arctan2(cross, dot)
uneg = ang < 0
ang[uneg] = -ang[uneg] + np.pi
ang[~uneg] = np.pi - ang[~uneg]
if not inside:
ang = 2 * np.pi - ang
if unit == 'deg':
return upt, ang * 180 / np.pi
elif unit == 'rad':
return upt, ang
# atan2(cross(a,b)), dot(a,b))
[docs] def pltlines(self, lines, fig=[], ax=[], color='r', alpha=1):
""" plot a line with a specified color and transparency
Parameters
-----------
lines : shapely lines
fig : matplotlib figure
ax : figure axis
color : string
alpha : float
transparency
See Also
--------
pylayers.gis.layout.Layout.plot
"""
if fig == []:
fig = plt.gcf()
if ax == []:
ax = plt.gca()
c = np.array([l.xy for l in lines])
[ax.plot(x[0, :], x[1, :], color=color, alpha=alpha) for x in c]
plt.axis(self.ax)
plt.draw()
[docs] def pltpoly(self, poly, fig=[], ax=[], color='r', alpha=0.2):
""" plot a polygon with a specified color and transparency
TODO : To be deplaced in an ither class
"""
if fig == []:
fig = plt.gcf()
if ax == []:
ax = plt.gca()
try:
mpl = [ PolygonPatch(x, alpha=alpha, color=color) for x in poly]
except:
mpl = [ PolygonPatch(x, alpha=alpha, color=color) for x in [poly]]
[ax.add_patch(x) for x in mpl]
plt.axis(self.ax)
plt.draw()
[docs] def pltvnodes(self, vn, fig=[], ax=[]):
""" plot vnodes
Parameters
----------
vn : list of nodes
fig :
ax :
"""
if fig == []:
fig = plt.gcf()
if ax == []:
ax = plt.gca()
if len(vn) > 0:
X = np.array([self.Gs.pos[x] for x in vn])
ax.plot(X[:, 0], X[:, 1], 'or')
[ax.text(x[0], x[1], vn[xx]) for xx, x in enumerate(X)]
return fig, ax
[docs] def updateshseg(self):
""" update shapely segment
build a shapely object for all segments
This function is called at the beginning of buildGt.
See Also
--------
buildGt
"""
seg_connect = {x: self.Gs.node[x]['connect']
for x in self.Gs.nodes() if x > 0}
dpts = {x[0]: (self.Gs.pos[x[1][0]], self.Gs.pos[x[1][1]])
for x in seg_connect.items()}
self._shseg = {p[0]: sh.LineString(p[1]) for p in dpts.items()}
def _triangle_old(self, poly_surround, poly_holes=[], mesh_holes=False):
"""
perfome a delaunay partitioning on shapely polygons
Parameters
----------
poly_surround : sh.Polygon
A single polygon to be partitionned
poly_holes : list of sh.Polygon
A list of polygon contained inside poly_surround. they are considered as holes
mesh_holes : bool
If True make the delaunay partition of poly_holes
else : only partitioning poly_surround and traits poly_holes as holes
Returns
-------
T : dict
dictionnary from triangle.triangulate library
T.keys()
['segment_markers',
'segments',
'holes',
'vertices',
'vertex_markers',
'triangles'
]
Notes
-----
uses triangle library
"""
if not isinstance(poly_surround, list):
poly_surround = [poly_surround]
lP = poly_surround + poly_holes
vertices = np.ndarray(shape=(2, 0))
segments = np.ndarray(shape=(2, 0), dtype='int')
holes = np.ndarray(shape=(2, 0))
segcpt = 0
for p in lP:
pts = np.array(p.exterior.xy)[:, :-1]
vertices = np.hstack((vertices, pts))
nbv = pts.shape[1]
segments = np.hstack((segments, np.array(
[np.arange(nbv), np.mod(range(1, nbv + 1), nbv)], dtype='int') + segcpt))
segcpt = segcpt + nbv
if not mesh_holes:
holes = np.hstack((holes, np.array(p.centroid.xy)))
if not mesh_holes:
C = {'vertices': vertices.T, 'segments': segments.T, 'holes': holes.T}
else:
C = {'vertices': vertices.T, 'segments': segments.T}
import ipdb
ipdb.set_trace()
T = triangle.triangulate(C, 'pa')
# import triangle.plot as plot
# ax=plt.gca()
# plot.plot(ax,**T)
return T
def _merge_polygons(self, lP):
""" merge triangle (polygon object) to cvx polygon
Parameters
----------
lP : list
list of polygon to be merged
Return
------
lMP : list
list of merged polygons
"""
lMP = []
# MERGE POLYGONS
# move from delaunay triangles to convex polygons
while lP != []:
p = lP.pop(0)
# restrict research to polygon that are touching themself
restp = [(ix, x) for ix, x in enumerate(lP)
if isinstance(p.intersection(x), sh.LineString)]
# self.pltpoly(p,ax=plt.gca())
conv = False
pold = p
# for ip2,p2 in restp:
for ip2, p2 in restp:
# inter = p.intersection(p2)
# if 2 triangles have a common segment
p = p + p2
if p.isconvex():
lP.pop(ip2)
lP.insert(0, p)
conv = True
break
else:
# if pold not in cpolys:
# cpolys.append(pold)
p = pold
# if (ip2 >= len(polys)):# and (conv):
# if conv :
# if p not in cpolys:
# cpolys.append(p)
if restp == [] and conv == True:
lMP.append(p)
if not conv: # else:
if pold not in lMP:
lMP.append(pold)
if len(lP) == 0:
if p not in lMP:
lMP.append(p)
return lMP
def _triangle(self, holes=[], vnodes=[] ,bplot = False):
""" Delaunay partitioning on shapely polygons
Parameters
----------
holes : ndarray
if holes ==[] : it means the merge is applied on the interior of the layout (indoor)
if holes == np.ndarray (centroid of polygon). indoor is discarded and delaunay
is applied on outdoor
Returns
-------
T : dict
dictionnary from triangle.triangulate library with the following keys
['segment_markers', 'segments', 'holes', 'vertices', 'vertex_markers', 'triangles']
map_vertices : points index
Notes
-----
This methods uses the `triangle` library
"""
# this means Delaunay is applied on exterior
# and inside polygon will be discarded
segbounds = []
ptbounds = []
if holes == []:
# remove air segments around layout
pass
# [segbounds.extend(nx.neighbors(L.Gs,x)) for x in L.lboundary]
# ptbounds = L.lboundary
if vnodes == []:
vnodes = self.Gs.nodes()
# find termination points of segments of layout
if nx.__version__!='1.10':
seg = np.array([self.Gs[x] for x in vnodes
if x > 0
and x not in segbounds])
else:
seg = np.array([nx.neighbors(self.Gs, x) for x in vnodes
if x > 0
and x not in segbounds])
# get vertices/points of layout
ivertices = np.array([(x, self.Gs.pos[x][0], self.Gs.pos[x][1]) for x in vnodes
if x < 0
and x not in ptbounds])
# map_vertices : points negative index (Np,)
map_vertices = ivertices[:, 0].astype('int')
# vertices : coordinates (Np x 2)
vertices = ivertices[:, 1:]
sorter = np.argsort(map_vertices)
# mapping between Gs graph segments and triangle segments
segments = sorter[np.searchsorted(map_vertices, seg, sorter=sorter)]
if holes == []:
C = {'vertices': vertices, 'segments': segments}
else:
C = {'vertices': vertices, 'segments': segments, 'holes': holes}
T = triangle.triangulate(C, 'pa')
if bplot:
import triangle.plot as plot
ax=plt.gca()
plot.plot(ax,**T)
ax = plt.gca()
ax.get_xaxis().set_visible(True)
ax.get_yaxis().set_visible(True)
plt.show()
return T, map_vertices
[docs] def buildGt(self, check=True, difftol=0.01, verbose=False, tqdmpos=0):
""" build graph of convex cycles
Parameters
----------
check : boolean
difftol : float
verbose : boolean
tqdmpos : progressbar
todo :
- add an option to only take outside polygon
=> pass to self._triangle a hole coreesponding to centroid of
polygon except those of boundary ( see buildGtold )
"""
# 1. Do a Delaunay triangulation
# build a list of triangle polygons : lTP
# vnodes refers to the nodes of Gs
# if vnodes == 0 it means this is a created
# segment which is tagged as _AIR
###
# if verbose :
# Gtpbar = tqdm.tqdm(total=100., desc='BuildGt',position=0)
# pbar_awloop = tqdm.tqdm(total=100., desc ='airwalls loop',leave=False,position=1)
Gtpbar = pbar(verbose,total=100., desc ='BuildGt',position=tqdmpos)
pbartmp = pbar(verbose,total=100., desc ='Triangulation',leave=True,position=tqdmpos+1)
logger.info('buildGt : Triangulation')
T, map_vertices = self._triangle()
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
ptri = T['vertices'][T['triangles']]
# List of Triangle Polygons
pbartmp = pbar(verbose,total=100.,
desc ='Transfer polygons list',
leave=True,
position=tqdmpos+1)
logger.info('buildGt : create list of Polygons')
lTP = [geu.Polygon(x) for x in ptri]
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
# update vnodes of Polygons
pbartmp = pbar(verbose,total=100.,
desc ='Update Polygons vnodes',
leave=True,
position=tqdmpos+1)
#
# p is a polygon
# get_points(p) : get points from polygon
# this is for limiting the search region for large Layout
#
logger.info('buildGt : setvnodes_new on each polygon')
[ polygon.setvnodes_new(self.get_points(polygon), self) for polygon in lTP ]
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
# 2.add air walls to triangle poly
###
# luaw : list of tuples
# ( polygon , array of _AIR segments)
pbartmp = pbar(verbose,total=100.,
desc ='Build list of airwalls',
leave=True,
position=tqdmpos+1)
logger.info('buildGt : get list of airwalls')
luaw = [(p, np.where(p.vnodes == 0)[0]) for p in lTP]
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
#
# For a triangle polygon the number of vnodes
# creates new _AIR segments
#
cpt = 1./(len(luaw)+1)
_airseg = []
pbartmp = pbar(verbose,total=100., desc ='Add airwalls',leave=True,position=tqdmpos+1)
logger.info('buildGt : add new airwalls segments')
for p, uaw in luaw:
# for each vnodes == 0, add an _AIR
if verbose :
pbartmp.update(100.*cpt)
for aw in uaw:
modpt = len(p.vnodes)
_airseg.append(self.add_segment(p.vnodes[np.mod(aw - 1, modpt)],
p.vnodes[np.mod(aw + 1, modpt)],
name='_AIR',
z=(0, 40000000),
verbose=False))
# update polygon segments with new added airwalls
p.setvnodes_new(self.get_points(p),self)
if verbose:
Gtpbar.update(100./12.)
pbartmp = pbar(verbose,total=100., desc ='Update Graph',leave=True,position=tqdmpos+1)
logger.info('buildGt : temporary graph')
tri = T['triangles']
nbtri = len(T['triangles'])
# temporary name/node_index of triangles
MT = -np.arange(1, nbtri + 1)
# 3. Create a temporary graph
# where : positive nodes (>0) are triangles segments
# negative nodes (<0) are triangles centroids
# edges link triangle centroids to their respective segments
# Ex represent list of points in Gs corresponging to segments
#[pt_head pt_tail]
E0 = map_vertices[tri[:, 1:]]
E1 = map_vertices[tri[:, :2]]
E2 = map_vertices[tri[:, 0::2]]
# from [pt_tail pt_head] get segment id in Gs
n0 = [self.numseg(e[0], e[1]) for e in E0]
n1 = [self.numseg(e[0], e[1]) for e in E1]
n2 = [self.numseg(e[0], e[1]) for e in E2]
# creation of a temporary graph
G = nx.Graph()
G.add_edges_from(zip(n0, MT))
G.add_edges_from(zip(n1, MT))
G.add_edges_from(zip(n2, MT))
# 4. search in the temporary graph
###
# nodes of degree 2 :
# - they correspond to Gs segments that link to triangle centroid
# - their neighbors are the triangles centroids
# find nodes of degree 2 (corresponding to segments linked to a
# triangle centroid)
rn = []
rn.extend([un for un in n0 if nx.degree(G, un) == 2])
rn.extend([un for un in n1 if nx.degree(G, un) == 2])
rn.extend([un for un in n2 if nx.degree(G, un) == 2])
rn = np.unique(rn)
# determine the neighbors of those segments (the 2 connected triangles
# centroids)
# v1.1 neigh = [nx.neighbors(G, un) for un in rn]
#neigh = [ dict(G[un]).keys() for un in rn ]
neigh = [[n for n in nx.neighbors(G,un)] for un in rn ]
# store into networkx compliant format
uE = [(neigh[un][0], neigh[un][1], {'segment': [
rn[un]] + self.Gs.node[rn[un]]['iso']}) for un in range(len(rn))]
iuE = {rn[un]: [-neigh[un][0], -neigh[un][1]]
for un in range(len(rn))}
# delete temporary graph
del G
logger.info('buildGt : creates graph Gt')
# create graph Gt
self.Gt = nx.Graph(name='Gt')
self.Gt.add_edges_from(uE)
self.Gt = nx.relabel_nodes(self.Gt, lambda x: -x)
# add polyg to nodes
# add indoor to nodes
# add isopen to nodes
nno = [(n, {'polyg': lTP[n - 1], 'indoor':True, 'isopen':True})
for n in self.Gt.nodes()]
self.Gt.add_nodes_from(nno)
self.Gt.pos = {}
self.Gt.pos.update({n: np.array(
self.Gt.node[n]['polyg'].centroid.xy).squeeze() for n in self.Gt.nodes()})
# self.Gtpos = {-MT[i]:pMT[i] for i in xrange(len(MT))}
# plt.figure()
# # G=nx.Graph()
# # G.add_edges_from(E0)
# # G.add_edges_from(E1)
# # G.add_edges_from(E2)
_airseg = np.array(_airseg)
_airseg = _airseg[_airseg != np.array(None)].astype('int')
_airseg = np.unique(_airseg)
#
# Mikado like progression for simplification of a set of convex polygons
#
# Loop over AIR segments
#
mapoldcy = {c: c for c in self.Gt.nodes()}
# self.showG('st',aw=1)
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
Nairseg = len(_airseg)
cpt = 1./(Nairseg+1)
pbartmp = pbar(verbose,total=100., desc ='Mikado',leave=True,position=tqdmpos+1)
for a in _airseg:
if verbose:
pbartmp.update(100.*cpt)
#
# n0,n1 : cycle number
#
n0, n1 = iuE[a]
found = False
while not found:
nn0 = mapoldcy[n0]
if n0 == nn0:
found = True
else:
n0 = nn0
found = False
while not found:
nn1 = mapoldcy[n1]
if n1 == nn1:
found = True
else:
n1 = nn1
p0 = self.Gt.node[n0]['polyg']
p1 = self.Gt.node[n1]['polyg']
# Merge polygon
P = p0 + p1
# If the new Polygon is convex update Gt
#
if geu.isconvex(P):
# updates vnodes of the new merged polygon
P.setvnodes_new(self.get_points(P),self)
# update edge
n0s = n0
n1s = n1
# get segments information from cycle n0
dne = dict(self.Gt[n0])
# remove connection to n0 to avoid a cycle being
# connected to itself
# v1.1 self.Gt[n1].pop(n0)
dict(self.Gt[n1]).pop(n0)
# add information from adjacent cycle n1
dne.update(dict(self.Gt[n1]))
# list of items of the merged dictionnary
ine = dne.items()
# update n0 with the new merged polygon
self.Gt.add_node(n0, polyg=P)
# connect new cycle n0 to neighbors
# for x in ine:
# if x[0]!=n0:
# ncy = x[0]
# dseg = x[1]
# # a link between cycles already exists
# if self.Gt.has_edge(n0,ncy):
# dseg_prev = self.Gt.edge[n0][ncy]
# dseg['segment']=list(set(dseg['segment']+dseg_prev['segment']))
# printn0,ncy,dseg['segment']
# self.Gt.add_edge(n0,ncy,segment=dseg['segment'])
self.Gt.add_edges_from([(n0, x[0], x[1])
for x in ine if x[0] != n0])
# remove old cycle n1 n
self.Gt.remove_node(n1)
# update pos of the cycle with merged polygon centroid
self.Gt.pos[n0] = np.array((P.centroid.xy)).squeeze()
self.Gt.pos.pop(n1)
# delete _air segment a
# do not apply g2npy
self.del_segment(a, verbose=False, g2npy=False)
mapoldcy[n1] = n0
# fig,a=self.showG('st',aw=1)
# plt.show()
######
# fix renumbering Gt nodes
if verbose:
Gtpbar.update(100./12.)
pbartmp = pbar(verbose,total=100., desc ='Update Gs ncy',leave=True,position=tqdmpos+1)
pos = self.Gt.pos
nl = {c: uc + 1 for uc, c in enumerate(self.Gt.nodes())}
self.Gt = nx.relabel_nodes(self.Gt, nl)
self.Gt.pos = {}
self.Gt.pos = {nl[n]: pos[n] for n in nl}
self._updGsncy()
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
#
# add cycle 0 to boundaries segments
# cycle 0 is necessarily outdoor
#
self.Gt.add_node(0, indoor=False)
for s in self.segboundary:
self.Gs.node[s]['ncycles'].append(0)
#
# boundary adjascent cycles
#
#adjcyair = np.array(map(lambda x: filter(lambda y: y != 0,
# self.Gs.node[x]['ncycles'])[0], self.segboundary))
adjcyair = np.array([[n for n in self.Gs.node[s]['ncycles'] if n!=0]
for s in self.segboundary]).ravel()
# connect cycles separated by air wall to cycle 0
for cy, seg in zip(adjcyair, self.segboundary):
self.Gt.node[cy]['indoor'] = False
self.Gt.node[cy]['isopen'] = True
self.Gt.add_edge(0, cy, segment=[seg])
#
#
#
if check:
# print("check len(ncycles) == 2",)
nodes = [i for i in self.Gs.nodes() if i > 0]
cncy = np.array([len(self.Gs.node[i]['ncycles']) for i in nodes])
ucncyl = np.where(cncy < 2)[0]
ucncym = np.where(cncy > 2)[0]
assert len(ucncyl) == 0, "Some segments are connected to LESS than 2 cycles" + \
str(np.array(nodes)[ucncyl])
assert len(ucncym) == 0, "Some segments are connected to MORE than 2 cycles" + \
str(np.array(nodes)[ucncym])
# print("passed")
# self.degree is updated in g2npy
# self.degree has to be called before determination of diffraction points
# which relies of the full determination of the degree of each point of Gs
# including the corner point with degree 0 ( only connected to _AIR)
self.g2npy()
# find diffraction points : updating self.ddiff
tqdmkwargs={'total':100.,'desc':'Find Diffractions','position':1}
self._find_diffractions(difftol=difftol,verbose=verbose,tqdmkwargs=tqdmkwargs)
if verbose:
Gtpbar.update(100./12.)
# print('find diffraction...Done 8/12')
pbartmp = pbar(verbose,total=100., desc ='Diffraction on airwalls',leave=True,position=tqdmpos+1)
#
# explanation of lnss
#
# list of diffraction point involving different segment
# list of diffraction point involving subsegment ( = iso segments)
# needs checking height in rays.to3D for constructing the 3D ray
#
self.lnss = [x for x in self.ddiff if len(set(self.Gs[x]).intersection(set(self.lsss))) > 0]
#set(nx.neighbors(self.Gs, x)).intersection(set(self.lsss))) > 0]
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
#
# VIII - Construct the list of interactions associated to each cycle
#
# Interaction labeling convention
#
# tuple (npoint,) : Diffraction on point npoint
# tuple (nseg,ncycle) : Reflection on nseg toward cycle ncycle
# tuple (nseg,cy0,cy1) : Transmission from cy0 to cy1 through nseg
#
# At that stage the diffraction points are not included
# not enough information available.
# The diffraction points are not known yet
tqdmkwargs={'total':100.,'desc':'List of interactions','position':1}
self._interlist(verbose=verbose,tqdmkwargs=tqdmkwargs)
if verbose:
Gtpbar.update(100./12.)
#
# dca : dictionnary of cycles which have an air wall
#
pbartmp = pbar(verbose,total=100., desc ='Build dca',leave=True,position=tqdmpos+1)
self.dca = {}
for seg, d in self.Gs.node.items():
if seg > 0:
if ((d['name'] == 'AIR') or d['name'] == '_AIR'):
cy = d['ncycles']
try:
self.dca[cy[0]].append(cy[1])
except:
self.dca[cy[0]] = [cy[1]]
try:
self.dca[cy[1]].append(cy[0])
except:
self.dca[cy[1]] = [cy[0]]
if verbose:
# print('build dca...Done 11/12')
pbartmp.update(100.)
Gtpbar.update(100./12.)
#
# indoor property is spread by contagion
#
pbartmp = pbar(verbose,total=100., desc ='Indoor properties',leave=False,position=tqdmpos+1)
visited = [0]
#v1.1 to_visit = nx.neighbors(self.Gt, 0)
to_visit = list(dict(self.Gt[0]).keys())
law = self.name['_AIR'] + self.name['AIR']
while len(to_visit) > 0:
# get current cycle
cur_cy = to_visit.pop()
# get neighbors of current_cycle
# v1.1 neighbors = nx.neighbors(self.Gt, cur_cy)
neighbors = self.Gt[cur_cy].keys()
# get neighbors separated by an air_wall
neighbors_aw = [x for x in neighbors
if (len(self.Gt[cur_cy][x]['segment'])==1 and
self.Gt[cur_cy][x]['segment'][0] in law
)
]
# get not visited neighbors_aw
nv_neighbors_aw = [
x for x in neighbors_aw if x not in (visited + to_visit)]
# not visited neighbors air wall separated cycles are outdoor cycle
for x in nv_neighbors_aw:
self.Gt.node[x]['indoor'] = False
self.Gt.node[x]['isopen'] = True
# extend to_visit to not visited neighbors
to_visit.extend(nv_neighbors_aw)
visited.append(cur_cy)
if verbose:
pbartmp.update(100.)
Gtpbar.update(100./12.)
self.g2npy()
def _visual_check(self,fontsize=18):
""" visual checking of graphs
Parameters
----------
fontsize : int
"""
fig, axs = plt.subplots(2, 2,figsize=(10,10))
plt.subplots_adjust(left = 0 ,
right = 1.0,
bottom = 0 ,
top = 1 ,
wspace = 0 ,
hspace =0)
if hasattr(self,'Gs') and hasattr(self,'Gt'):
ax = axs[0, 0]
self.showG('s', aw=1, ax=ax, fig=fig)
indoor = [self.Gt.node[p]['polyg']
for p in self.Gt.nodes() if p != 0 and self.Gt.node[p]['indoor']]
outdoor = [self.Gt.node[p]['polyg']
for p in self.Gt.nodes() if p != 0 and not self.Gt.node[p]['indoor']]
self.pltpoly(indoor, color='r', ax=ax, fig=fig)
self.pltpoly(outdoor, color='g', ax=ax, fig=fig)
ax = axs[0, 1]
f, ax = self.showG('s', aw=1, ax=ax, fig=fig)
if hasattr(self,'ddiff'):
diffpos = np.array([self.Gs.pos[x] for x in self.ddiff.keys()])
ax.scatter(diffpos[:, 0], diffpos[:, 1],s=130)
#ax.set_title('Diffraction points')
ax = axs[1, 0]
f, ax = self.showG('st', aw=1, ax=ax, fig=fig)
#ax.set_title('$\mathcal{G}_t$',fontsize=fontsize)
ax.set_axis_off
if hasattr(self,'Gv'):
ax = axs[1, 1]
f, ax = self.showG('sv', aw=1, ax=ax, fig=fig)
#ax.set_title('$\mathcal{G}_v$',fontsize=fontsize)
ax.set_axis_off
else:
print('no Gv found. Yet computed ?')
plt.savefig('visual_check.pdf')
#plt.tight_layout()
# axs[2,1].remove()
def _delaunay(self, poly, polyholes=[]):
""" make a Delaunay partitioning of a polygon
If polyhole == []
if a cycle is non convex
1- find its polygon
2- partition polygon into convex polygons (Delaunay)
3- try to merge partitioned polygons in order to obtain
the minimal number of convex polygons
If polyholes != []
polygon poly contains holes (polyholes)
This methods returns a partitioning of the polygon poly
into several convex polygons (voronoi).
Parameters
----------
poly : sh.Polygon
polyhole : list of sh.Polygon
Returns
-------
ncpol : list
list of new created geu.Polygons
Notes
-----
The algorithm updates the Gt nodes and edges created into self.buildGt
by adding new nodes and new _AIR segments.
Called In
---------
pylayers.gis.layout.buildGt
See Also
--------
pylayers.gis.layout.buildGt
pylayers.gis.layout.add_segment
pylayers.gis.layout.del_segment
pylayers.util.geomutil.Polygon
sp.spatial.Delaunay
"""
pucs = np.array(poly.exterior.xy).T
# keep all convex points (in + out) to build a Delaunay triangulation
if polyholes != []:
if not isinstance(polyholes, list):
polyholes = [polyholes]
for ph in polyholes:
# sum up polyholes to their gathered polygones
pucsh = np.array(ph.exterior.xy).T
pucs = np.vstack((pucs, pucsh))
if len(pucs) != 0:
####
# perform a Delaunay Partioning
####
trid = sp.spatial.Delaunay(pucs)
tri = trid.simplices
polys = []
naw = []
popo = []
for t in tri:
ts = geu.Polygon(pucs[t])
# check if the new polygon is contained into
# the original polygon (non guarantee by Delaunay)
try:
C0 = poly.contains(ts)
except:
from IPython.core.debugger import Tracer
Tracer()()
if polyholes == []:
C = [False]
I = 0
else:
C = [isinstance(ii.intersection(ts), sh.Polygon)
for ii in polyholes]
popo.append(ts)
# if poly contains triangle but not the polyholes
# if polyholes !=[]:
# self.pltpoly([ts],color='b')
# import ipdb
# ipdb.set_trace()
if C0 and (not np.any(C)):
# if polyholes!=[]:
# self.pltpoly([ts],color='r')
# plt.draw()
cp = ts
cp.setvnodes(self)
uaw = np.where(cp.vnodes == 0)[0]
lvn = len(cp.vnodes)
for i in uaw:
# keep track of created airwalls, because some
# of them will be destroyed in step 3.
naw.append(self.add_segment(
cp.vnodes[np.mod(i - 1, lvn)],
cp.vnodes[np.mod(i + 1, lvn)], name='_AIR'))
polys.append(cp)
#
# 3. merge Delaunay triangulation in order to obtain
# the larger convex polygons partitioning
#
diff = poly.difference(sh.MultiPolygon(polys))
if isinstance(diff, sh.Polygon):
diff = sh.MultiPolygon([diff])
if isinstance(diff, sh.MultiPolygon):
for d in diff:
extra = geu.Polygon(d)
extra.setvnodes(self)
polys.append(extra)
cpolys = []
nbpolys = len(polys)
while polys != []:
p = polys.pop(0)
for ip2, p2 in enumerate(polys):
conv = False
inter = p.intersection(p2)
# if 2 triangles have a common segment
pold = p
if isinstance(inter, sh.LineString):
p = p + p2
if p.isconvex():
polys.pop(ip2)
polys.insert(0, p)
conv = True
break
else:
# if pold not in cpolys:
# cpolys.append(pold)
p = pold
# if (ip2 >= len(polys)):# and (conv):
# if conv :
# if p not in cpolys:
# cpolys.append(p)
if not conv: # else:
if pold not in cpolys:
cpolys.append(pold)
if len(polys) == 0:
cpolys.append(p)
# 4. ensure the correct vnode numerotation of the polygons
# and remove unecessary airwalls
# ncpol : new created polygons
ncpol = []
vnodes = []
for p in cpolys:
interpoly = poly.intersection(p)
if isinstance(interpoly, sh.MultiPolygon):
raise AttributeError('multi polygon encountered')
else:
try:
ptmp = geu.Polygon(interpoly)
# ptmp = self.polysh2geu(interpoly)
except:
import ipdb
ipdb.set_trace()
ptmp.setvnodes(self)
ncpol.append(ptmp)
vnodes.extend(ptmp.vnodes)
# if no polyholes
if polyholes == []:
# 4bis
# Check if all the original area is covered
# sometimes, area surrounded by 2 new airwalls is not found
# the following code re-add it.
cpdiff = poly.difference(cascaded_union(cpolys))
if isinstance(cpdiff, sh.Polygon):
cpdiff = sh.MultiPolygon([cpdiff])
if isinstance(cpdiff, sh.MultiPolygon):
for cp in cpdiff:
ptmp = geu.Polygon(cp)
ptmp.setvnodes(self)
ncpol.append(ptmp)
vnodes.extend(ptmp.vnodes)
daw = filter(lambda x: x not in vnodes, naw)
for d in daw:
self.del_segment(d, verbose=False, g2npy=False)
self.g2npy()
return ncpol
def _updGsncy(self):
""" update Gs ncycles using Gt information
Update graph Gs segment with their 2 cycles information
initialize a void list 'ncycles' for each segment of Gs
See Also
--------
pylayers.gis.layout.buildGt
pylayers.gis.layout.convexify
"""
for k in self.Gs.node:
self.Gs.node[k]['ncycles'] = []
# filter out node 0
Gtnodes = filter(lambda x: x != 0, self.Gt.nodes())
# loop over all cycles
for ncy in Gtnodes:
# get vnodes : points and segments number
vnodes = self.Gt.node[ncy]['polyg'].vnodes
for n in vnodes:
if n == 0:
pdb.set_trace()
if ncy not in self.Gs.node[n]['ncycles']:
self.Gs.node[n]['ncycles'].append(ncy)
if n > 0:
if len(self.Gs.node[n]['ncycles']) > 2:
print(n, self.Gs.node[n]['ncycles'])
logger.warning(
'A segment cannot relate more than 2 cycles')
for nseg in self.Gs.node:
if nseg > 0:
ncycles = self.Gs.node[nseg]['ncycles']
if len(ncycles) > 1:
#if nseg not in self.Gt.edge[ncycles[0]][ncycles[1]]['segment']:
# self.Gt.edge[ncycles[0]][ncycles[1]][
# 'segment'].append(nseg)
if nseg not in self.Gt[ncycles[0]][ncycles[1]]['segment']:
self.Gt[ncycles[0]][ncycles[1]]['segment'].append(nseg)
def _addoutcy(self, check=False):
"""
Probably use in a future version of buildGt , managing the upcoming inifile
add outside cycle (absorbant region index 0 )
Parameters
----------
check : Boolean
# if ncycles is a list which has only one element then the adjascent
# cycle is the outside region (cycle 0)
"""
seg0 = []
for macvx in self.macvx:
seg = [i for i in macvx.vnodes if i > 0]
seg0 = seg0 + seg
[self.Gs.node[i]['ncycles'].append(0) for i in seg0]
if check:
print("check len(ncycles) == 2",)
nodes = [i for i in self.Gs.nodes() if i > 0]
cncy = np.array([len(self.Gs.node[i]['ncycles']) for i in nodes])
ucncyl = np.where(cncy < 2)[0]
ucncym = np.where(cncy > 2)[0]
assert len(ucncyl) == 0, "Some segments are connected to LESS than 2 cycles" + \
str(np.array(nodes)[ucncyl])
assert len(ucncym) == 0, "Some segments are connected to MORE than 2 cycles" + \
str(np.array(nodes)[ucncym])
print("passed")
def _interlist(self, nodelist=[],verbose = False,tqdmkwargs={}):
""" Construct the list of interactions associated to each cycle
Parameters
----------
nodelist: list
list of Gt nodes (cycles) for which interactions have to be found
Notes
-----
if selfr.indoor==True , get list of interaction of Gt cycle with indoor =True
else list of indoor interaction is skipped
Interaction labeling convention
tuple (npoint,) : Diffraction on point npoint
tuple (nseg,ncycle) : Reflection on nseg toward cycle ncycle
tuple (nseg,cy0,cy1) : Transmission from cy0 to cy1 through nseg
At that stage the diffraction points are not included
not enough information available. The diffraction point are not
known yet
See Also
--------
pylayers.gis.layout.buildGt
pylayers.gis.layout._convex_hull
"""
if tqdmkwargs=={}:
tqdmkwargs={'total':100.,
'desc':'list of interactions',
'position':0}
if nodelist == []:
nodelist = self.Gt.nodes()
elif not isinstance(nodelist, list):
nodelist = [nodelist]
# for all cycles k (node of Gt)
if verbose :
cpt = 1./(len(nodelist)+1.)
pbar = tqdm.tqdm(tqdmkwargs)
for k in nodelist:
if verbose:
pbar.update(100.*cpt)
if k != 0:
if self.typ=='indoor' or not self.Gt.node[k]['indoor']:
#vnodes = self.Gt.node[k]['vnodes']
vnodes = self.Gt.node[k]['polyg'].vnodes
ListInteractions = []
for inode in vnodes:
if inode > 0: # segments
cy = set(self.Gs.node[inode]['ncycles'])
name = self.Gs.node[inode]['name'] # segment name
#
# Reflexion occurs on segment different
# from AIR and ABSORBENT (segment number, cycle)
#
if ((name != '_AIR') & (name != 'AIR') & (name != 'ABSORBENT')):
ListInteractions.append((inode, k))
#
# Transmission requires 2 cycles separated by a
# segment which is different from METAL and ABSORBENT
#
# (segment number, cycle in , cycle out )
if len(cy) == 2:
if ('METAL' not in name) & ('ABSORBENT' not in name):
ncy = list(cy.difference({k}))[0]
ListInteractions.append((inode, k, ncy))
ListInteractions.append((inode, ncy, k))
else: # points
pass
# add list of interactions of a cycle
self.Gt.add_node(k, inter=ListInteractions)
else:
self.Gt.add_node(k, inter=[])
def _convex_hull(self, mask):
"""
Add air walls to the layout enveloppe in self.Gs
in order the hull of the Layout to be convex.
Parameters
----------
mask : Polygon
Returns
-------
polys : list of geu.Polygon
nsew polygon of the convex hull
self.macvx : convex mask of the layout
Notes
-----
This is a post processing of BuildGt
See Also
--------
pylayers.gis.layout._interlist
"""
# 1 - Find differences between the convex hull and the Layout contour
# The result of the difference are polygons
masku = cascaded_union(mask)
ch = masku.convex_hull
P = ch.difference(masku)
polys = []
if isinstance(P, sh.MultiPolygon):
for p in P:
if p.area > 1e-3:
polys.append(geu.Polygon(p))
polys[-1].setvnodes(self)
lncy = []
for p in polys:
# p.coorddeter()
uaw = np.where(p.vnodes == 0)
for aw in uaw:
# 2 - non existing segments are created as airwalls
awid = self.add_segment(
p.vnodes[aw - 1][0], p.vnodes[aw + 1][0], name='AIR')
p.vnodes[aw] = awid
# U = cascaded_union([mask]+polys)
# self.macvx = geu.Polygon(U)
# self.macvx.setvnodes(self)
return polys
[docs] def buildGv(self, show=False,verbose=False,tqdmpos=0):
""" build visibility graph
Parameters
----------
show : boolean
default False
verbose : boolean
tqdmpos : progressbar
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('TA-Office.lay')
>>> L.buildGt()
>>> Ga = L.buildGr()
>>> L.buildGv()
Notes
-----
This method exploits cycles convexity.
"""
if not hasattr(self,'ddiff'):
self.ddiff={}
Gvpbar = pbar(verbose,total=100., desc ='build Gv',position=tqdmpos)
self.Gv = nx.Graph(name='Gv')
#
# loop over convex cycles (nodes of Gt)
#
self.dGv = {} # dict of Gv graph
cpt = 1./(len(self.Gt.node) + 1.)
for icycle in self.Gt.node:
if verbose:
Gvpbar.update(100.*cpt)
if icycle != 0:
#if self.indoor or not self.Gt.node[icycle]['indoor']:
#print(icycle)
# pass
#
# If indoor or outdoor all visibility are calculated
# If outdoor only visibility between iso = 'AIR' and '_AIR' are calculated
#
#if self.indoor or not self.Gt.node[icycle]['indoor']:
polyg = self.Gt.node[icycle]['polyg']
# plt.show(polyg.plot(fig=plt.gcf(),ax=plt.gca())
# take a single segment between 2 points
vnodes = polyg.vnodes
# list of index of points in vodes
unodes = np.where(vnodes<0)[0]
# list of position of an incomplete list of segments
# used rule : after a point there is always a segment
useg = np.mod(unodes+1,len(vnodes))
# list of points
#npt = filter(lambda x: x < 0, vnodes)
npt = [ x for x in vnodes if x <0 ]
nseg_full = [x for x in vnodes if x > 0]
# nseg : incomplete list of segments
#
# if mode outdoor and cycle is indoor only
# the part above the building (AIR and _AIR) is considered
if ((self.typ=='outdoor') and (self.Gt.node[icycle]['indoor'])):
nseg = [ x for x in nseg_full if ((self.Gs.node[x]['name']=='AIR') or (self.Gs.node[x]['name']=='_AIR') ) ]
else:
nseg = vnodes[useg]
# # nseg_full : full list of segments
# #nseg_full = filter(lambda x: x > 0, vnodes)
# # keep only airwalls without iso single (_AIR)
# nseg_single = filter(lambda x: len(self.Gs.node[x]['iso'])==0, nseg)
# lair1 = self.name['AIR']
# lair2 = self.name['_AIR']
# lair = lair1 + lair2
# # list of airwalls in nseg_single
# airwalls = filter(lambda x: x in lair, nseg_single)
# diffraction points
ndiff = [x for x in npt if x in self.ddiff.keys()]
#
# Create a graph
#
Gv = nx.Graph(name='Gv')
#
# in convex case :
#
# i) every non aligned segments see each other
#
for nk in combinations(nseg, 2):
nk0 = self.tgs[nk[0]]
nk1 = self.tgs[nk[1]]
tahe0 = self.tahe[:, nk0]
tahe1 = self.tahe[:, nk1]
pta0 = self.pt[:, tahe0[0]]
phe0 = self.pt[:, tahe0[1]]
pta1 = self.pt[:, tahe1[0]]
phe1 = self.pt[:, tahe1[1]]
aligned = geu.is_aligned4(pta0,phe0,pta1,phe1)
# A0 = np.vstack((pta0, phe0, pta1))
# A0 = np.hstack((A0, np.ones((3, 1))))
# A1 = np.vstack((pta0, phe0, phe1))
# A1 = np.hstack((A1, np.ones((3, 1))))
# d0 = np.linalg.det(A0)
# d1 = np.linalg.det(A1)
#if not ((abs(d0) < 1e-1) & (abs(d1) < 1e-1)):
if not aligned:
if ((0 not in self.Gs.node[nk[0]]['ncycles']) and
(0 not in self.Gs.node[nk[1]]['ncycles'])):
# get the iso segments of both nk[0] and nk[1]
if ((self.typ=='indoor') or (not self.Gt.node[icycle]['indoor'])):
l0 = [nk[0]]+self.Gs.node[nk[0]]['iso']
l1 = [nk[1]]+self.Gs.node[nk[1]]['iso']
else:
l0 = [nk[0]]
l1 = [nk[1]]
for vlink in product(l0,l1):
#printicycle,vlink[0],vlink[1]
Gv.add_edge(vlink[0], vlink[1])
#
# Handle diffraction points
#
# ii) all non adjascent valid diffraction points see each other
# iii) all valid diffraction points see segments non aligned
# with adjascent segments
#
#if diffraction:
#
# diffraction only if indoor or outdoor cycle if outdoor
#
if ((self.typ=='indoor') or (not self.Gt.node[icycle]['indoor'])):
ndiffvalid = [ x for x in ndiff if icycle in self.ddiff[x][0]]
# non adjascent segment of vnodes see valid diffraction
# points
for idiff in ndiffvalid:
#
# segments voisins du point de diffraction valide
#
# v1.1 nsneigh = [x for x in
# nx.neighbors(self.Gs, idiff)
# if x in nseg_full]
nsneigh = [x for x in self.Gs[idiff] if x in nseg_full]
# segvalid : not adjascent segment
seen_from_neighbors = []
#
# point to point
#
for npoint in ndiffvalid:
if npoint != idiff:
Gv.add_edge(idiff, npoint)
#
# All the neighbors segment in visibility which are not connected to cycle 0
# and which are not neighbors of the point idiff
#
for x in nsneigh:
# v1.1 neighbx = [ y for y in nx.neighbors(Gv, x)
# if 0 not in self.Gs.node[y]['ncycles']
# and y not in nsneigh]
neighbx = [ y for y in Gv[x]
if 0 not in self.Gs.node[y]['ncycles']
and y not in nsneigh]
seen_from_neighbors += neighbx
for ns in seen_from_neighbors:
Gv.add_edge(idiff, ns)
#
# Graph Gv composition
#
self.Gv = nx.compose(self.Gv, Gv)
self.dGv[icycle] = Gv
[docs] def buildGi(self,verbose=False,tqdmpos=0):
""" build graph of interactions
Notes
-----
For each node of graph Gv creates
5 different nodes associated to the same segment
(np,) D
(ns,cy0) R -> cy0
(ns,cy1) R -> cy1
(ns,cy0,cy1) T 0->1
(ns,cy1,cy0) T 1->0
Gi is an oriented Graph (DiGraph)
"""
Gipbar = pbar(verbose,total=100., desc ='Build Gi',position=tqdmpos)
if verbose:
Gipbar.update(0.)
self.Gi = nx.DiGraph(name='Gi')
self.Gi.pos = {}
#
# 1 ) Create nodes of Gi and their positions
#
# diffraction node (D,)
# reflexion node (R,cy0)
# transmission node (T,cy0,cy1)
#
cpt = 100./(len(self.Gv.node)+1)
pbartmp = pbar(verbose,total=100., desc ='Create Gi nodes',position=tqdmpos+1)
for n in self.Gv.node:
# espoo_journal debug
#if n == 530:
if verbose:
pbartmp.update(cpt)
if n < 0: # D
self.Gi.add_node((n,))
self.Gi.pos[(n,)] = self.Gs.pos[n]
if n > 0: # R | T
cy = self.Gs.node[n]['ncycles']
name = self.Gs.node[n]['name']
assert(len(cy) == 2)
cy0 = cy[0]
cy1 = cy[1]
#nei = self.Gs.neighbors(n) # get neighbor
nei = list(dict(self.Gs[n]).keys()) # get neighbor
np1 = nei[0]
np2 = nei[1]
p1 = np.array(self.Gs.pos[np1])
p2 = np.array(self.Gs.pos[np2])
l = p1 - p2
nl = np.dot(l, l)
ln = l / nl
delta = nl / 10.
# On AIR or ABSORBENT there is no reflection
if ((name != '_AIR') & (name != 'AIR') & (name != 'ABSORBENT')):
self.Gi.add_node((n, cy0))
self.Gi.pos[(n, cy0)] = tuple(self.Gs.pos[n] + ln * delta)
self.Gi.add_node((n, cy1))
self.Gi.pos[(n, cy1)] = tuple(self.Gs.pos[n] - ln * delta)
# Through METAL or ABSORBENT there is no transmission
# except if n has a subsegment
if (name != 'METAL') & (name != 'ABSORBENT'):
self.Gi.add_node((n, cy0, cy1))
self.Gi.add_node((n, cy1, cy0))
self.Gi.pos[(n, cy0, cy1)] = tuple(
self.Gs.pos[n] + ln * delta / 2.)
self.Gi.pos[(n, cy1, cy0)] = tuple(
self.Gs.pos[n] - ln * delta / 2.)
#
# 2) Establishing link between interactions
#
# Loop over all Gt nodes cy
#
# if cy > 0
# calculates vnodes of cycles
# for all node of vnodes
#
iprint = 0
if verbose :
Gipbar.update(33.)
cpt = 100./(len(self.Gt.node)+1)
pbartmp = pbar(verbose,total=100., desc ='Create Gi nodes',position=tqdmpos+1)
for cy in self.Gt.node:
if verbose:
pbartmp.update(cpt)
# for all >0 convex cycles
if cy > 0:
vnodes = self.Gt.node[cy]['polyg'].vnodes
npt = []
#
# find all diffraction points involved in the cycle cy
#
for x in vnodes:
if x < 0:
if x in self.ddiff:
for y in self.ddiff[x][0]:
if y == cy:
npt.append(x)
nseg = [ k for k in vnodes if k>0 ]
# all segments and diffraction points of the cycle
vnodes = nseg + npt
for nstr in vnodes:
if nstr in self.Gv.nodes():
# list 1 of interactions
li1 = []
if nstr > 0:
# output cycle
# cy -> cyo1
cyo1 = self.Gs.node[nstr]['ncycles']
cyo1 = [ x for x in cyo1 if x!= cy] [0]
#cyo1 = filter(lambda x: x != cy, cyo1)[0]
# R , Tin , Tout
if cyo1 > 0:
if (nstr, cy) in self.Gi.nodes():
li1.append((nstr, cy)) # R
if (nstr, cy, cyo1) in self.Gi.nodes():
li1.append((nstr, cy, cyo1)) # T cy -> cyo1
if (nstr, cyo1, cy) in self.Gi.nodes():
li1.append((nstr, cyo1, cy)) # T : cyo1 -> cy
# if (nstr,cy) in self.Gi.nodes():
# li1 = [(nstr,cy),(nstr,cy,cyo1),(nstr,cyo1,cy)]
# else:# no reflection on airwall
# li1 = [(nstr,cyo1,cy)]
else:
if (nstr, cy) in self.Gi.nodes():
li1 = [(nstr, cy)]
# else:
# li1 =[]
else:
# D
li1 = [(nstr,)]
# list of cycle entities in visibility of nstr
# v1.1 lneighb = nx.neighbors(self.Gv, nstr)
lneighb = list(dict(self.Gv[nstr]).keys())
#if (self.Gs.node[nstr]['name']=='AIR') or (
# self.Gs.node[nstr]['name']=='_AIR'):
# lneighcy = lneighb
#else:
# list of cycle entities in visibility of nstr in the same cycle
lneighcy = [ x for x in lneighb if x in vnodes ]
# lneighcy = filter(lambda x: x in vnodes, lneighb)
for nstrb in lneighcy:
if nstrb in self.Gv.nodes():
li2 = []
if nstrb > 0:
cyo2 = self.Gs.node[nstrb]['ncycles']
cyo2 = [ x for x in cyo2 if x!= cy] [0]
#cyo2 = filter(lambda x: x != cy, cyo2)[0]
if cyo2 > 0:
if (nstrb, cy) in self.Gi.nodes():
li2.append((nstrb, cy))
if (nstrb, cy, cyo2) in self.Gi.nodes():
li2.append((nstrb, cy, cyo2))
if (nstrb, cyo2, cy) in self.Gi.nodes():
li2.append((nstrb, cyo2, cy))
# if (nstrb,cy) in self.Gi.nodes():
# li2 = [(nstrb,cy),(nstrb,cy,cyo2),(nstrb,cyo2,cy)]
# else: #no reflection on airwall
# li2 = [(nstrb,cy,cyo2),(nstrb,cyo2,cy)]
else:
if (nstrb, cy) in self.Gi.nodes():
li2 = [(nstrb, cy)]
else:
li2 = [(nstrb,)]
# if cy==4:
# printnstr,nstrb
#if iprint:
# print("li1",li1)
# print("li2",li2)
#if cy == 91:
# print(" ",li2)
for i1 in li1:
for i2 in li2:
if (i1[0] != i2[0]):
if ((len(i1) == 2) & (len(i2) == 2)):
# print"RR"
self.Gi.add_edge(i1, i2)
self.Gi.add_edge(i2, i1)
if ((len(i1) == 2) & (len(i2) == 3)):
# print"RT"
if i1[1] == i2[1]:
self.Gi.add_edge(i1, i2)
if ((len(i1) == 3) & (len(i2) == 2)):
# print"TR"
if i1[2] == i2[1]:
self.Gi.add_edge(i1, i2)
if ((len(i1) == 3) & (len(i2) == 3)):
# print"TT"
if i1[2] == i2[1]:
self.Gi.add_edge(i1, i2)
if i2[2] == i1[1]:
self.Gi.add_edge(i2, i1)
if ((len(i1) == 1) & (len(i2) == 3)):
# print"DT"
if i2[1] == cy:
self.Gi.add_edge(i1, i2)
if ((len(i1) == 3) & (len(i2) == 1)):
# print"TD"
if i1[2] == cy:
self.Gi.add_edge(i1, i2)
if ((len(i1) == 1) & (len(i2) == 2)):
# print"DR"
self.Gi.add_edge(i1, i2)
if ((len(i1) == 2) & (len(i2) == 1)):
# print"RD"
self.Gi.add_edge(i1, i2)
if ((len(i1) == 1) & (len(i2) == 1)):
# print"DD"
self.Gi.add_edge(i1, i2)
if verbose :
Gipbar.update(66.)
# updating the list of interactions of a given cycle
pbartmp = pbar(verbose,total=100.,
desc ='update interraction list',
leave=False,
position=tqdmpos+1)
for c in self.Gt.node:
if verbose:
pbartmp.update(cpt)
if c != 0:
vnodes = self.Gt.node[c]['polyg'].vnodes
for k in npt:
self.Gt.node[c]['inter'] += [(k,)]
if verbose :
Gipbar.update(100.)
# cleaning deadend Gi
# if outdoor for all nodes of Gi
# if not diffraction
# if termination cycle is indoor
# or if starting point is indoor
# then delete interaction
ldelete = []
if self.typ=='outdoor':
for k in list(dict(self.Gi.node).keys()):
# R and T
if len(k)>1:
segtype = self.Gs.node[k[0]]['name']
if ((segtype!='AIR') and (segtype!='_AIR')):
cyend = k[-1]
if self.Gt.node[cyend]['indoor']:
# if k[0]>0:
# if self.Gs.node[k[0]]['name']!='AIR':
ldelete.append(k)
if len(k) == 3:
cystart = k[1]
if self.Gt.node[cystart]['indoor']:
# if k[0]>0:
# if self.Gs.node[k[0]]['name']!='AIR':
ldelete.append(k)
self.Gi.remove_nodes_from(ldelete)
# build adjacency matrix of Gi graph
self.Gi_A = nx.adjacency_matrix(self.Gi)
#store list of nodes of Gi ( for keeping order)
self.Gi_no = self.Gi.nodes()
[docs] def filterGi(self, situ='outdoor'):
""" filter Gi to manage indoor/outdoor situations
Not called
"""
# get outdoor notes
cy = np.array(self.Gt.nodes())
uout = np.where([not self.Gt.node[i]['indoor'] for i in cy])
cyout = cy[uout]
inter = self.Gi.nodes()
Ti = [i for i in inter if ((len(i) == 3) and i[0] > 0)]
Ri = [i for i in inter if ((len(i) == 2) and i[0] > 0)]
Di = [i for i in inter if i[0] < 0]
Ti = [i for i in Ti if ((i[1] in cyout) and (i[2] in cyout))]
Ri = [i for i in Ri if (i[1] in cyout)]
Di = [i for i in Di if (i in self.ldiffout)]
rinter = Ti + Ri + Di
rGi = nx.subgraph(self.Gi, rinter)
rGi.pos = {i: self.Gi.pos[i] for i in self.Gi.nodes()}
self.Gi = rGi
self.Gi.pos = rGi.pos
#@profile
[docs] def outputGi(self, verbose=False, tqdmpos=0.):
""" filter output of Gi edges
Parameters
----------
L : Layout
Notes
-----
Let assume a sequence (nstr0,nstr1,{nstr2A,nstr2B,...}) in a signature.
This function checks whether this sequence is feasible or not
, whatever the type of nstr0 and nstr1.
The feasible outputs from nstr0 to nstr1 are stored in an output field of
edge (nstr0,nstr1)
See Also
--------
pylayers.util.cone.Cone.from2seg
pylayers.util.cone.Cone.belong_seg
"""
assert('Gi' in self.__dict__)
oGipbar=pbar(verbose,total=100.,leave=False,desc='OutputGi',position=tqdmpos)
# loop over all edges of Gi
Nedges = len(self.Gi.edges())
cpt = 100./Nedges
# print "Gi Nedges :",Nedges
cn = cone.Cone()
for k, e in enumerate(self.Gi.edges()):
# if (k%100)==0:
# print"edge : ",k
# extract both termination interactions nodes
if verbose:
oGipbar.update(cpt)
i0 = e[0]
i1 = e[1]
nstr0 = i0[0]
nstr1 = i1[0]
# list of authorized outputs. Initialized void
output = []
# nstr1 : segment number of central interaction
if nstr1 > 0:
# central interaction is a segment
pseg1 = self.seg2pts(nstr1).reshape(2, 2).T
#pseg1 = self.s2pc[nstr1].toarray().reshape(2, 2).T
# list all potential successors of interaction i1
# v1.1 i2 = nx.neighbors(self.Gi, i1)
i2 = list(dict(self.Gi[i1]).keys())
# create a Cone object
#cn = cone.Cone()
# if starting from segment
if nstr0 > 0:
pseg0 = self.seg2pts(nstr0).reshape(2, 2).T
#pseg0 = self.s2pc[nstr0].toarray().reshape(2, 2).T
# if nstr0 and nstr1 are connected segments
# v1.1 if (len(np.intersect1d(nx.neighbors(self.Gs, nstr0), nx.neighbors(self.Gs, nstr1))) == 0):
if (len(np.intersect1d(self.Gs[nstr0], self.Gs[nstr1])) == 0):
# from 2 not connected segment
cn.from2segs(pseg0, pseg1)
else:
# from 2 connected segments
cn.from2csegs(pseg0, pseg1)
# if starting from a point
else:
pt = np.array(self.Gs.pos[nstr0])
cn.fromptseg(pt, pseg1)
#
ipoints = [x for x in i2 if len(x)==1 ]
# i0 i1 i2[x]
# Avoid to have the same diffaction point after reflection
# exemple : (-10,),(245,12),(-10,) impossible
# nstr0 nstr1
if nstr0<0:
ipoints = [x for x in ipoints if x[0]!=nstr0]
#ipoints = filter(lambda x: len(x) == 1, i2)
pipoints = np.array([self.Gs.pos[ip[0]] for ip in ipoints]).T
# filter tuple (R | T)
#istup = filter(lambda x : type(eval(x))==tuple,i2)
# map first argument segment number
#isegments = np.unique(map(lambda x : eval(x)[0],istup))
#isegments = np.unique(
# filter(lambda y: y > 0, map(lambda x: x[0], i2)))
isegments = np.unique(np.array([ s for s in [ n[0] for n in i2]
if s >0 ] ))
# if nstr0 and nstr1 are adjescent segment remove nstr0 from
# potential next interaction
# Fix 01/2017
# This is not always True if the angle between
# the two adjascent segments is < pi/2
# v1.1 nb_nstr0 = self.Gs.neighbors(nstr0)
# v1.1 nb_nstr1 = self.Gs.neighbors(nstr1)
nb_nstr0 = self.Gs[nstr0]
nb_nstr1 = self.Gs[nstr1]
#common_point = np.intersect1d(nb_nstr0,nb_nstr1)
common_point = np.array([x for x in nb_nstr0 if x in nb_nstr1]).astype('int')
if len(common_point) == 1:
num0 = [x for x in nb_nstr0 if x != common_point]
num1 = [x for x in nb_nstr1 if x != common_point]
p0 = np.array(self.Gs.pos[num0[0]])
p1 = np.array(self.Gs.pos[num1[0]])
pc = np.array(self.Gs.pos[common_point[0]])
v0 = p0 - pc
v1 = p1 - pc
v0n = v0/np.sqrt(np.sum(v0*v0))
v1n = v1/np.sqrt(np.sum(v1*v1))
if np.dot(v0n,v1n)<=0:
isegments = np.array([ x for x in isegments if x != nstr0 ])
# filter(lambda x: x != nstr0, isegments))
# there are one or more segments
if len(isegments) > 0:
points = self.seg2pts(isegments)
pta = points[0:2, :]
phe = points[2:, :]
# add difraction points
# WARNING Diffraction points are added only if a segment is seen
# it should be the case in 99% of cases
if len(ipoints) > 0:
isegments = np.hstack((isegments, np.array(ipoints)[:, 0]))
pta = np.hstack((pta, pipoints))
phe = np.hstack((phe, pipoints))
# cn.show()
# if i0 == (38,79) and i1 == (135,79,23):
# printi0,i1
# import ipdb
# ipdb.set_trace()
# i1 : interaction T
if len(i1) == 3:
#if ((e[0]==(53,17)) and (e[1]==(108,17,18))):
# typ, prob = cn.belong_seg(pta, phe,visu=True)
#else:
#typ, prob = cn.belong_seg_old(pta, phe, prob=False)
typ = cn.belong_seg(pta, phe)
# if bs.any():
# plu.displot(pta[:,bs],phe[:,bs],color='g')
# if ~bs.any():
# plu.displot(pta[:,~bs],phe[:,~bs],color='k')
# i1 : interaction R --> mirror
if len(i1) == 2:
Mpta = geu.mirror(pta, pseg1[:, 0], pseg1[:, 1])
Mphe = geu.mirror(phe, pseg1[:, 0], pseg1[:, 1])
typ = cn.belong_seg(Mpta, Mphe)
#typ, prob = cn.belong_seg_old(Mpta, Mphe, prob=False)
# keep segment with typ <> 0
utypseg = typ != 0
isegkeep = isegments[utypseg]
# dict {numint : proba}
#dsegprob = {k: v for k, v in zip(isegkeep, prob[utypseg])}
#########
# output = filter(lambda x: x[0] in isegkeep, i2)
output = [x for x in i2 if x[0] in isegkeep]
# probint = map(lambda x: dsegprob[x[0]], output)
#probint = [dsegprob[x[0]] for x in output]
# dict interaction : proba
#dintprob = {k: v for k, v in zip(output, probint)}
# keep all segment above nstr1 and in Cone if T
# keep all segment below nstr1 and in Cone if R
else:
# central interaction is a point (nstr1 <0)
# 1) Simple approach
# output interaction are all visible interactions
# 2) TO BE DONE
#
# output of the diffraction points
# exploring
# b
# + right of ISB
# + right of RSB
#
# + using the wedge cone
# + using the incident cone
#
# v1.1 output = nx.neighbors(self.Gi, (nstr1,))
output = self.Gi[(nstr1,)]
#nout = len(output)
#probint = np.ones(nout) # temporarybns
#dintprob = {k: v for k, v in zip(output, probint)}
#self.Gi.add_edge(i0, i1, output=dintprob)
self.Gi.add_edge(i0, i1, output=output)
[docs] def outputGi_new(self,verbose=False,tqdmpos=0.):
""" filter output of Gi edges
this version of outputGi, uses sparses matrix instead of NetworkX for MP
purpose
Parameters
----------
L : Layout
Notes
-----
Let assume a sequence (nstr0,nstr1,{nstr2A,nstr2B,...}) in a signature.
This function checks whether this sequence is feasible or not
, whatever the type of nstr0 and nstr1.
The feasible outputs from nstr0 to nstr1 are stored in an output field of
edge (nstr0,nstr1)
See Also
--------
pylayers.util.cone.Cone.from2seg
pylayers.util.cone.Cone.belong_seg
"""
def Gspos(n):
if n>0:
return np.mean(self.s2pc[n].toarray().reshape(2,2),axis=0)
else:
return self.p2pc[-n].toarray()
#s2pc = self.s2pc.toarray()
#s2pu = self.s2pu.toarray()
#p2pc = self.p2pc.toarray()
#A = self.Gi_A.toarray()
assert('Gi' in self.__dict__)
oGipbar = pbar(verbose,total=100.,leave=False,desc='OutputGi',position=tqdmpos)
# loop over all edges of Gi
Nedges = len(self.Gi.edges())
cpt = 100./Nedges
# print "Gi Nedges :",Nedges
for k, e in enumerate(self.Gi.edges()):
# if (k%100)==0:
# print"edge : ",k
# extract both termination interactions nodes
if verbose:
oGipbar.update(cpt)
i0 = e[0] # first interaction
i1 = e[1] # central interaction
nstr0 = i0[0]
nstr1 = i1[0]
# list of authorized outputs. Initialized void
output = []
# nstr1 : segment number of central interaction
if nstr1 > 0:
# central interaction is a segment
# pseg1 = self.s2pc[nstr1,:].toarray().reshape(2, 2).T
pseg1 = self.s2pc[nstr1,:].toarray().reshape(2, 2).T
# pseg1 = self.s2pc[nstr1,:].data.reshape(2, 2).T
# pseg1o = self.seg2pts(nstr1).reshape(2, 2).T
# create a Cone object
cn = cone.Cone()
# if starting from segment
if nstr0 > 0:
# pseg0 = self.s2pc[nstr0,:].toarray().reshape(2, 2).T
pseg0 = self.s2pc[nstr0,:].toarray().reshape(2, 2).T
# pseg0 = self.s2pc[nstr0,:].data.reshape(2, 2).T
# pseg0o = self.seg2pts(nstr0).reshape(2, 2).T
# if nstr0 and nstr1 are connected segments
if self.sgsg[nstr0,nstr1] == 0:
# from 2 not connected segment
cn.from2segs(pseg0, pseg1)
else:
# from 2 connected segments
cn.from2csegs(pseg0, pseg1)
# if starting from a point
else:
pt = Gspos(nstr0)[0,:]
# pt = np.array(self.Gs.pos[nstr0])
cn.fromptseg(pt, pseg1)
# list all potential successors of interaction i1
ui2 = self.Gi_no.index(i1)
ui = np.where(self.Gi_A[ui2,:].toarray()!=0)[1]
i2 = [self.Gi_no[u] for u in ui]
# i2 = nx.neighbors(self.Gi, i1)
# how to find neighbors without network
# ngi=L.Gi.nodes()
# A=nx.adjacency_matrix(L.Gi)
# inter = ngi[10]
# u = ngi.index(inter)
# ui = A[u,:].indices
# neigh_inter = np.array([ngi[u] for u in ui])
ipoints = [x for x in i2 if len(x)==1 ]
#ipoints = filter(lambda x: len(x) == 1, i2)
# pipoints = np.array([self.Gs.pos[ip[0]] for ip in ipoints]).T
pipoints = np.array([Gspos(ip[0]) for ip in ipoints]).T
# filter tuple (R | T)
#istup = filter(lambda x : type(eval(x))==tuple,i2)
# map first argument segment number
#isegments = np.unique(map(lambda x : eval(x)[0],istup))
# isegments = np.unique(
# filter(lambda y: y > 0, map(lambda x: x[0], i2)))
isegments = np.unique([x[0] for x in i2 if x[0]>0])
# if nstr0 and nstr1 are adjescent segment remove nstr0 from
# potential next interaction
# Fix 01/2017
# This is not always True if the angle between
# the two adjascent segments is < pi/2
# nb_nstr0 = self.Gs.neighbors(nstr0)
# nb_nstr1 = self.Gs.neighbors(nstr1)
# nb_nstr0 = np.array([self.s2pu[nstr0,0],self.s2pu[nstr0,1]])
# nb_nstr1 = np.array([self.s2pu[nstr1,0],self.s2pu[nstr1,1]])
# nb_nstr0 = self.s2pu[nstr0,:].toarray()[0]
# nb_nstr1 = self.s2pu[nstr1,:].toarray()[0]
# first interaction is a point
if nstr0<0:
nb_nstr0 = [nstr0]
else:
nb_nstr0 = self.s2pu[nstr0,:].toarray()[0,:]
nb_nstr1 = self.s2pu[nstr1,:].toarray()[0,:]
# common_point = np.intersect1d(nb_nstr0,nb_nstr1)
common_point = np.array([x for x in nb_nstr0 if x in nb_nstr1])
#print(common_point)
# if len(common_point) == 1:
# pdb.set_trace()
if common_point.any():
num0 = [x for x in nb_nstr0 if x != common_point]
num1 = [x for x in nb_nstr1 if x != common_point]
p0 = Gspos(num0[0])[0,:]
p1 = Gspos(num1[0])[0,:]
pc = Gspos(common_point[0])[0,:]
v0 = p0 - pc
v1 = p1 - pc
v0n = v0/np.sqrt(np.sum(v0*v0))
v1n = v1/np.sqrt(np.sum(v1*v1))
if np.dot(v0n,v1n)<=0:
isegments = np.array([ x for x in isegments if x != nstr0 ])
# [ x for x in rle if x != nstr0, isegments))
# there are one or more segments
# if len(isegments) > 0:
if isegments.any():
li1 = len(i1)
# points = self.s2pc[isegments,:].toarray().T
points = self.s2pc[isegments,:].toarray().T
# points = self.s2pc[isegments,:].data.reshape(4,len(isegments))
# pointso = self.seg2pts(isegments)
pta = points[0:2, :]
phe = points[2:, :]
# add difraction points
# WARNING Diffraction points are added only if a segment is seen
# it should be the case in 99% of cases
if len(ipoints) > 0:
isegments = np.hstack(
(isegments, np.array(ipoints)[:, 0]))
pta = np.hstack((pta, pipoints))
phe = np.hstack((phe, pipoints))
# cn.show()
# if i0 == (38,79) and i1 == (135,79,23):
# printi0,i1
# import ipdb
# ipdb.set_trace()
# i1 : interaction T
if li1 == 3:
typ, prob = cn.belong_seg(pta, phe, prob=False)
# if bs.any():
# plu.displot(pta[:,bs],phe[:,bs],color='g')
# if ~bs.any():
# plu.displot(pta[:,~bs],phe[:,~bs],color='k')
# i1 : interaction R --> mirror
elif li1 == 2:
Mpta = geu.mirror(pta, pseg1[:, 0], pseg1[:, 1])
Mphe = geu.mirror(phe, pseg1[:, 0], pseg1[:, 1])
#typ, prob = cn.belong_seg_old(Mpta, Mphe, prob=False)
typ = cn.belong_seg(Mpta, Mphe)
# printi0,i1
# if ((i0 == (6, 0)) & (i1 == (7, 0))):
# pdb.set_trace()
# if bs.any():
# plu.displot(pta[:,bs],phe[:,bs],color='g')
# if ~bs.any():
# plu.displot(pta[:,~bs],phe[:,~bs],color='m')
# plt.show()
# pdb.set_trace())
########
# SOMETIMES PROBA IS 0 WHEREAS SEG IS SEEN
###########
# # keep segment with prob above a threshold
# isegkeep = isegments[prob>0]
# # dict {numint : proba}
# dsegprob = {k:v for k,v in zip(isegkeep,prob[prob>0])}
# 4 lines are replaced by
# keep segment with prob above a threshold
utypseg = typ != 0
isegkeep = isegments[utypseg]
# dict {numint : proba}
dsegprob = {k: v for k, v in zip(isegkeep, prob[utypseg])}
#########
# output = [ x for x in rle if x[0] in isegkeep, i2)
output = [x for x in i2 if x[0] in isegkeep]
# probint = map(lambda x: dsegprob[x[0]], output)
probint = [dsegprob[x[0]] for x in output]
# dict interaction : proba
dintprob = {k: v for k, v in zip(output, probint)}
# keep all segment above nstr1 and in Cone if T
# keep all segment below nstr1 and in Cone if R
else:
# central interaction is a point
# 1) Simple approach
# output interaction are all visible interactions
# 2) TO BE DONE
#
# output of the diffraction points
# exploring
# b
# + right of ISB
# + right of RSB
#
# + using the wedge cone
# + using the incident cone
#
# output = nx.neighbors(self.Gi, (nstr1,))
uout = self.Gi_no.index((nstr1,))
ui = np.where(self.Gi_A[uout,:].toarray()!=0)[1]
output = [self.Gi_no[u] for u in ui]
nout = len(output)
probint = np.ones(nout) # temporarybns
dintprob = {k: v for k, v in zip(output,probint)}
try:
self.Gi.add_edge(i0, i1, output=dintprob)
except:
pass
[docs] def outputGi_mp(self):
""" filter output of Gi edges
Parameters
----------
L : Layout
Notes
-----
Let assume a sequence (nstr0,nstr1,{nstr2A,nstr2B,...}) in a signature.
This function checks whether this sequence is feasible or not
, whatever the type of nstr0 and nstr1.
The feasible outputs from nstr0 to nstr1 are stored in an output field of
edge (nstr0,nstr1)
See Also
--------
pylayers.util.cone.Cone.from2seg
pylayers.util.cone.Cone.belong_seg
"""
# assert('Gi' in self.__dict__)
# oGipbar=pbar(verbose,total=100.,leave=False,desc='OutputGi',position=tqdmpos)
# # loop over all edges of Gi
# Nedges = len(self.Gi.edges())
# cpt = 100./Nedges
# print "Gi Nedges :",Nedges
e = self.Gi.edges()
#Gi_no = [self.Gi_no]*len(e)
# densify sparse matrix
#aGi_A = self.Gi_A.toarray()
#ap2pc = self.p2pc.toarray()
#asgsg = self.sgsg.toarray()
#as2pc = self.s2pc.toarray()
#as2pu = self.s2pu.toarray()
global Gi_A
global Gi_no
global p2pc
global sgsg
global s2pc
global s2pu
Gi_A = self.Gi_A
Gi_no = self.Gi_no
p2pc = self.p2pc
sgsg = self.sgsg
s2pc = self.s2pc
s2pu = self.s2pu
#Gi_A = [aGi_A]*len(e)
#p2pc = [ap2pc]*len(e)
#s2pc = [as2pc]*len(e)
#s2pu = [as2pu]*len(e)
#sgsg = [asgsg]*len(e)
pool = Pool(cpu_count())
# multiprocessing style
#Z=zip(e, Gi_no, Gi_A, p2pc, sgsg, s2pc, s2pu)
#res = pool.map(outputGi_func,Z)
Z = zip(e)
res = pool.map(outputGi_func,Z)
self.Gi.add_edges_from(res)
# res = pool.map(outputGi_func_test,e)
# print('e')
# time.sleep(1)
# res = pool.map(outputGi_func_test,Gi_no)
# print('no')
# time.sleep(1)
# res = pool.map(outputGi_func_test,Gi_A)
# print('A')
# time.sleep(1)
# res = pool.map(outputGi_func_test,Gspos)
# print('pos')
# time.sleep(1)
# res = pool.map(outputGi_func_test,sgsg)
# print('sgsg')
# time.sleep(1)
# res = pool.map(outputGi_func_test,s2pc)
# print('s2pc')
# time.sleep(1)
# res = pool.map(outputGi_func_test,s2pu)
# print('s2pu')
# time.sleep(1)
# res = pool.map(outputGi_func_test,Z)
# print('Z')
#def outputGi_func(arg):
# if (k%100)==0:
# print"edge : ",k
# extract both termination interactions nodes
#for k in arg:
# Z=arg*arg
# e=arg[0]
# s2pc=arg[1]
# Gs=arg[2]
# Gi=arg[3]
# i0 = e[0]
# i1 = e[1]
# nstr0 = i0[0]
# nstr1 = i1[0]
# print(i0,i1)
# for k in range(1000):
# y=k*k
# # list of authorized outputs. Initialized void
# output = []
# # nstr1 : segment number of central interaction
# if nstr1 > 0:
# # central interaction is a segment
# pseg1 = np.array(s2pc[nstr1,:].todense()).reshape(2, 2).T
# # create a Cone object
# cn = cone.Cone()
# # if starting from segment
# if nstr0 > 0:
# pseg0 = np.array(s2pc[nstr0,:].todense()).reshape(2, 2).T
# # if nstr0 and nstr1 are connected segments
# if (len(np.intersect1d(nx.neighbors(Gs, nstr0), nx.neighbors(Gs, nstr1))) == 0):
# # from 2 not connected segment
# cn.from2segs(pseg0, pseg1)
# else:
# # from 2 connected segments
# cn.from2csegs(pseg0, pseg1)
# # if starting from a point
# else:
# pt = np.array(Gs.pos[nstr0])
# cn.fromptseg(pt, pseg1)
# # list all potential successors of interaction i1
# i2 = nx.neighbors(Gi, i1)
# ipoints = [x for x in i2 if len(x)==1 ]
# #ipoints = [ x for x in rle if len(x) == 1, i2)
# pipoints = np.array([Gs.pos[ip[0]] for ip in ipoints]).T
# # filter tuple (R | T)
# #istup = filter(lambda x : type(eval(x))==tuple,i2)
# # map first argument segment number
# #isegments = np.unique(map(lambda x : eval(x)[0],istup))
# isegments = np.unique(
# filter(lambda y: y > 0, map(lambda x: x[0], i2)))
# # if nstr0 and nstr1 are adjescent segment remove nstr0 from
# # potential next interaction
# # Fix 01/2017
# # This is not always True if the angle between
# # the two adjascent segments is < pi/2
# nb_nstr0 = Gs.neighbors(nstr0)
# nb_nstr1 = Gs.neighbors(nstr1)
# common_point = np.intersect1d(nb_nstr0,nb_nstr1)
# if len(common_point) == 1:
# num0 = [x for x in nb_nstr0 if x != common_point]
# num1 = [x for x in nb_nstr1 if x != common_point]
# p0 = np.array(Gs.pos[num0[0]])
# p1 = np.array(Gs.pos[num1[0]])
# pc = np.array(Gs.pos[common_point[0]])
# v0 = p0-pc
# v1 = p1-pc
# v0n = v0/np.sqrt(np.sum(v0*v0))
# v1n = v1/np.sqrt(np.sum(v1*v1))
# if np.dot(v0n,v1n)<=0:
# isegments = np.array([ x for x in isegments if x != nstr0 ])
# # [ x for x in rle if x != nstr0, isegments))
# # there are one or more segments
# if len(isegments) > 0:
# points = np.array(s2pc[isegments,:].todense()).T
# pta = points[0:2, :]
# phe = points[2:, :]
# # add difraction points
# # WARNING Diffraction points are added only if a segment is seen
# # it should be the case in 99% of cases
# if len(ipoints) > 0:
# isegments = np.hstack(
# (isegments, np.array(ipoints)[:, 0]))
# pta = np.hstack((pta, pipoints))
# phe = np.hstack((phe, pipoints))
# # cn.show()
# # if i0 == (38,79) and i1 == (135,79,23):
# # printi0,i1
# # import ipdb
# # ipdb.set_trace()
# # i1 : interaction T
# if len(i1) == 3:
# typ, prob = cn.belong_seg(pta, phe)
# # if bs.any():
# # plu.displot(pta[:,bs],phe[:,bs],color='g')
# # if ~bs.any():
# # plu.displot(pta[:,~bs],phe[:,~bs],color='k')
# # i1 : interaction R --> mirror
# if len(i1) == 2:
# Mpta = geu.mirror(pta, pseg1[:, 0], pseg1[:, 1])
# Mphe = geu.mirror(phe, pseg1[:, 0], pseg1[:, 1])
# typ, prob = cn.belong_seg(Mpta, Mphe)
# # printi0,i1
# # if ((i0 == (6, 0)) & (i1 == (7, 0))):
# # pdb.set_trace()
# # if bs.any():
# # plu.displot(pta[:,bs],phe[:,bs],color='g')
# # if ~bs.any():
# # plu.displot(pta[:,~bs],phe[:,~bs],color='m')
# # plt.show()
# # pdb.set_trace())
# ########
# # SOMETIMES PROBA IS 0 WHEREAS SEG IS SEEN
# ###########
# # # keep segment with prob above a threshold
# # isegkeep = isegments[prob>0]
# # # dict {numint : proba}
# # dsegprob = {k:v for k,v in zip(isegkeep,prob[prob>0])}
# # 4 lines are replaced by
# # keep segment with prob above a threshold
# utypseg = typ != 0
# isegkeep = isegments[utypseg]
# # dict {numint : proba}
# dsegprob = {k: v for k, v in zip(isegkeep, prob[utypseg])}
# #########
# # output = [ x for x in rle if x[0] in isegkeep, i2)
# output = [x for x in i2 if x[0] in isegkeep]
# # probint = map(lambda x: dsegprob[x[0]], output)
# probint = [dsegprob[x[0]] for x in output]
# # dict interaction : proba
# dintprob = {k: v for k, v in zip(output, probint)}
# # keep all segment above nstr1 and in Cone if T
# # keep all segment below nstr1 and in Cone if R
# else:
# # central interaction is a point
# # 1) Simple approach
# # output interaction are all visible interactions
# # 2) TO BE DONE
# #
# # output of the diffraction points
# # exploring
# # b
# # + right of ISB
# # + right of RSB
# #
# # + using the wedge cone
# # + using the incident cone
# #
# output = nx.neighbors(Gi, (nstr1,))
# nout = len(output)
# probint = np.ones(nout) # temporarybns
# dintprob = {k: v for k, v in zip(output, probint)}
# return(i0,i1,dintprob)
#self.Gi.add_edge(i0, i1, output=dintprob)
[docs] def intercy(self, ncy, typ='source'):
""" return the list of interactions seen from a cycle
Parameters
----------
ncy : cycle number( Project -> save project)
typ : string
if 'source' connect source cycle
if 'target' connect target cycle
Notes
-----
This method is called at the beginning of signature evaluation in order
to get the starting and ending interaction. It exploits the information
contained in teh graph Gi.
"""
# list of interactions
lint = self.Gi.node
# list of tuple interactions (R|T)
lD = [x for x in lint if len(x)==1]
lR = [x for x in lint if len(x)==2]
lT = [x for x in lint if len(x)==3]
# lD = [ x for x in rle if len(x) == 1, lint)
# lR = [ x for x in rle if len(x) == 2, lint)
# lT = [ x for x in rle if len(x) == 3, lint)
# visible R|T source cycle is ncy
lR = [ x for x in lR if x[1] == ncy ]
if typ == 'source':
lT = [ x for x in lT if x[1] == ncy ]
if typ == 'target':
lT = [ x for x in lT if x[2] == ncy ]
if typ == 'all':
lT = lT
# Finding the diffraction points
# Diffraction points are different from indoor cycle and outdoor
# cycles
#
# TODO check wedge validity.
#
vnodes = self.Gt.node[ncy]['polyg'].vnodes
vpoints = [ x for x in vnodes if x < 0 ]
lD = []
for x in vpoints:
if x in self.ddiff:
for y in self.ddiff[x][0]:
if y == ncy:
lD.append((x,))
# indoor = self.Gt.node[ncy]['indoor']
# if indoor:
# lD = map(lambda y : (y,),filter(lambda x : x in
# self.ldiffin,vpoints))
# else:
# lD = map(lambda y : (y,),filter(lambda x : x in
# self.ldiffout,vpoints))
return lR, lT, lD
[docs] def show(self, **kwargs):
""" show layout
See also
--------
showG
"""
defaults = {'show': True,
'fig': [],
'ax': [],
'nodes': False,
'edges': True,
'labels': False,
'alphan': 1.0,
'alphae': 1.0,
'width': 2,
'node_color': 'w',
'edge_color': 'k',
'node_size': 200,
'font_size': 30,
'nodelist': [],
'figsize': (5, 5),
'mode': 'cycle',
}
for key, value in defaults.items():
if key not in kwargs:
kwargs[key] = value
lair = []
if 'AIR' in self.name:
lair = self.name['AIR']
if '_AIR' in self.name:
lair = lair + self.name['_AIR']
#
# tsg : list of segment index for mapping with self.tahe
segfilt = [ x for x in self.tsg if x not in lair ]
# get the association between segment and nx edges
edges = self.Gs.edges()
Ne = len(edges)
# segments = np.array(edges)[:,0]
# segments are >0 index so max in necesssarily
# a segment number whatever the order
segments = np.array([max(x) for x in edges])
dse = {k: v for k, v in zip(segments, range(Ne))}
edfilt = list(
np.ravel(np.array(map(lambda x: [dse[x] - 1, dse[x]], segfilt))))
# edgelist is to be understood as edges of Graph and not segments of
# Layout
if hasattr(self,'extent'):
fig, ax = gkml.gearth_fig(self.extent,self.extent_c)
else:
fig = plt.gca()
ax = plt.gca()
fig, ax = self.showG('s', nodes=False, edgelist=edfilt,fig=fig,ax=ax)
# display degree 1 nodes
if 1 in self.degree:
ldeg1 = list(self.degree[1])
print(ldeg1)
fig, ax = self.showG('s',
fig=fig,
ax=ax,
nodelist=ldeg1,
edges=kwargs['edges'],
nodes=kwargs['nodes'],
node_size=kwargs['node_size'],
node_color='r')
# display degree 4 nodes
if 4 in self.degree:
ldeg4 = list(self.degree[4])
fig, ax = self.showG('s',
fig=fig,
ax=ax,
nodelist=ldeg4,
edges=kwargs['edges'],
nodes=kwargs['nodes'],
node_size=kwargs['node_size'],
node_color='g')
if hasattr(self,'extent'):
pnglayout = 'kmllayout.png'
kmzlayout = 'kmzlayout.kmz'
fig.savefig(pnglayout,transparent=True,format='png')
gkml.make_kml(self.extent,
figs = [pnglayout],
kmzfile = kmzlayout,
name = 'Layout')
# if k==1:
# fig,ax = self.showG('s',fig=fig,ax=ax,nodelist=ldeg,edges=False,nodes=True,node_size=50,node_color='c')
# if k==4:
# fig,ax = self.showG('s',fig=fig,ax=ax,nodelist=ldeg,nodes=False,node_size=50,node_color='b')
def show_poly(self,**kwargs):
""" show polygons
Parameters
----------
bmap : boolean (display smpoy map)
Returns
-------
fig,ax,args,
"""
import smopy
bmap = kwargs.pop('bmap',True)
figsize = kwargs.pop('figsize',(15,15))
lm = self.extent[0]
lM = self.extent[1]
Lm = self.extent[2]
LM = self.extent[3]
zoom = 15
self.map = smopy.Map((Lm,lm,LM,lM), z=zoom)
bcond = bmap and hasattr(self,'map')
ax = self.map.show_mpl(figsize=figsize)
#ax = kwargs.pop('ax',plt.gca())
BLUE='#6699cc'
verts = []
lbdg_height = []
if hasattr(self.dpoly,'_xy'):
for kpoly in self.dpoly:
verts.append(self.dpoly[kpoly]._xy.T)
else:
for kpoly in self.dpoly:
connect = self.dpoly[kpoly]['connect']
z = self.dpoly[kpoly]['z']
building_height = z[1] - z[0]
lbdg_height.append(building_height)
lpol = []
lprev = 0
#
# Take care of the order of the sequence of points
#
for seg in connect:
ta = self.Gs.node[seg]['connect'][0]
he = self.Gs.node[seg]['connect'][1]
if ((he==lprev) or (lprev==0)):
lpol.append((self.Gs.pos[ta][0],self.Gs.pos[ta][1]))
lprev = ta
else:
lpol.append((self.Gs.pos[he][0],self.Gs.pos[he][1]))
lprev = he
llL = [ self.m(x[0],x[1],inverse=True) for x in lpol ]
lpol2 = [ self.map.to_pixels(lL[1],lL[0]) for lL in llL]
verts.append(lpol2)
hmax = np.max(lbdg_height)
hmin = np.min(lbdg_height)
arg = 255*(np.array(lbdg_height)-hmin)/(hmax-hmin)
facecolors = cm.jet(arg.astype(int))
coll = PolyCollection(verts, edgecolors='k', facecolors=facecolors)
ax.add_collection(coll)
plt.axis('on')
#ax.autoscale_view()
#ax.axis('equal')
fig = plt.gcf()
return fig,ax,arg,facecolors
[docs] def showG(self, graph='s', **kwargs):
""" show the different graphs
Parameters
----------
graph : char
't' : Gt 'r' : Gr 's' : Gs 'v' : Gv 'i' : Gi
fig : matplotlib figure
[]
ax : matplotlib figure
[]
show : boolean
False
nodes : boolean
alse
edges : boolean
True
airwalls | aw: boolean
display airwalls (False)
subseg: boolean
display subsegments (False)
slab : boolean
display color and width of slabs (False)
labels : boolean |list
display graph labels (False)
if list precise label of which cycle to display
(e.g. ['t'])
alphan : float
transparency of nodes (1.0)
alphae : float
transparency of edges (1.0)
width : float
line width (2)
node_color: string
w
posnode_color: string
positive node color (k)
negnode_color: string
negative node color (b)
edge_color : string
k
node_size : float
20
font_size : float
15,
nodelist : list
list of nodes to be displayed (all)
edgelist : list
list of edges to be displayed (all)
mode : string
'cycle' | 'none' | 'room'
alphacy : string
transparency of cycles (0.8)
colorcy :
'#abcdef'
linter : list
list of interaction for Gi
['RR','TT','RT','TR','RD','DR','TD','DT','DD']
show0 : boolean
If true display connection to cycle 0 of Gt (False)
eded : boolean
True
ndnd : boolean
True
nded : boolean
True
width : int
2
nodelist : list
[]
overlay : boolean
diffraction :boolean
False
defaults = {'show': False,
'fig': [],
'ax': [],
'nodes': False,
'edges': True,
'sllist':[],
'airwalls': False,
'subseg': False,
'slab': True,
'labels': False,
'alphan': 1.0,
'alphae': 1.0,
'width': 2,
'node_color':'w',
'edge_color':'k',
'node_size':20,
'font_size':15,
'nodelist': [],
'edgelist': [],
'figsize': (5,5),
'mode':'nocycle',
'alphacy':0.8,
'colorcy':'abcdef',
'linter' : ['RR','TT','RT','TR','RD','DR','TD','DT','DD'],
'show0':False,
'axis':False,
'overlay':False,
'diffraction':False
}
Examples
--------
.. plot::
:include-source:
>>> from pylayers.gis.layout import *
>>> import matplotlib.pyplot as plt
>>> L = Layout('TA-Office.lay')
>>> L.dumpr()
>>> fig = plt.figure(figsize=(10,10))
>>> ax = fig.add_subplot(221)
>>> fig,ax = L.showG('s',fig=fig,ax=ax)
>>> tis = plt.title("Gs")
>>> ax = fig.add_subplot(222)
>>> fig,ax = L.showG('t',fig=fig,ax=ax)
>>> tit = plt.title("Gt")
>>> ax = fig.add_subplot(223)
>>> fig,ax = L.showG('r',fig=fig,ax=ax)
>>> tic = plt.title("Gr")
>>> ax = fig.add_subplot(224)
>>> fig,ax = L.showG('v',fig=fig,ax=ax)
>>> tiv = plt.title("Gv")
>>> plt.show()
See Also
--------
pylayers.util.graphutil.draw
"""
defaults = {'show': False,
'fig': [],
'ax': [],
'nodes': [],
'edges': True,
'sllist': [],
'airwalls': False,
'aw': [],
'subseg': False,
'slab': True,
'labels': False,
'alphan': 1.0,
'alphae': 1.0,
'width': 2,
'node_color': 'w',
'edge_color': '',
'node_size': 20,
'font_size': 15,
'nodelist': [],
'edgelist': [],
'figsize': (8, 8),
'mode': 'nocycle',
'alphacy': 0.8,
'colorcy': '#abcdef',
'lvis': ['nn', 'ne', 'ee'],
'linter': ['RR', 'TT', 'RT', 'TR', 'RD', 'DR', 'TD', 'DT', 'DD'],
'show0': False,
'axis': True,
'overlay': False,
'diffraction': False
}
for key, value in defaults.items():
if key not in kwargs:
kwargs[key] = value
if kwargs['aw'] != []:
kwargs['airwalls'] = kwargs['aw']
if 'graph' in kwargs:
graph = kwargs['graph']
# get color dictionnary from pyutil
cold = pyu.coldict()
if isinstance(kwargs['labels'], list):
labels = kwargs['labels']
elif kwargs['labels'] == True:
labels = ['s', 't', 'v', 'i', 'w']
elif isinstance(kwargs['labels'], str):
labels = kwargs['labels']
else:
labels = []
if isinstance(kwargs['nodes'], list):
dis_nodes = kwargs['nodes']
elif kwargs['nodes'] == True:
dis_nodes = ['s', 't', 'v', 'i', 'w']
elif isinstance(kwargs['nodes'], str):
dis_nodes = kwargs['nodes']
else:
dis_nodes = []
#
# s : structure graph
#
if 's' in graph:
# not efficient
G = self.Gs
# lss = [ x for x in self.Gs.nodes if # self.Gs.node[x].has_key('ss_name')]
# lss = [ x for x in lss if len(self.Gs.node[x]['ss_name'])>0 ]
# keep track of segments already printed
nodelistbkup = kwargs['nodelist']
edgelistbkup = kwargs['edgelist']
widthbkup = kwargs['width']
nodecolbkup = kwargs['edge_color']
try:
sllist = [kwargs['sllist'].pop()]
except:
sllist = list(dict(self.name).keys())
#
# Draw segment slab per slab with proper linewidth and color
#
for lmat in sllist:
#print(lmat)
lseg = self.name[lmat]
if lseg != []:
lseg2 = [np.where(np.array(self.Gs.edges()) == i)[0] for i in lseg]
kwargs['edgelist'] = []
for y in lseg2:
kwargs['edgelist'] = kwargs['edgelist'] + list(y)
#kwargs['edgelist'] = list(reduce(lambda x, y: list(x) + list(y), lseg2))
if kwargs['slab']:
if self.sl[lmat]['color'][0]=="#":
kwargs['edge_color'] = self.sl[lmat]['color']
else:
kwargs['edge_color'] = cold[self.sl[lmat]['color']]
kwargs['width'] = self.sl[lmat]['linewidth']
else:
kwargs['edge_color'] = 'k'
kwargs['width'] = 1
if 's' in labels:
kwargs['labels'] = True
else:
kwargs['labels'] = False
if 's' in dis_nodes:
kwargs['nodes'] = True
else:
kwargs['nodes'] = False
kwargs['fig'], kwargs['ax'] = gru.draw(G, **kwargs)
kwargs['nodelist'] = nodelistbkup
kwargs['width'] = widthbkup
kwargs['edge_color'] = nodecolbkup
kwargs['edgelist'] = edgelistbkup
if kwargs['subseg']:
#
# Display doors and windows subsegments with a slight offset
#
cold = pyu.coldict()
d = self.subseg()
for ss in list(dict(d).keys()):
color = cold[self.sl[ss]['color']]
for ns in d[ss]:
norm = self.Gs.node[ns[0]]['norm']
# v1.1 np1, np2 = self.Gs.neighbors(ns[0])
np1, np2 = self.Gs[ns[0]]
x = np.array(
[self.Gs.pos[np1][0], self.Gs.pos[np2][0]])
y = np.array(
[self.Gs.pos[np1][1], self.Gs.pos[np2][1]])
xoff = (1 + ns[1]) * 0.05 * norm[0]
yoff = (1 + ns[1]) * 0.05 * norm[1]
kwargs['ax'].plot(x + xoff, y + yoff,
linewidth=2, color=color)
#
# t : graph of cycles
#
if 't' in graph:
G = self.Gt
if not kwargs['show0']:
# filter out the 0 cycle
nodes = list(G.nodes())
edges = list(G.edges())
nodf = [ x for x in nodes if x != 0 ]
edf = [ x for x in np.arange(len(edges)) if ((edges[x][0]!=0) &
(edges[x][1]!=0))
]
kwargs['nodelist'] = nodf
kwargs['edgelist'] = edf
else:
kwargs['nodelist'] = G.nodes()
kwargs['edgelist'] = np.arange(len(G.edges()))
if kwargs['edge_color'] == '':
kwargs['edge_color'] = 'r'
if 't' in labels:
kwargs['labels'] = True
else:
kwargs['labels'] = False
if 't' in dis_nodes:
kwargs['nodes'] = True
else:
kwargs['nodes'] = False
fig, ax = gru.draw(G, **kwargs)
kwargs['fig'] = fig
kwargs['ax'] = ax
#
# r : graph of rooms
#
if 'r' in graph:
G = self.Gr
if kwargs['edge_color'] == '':
kwargs['edge_color'] = 'g'
kwargs['fig'], kwargs['ax'] = gru.draw(self.Gs,
nodes=False, edges=True, alphacy=1.,
fig=kwargs['fig'], ax=kwargs['ax'], labels=False)
if 'r' in labels:
kwargs['labels'] = True
else:
kwargs['labels'] = False
if 'r' in dis_nodes:
kwargs['nodes'] = True
else:
kwargs['nodes'] = False
fig, ax = gru.draw(G, **kwargs)
kwargs['fig'] = fig
kwargs['ax'] = ax
#
# v : visibility graph
# In blue : segment segment
# In red : point point (Diffraction)
# In green : point segment
#
if 'v' in graph:
G = self.Gv
G.pos = {}
# nodes of Gv are nodes of Gs
G.pos.update(self.Gs.pos)
if kwargs['edge_color'] == '':
kwargs['edge_color'] = 'm'
edges = list(G.edges())
rle = range(len(edges))
eded = [ x for x in rle if (edges[x][0] > 0) & (edges[x][1] > 0)]
ndnd = [ x for x in rle if (edges[x][0] < 0) & (edges[x][1] < 0)]
nded = [ x for x in rle if (((edges[x][0] < 0) & (edges[x][1] > 0)) |
((edges[x][0] > 0) & (edges[x][1] < 0)))]
if 'v' in labels:
kwargs['labels'] = True
else:
kwargs['labels'] = False
if 'v' in dis_nodes:
kwargs['nodes'] = True
else:
kwargs['nodes'] = False
if 'ee' in kwargs['lvis']:
kwargs['edgelist'] = eded
kwargs['edge_color'] = 'blue'
kwargs['node_size'] = 200
kwargs['fig'], kwargs['ax'] = gru.draw(G, **kwargs)
if 'nn' in kwargs['lvis']:
kwargs['edgelist'] = ndnd
kwargs['edge_color'] = 'red'
kwargs['fig'], kwargs['ax'] = gru.draw(G, **kwargs)
if 'ne' in kwargs['lvis']:
kwargs['edgelist'] = nded
kwargs['edge_color'] = 'green'
kwargs['fig'], kwargs['ax'] = gru.draw(G, **kwargs)
#
# i : interaction graph
#
if 'i' in graph:
G = self.Gi
if kwargs['edge_color'] == '':
kwargs['edge_color'] = 'k'
#
# Parsing the type of interactions
#
edges = list(G.edges())
# range len edges
rle = range(len(edges))
DD = [ x for x in rle if ((len(edges[x][0]) == 1) &
(len(edges[x][1]) == 1))]
RR = [ x for x in rle if ((len(edges[x][0]) == 2) &
(len(edges[x][1]) == 2))]
TT = [ x for x in rle if ((len(edges[x][0]) == 3) &
(len(edges[x][1]) == 3))]
RT = [ x for x in rle if ((len(edges[x][0]) == 2) &
(len(edges[x][1]) == 3))]
TR = [ x for x in rle if ((len(edges[x][0]) == 3) &
(len(edges[x][1]) == 2))]
RD = [ x for x in rle if ((len(edges[x][0]) == 2) &
(len(edges[x][1]) == 1))]
TD = [ x for x in rle if ((len(edges[x][0]) == 3) &
(len(edges[x][1]) == 1))]
DR = [ x for x in rle if ((len(edges[x][0]) == 1) &
(len(edges[x][1]) == 2))]
DT = [ x for x in rle if ((len(edges[x][0]) == 1) &
(len(edges[x][1]) == 3))]
tabcol = ['b', 'g', 'r', 'm', 'c', 'orange',
'purple', 'maroon', 'purple', 'k'][::-1]
li = []
if 'i' in labels:
kwargs['labels'] = True
else:
kwargs['labels'] = False
if 'v' in dis_nodes:
kwargs['nodes'] = True
else:
kwargs['nodes'] = False
for inter in kwargs['linter']:
if len(eval(inter)) > 0:
li.append(inter)
kwargs['edgelist'] = eval(inter)
# ndlist = map(lambda x: edges[x][0],kwargs['edgelist'])+\
# map(lambda x: edges[x][1],kwargs['edgelist'])
#ndlist = map(lambda x: edges[x][0], kwargs['edgelist']) +\
# map(lambda x: edges[x][1], kwargs['edgelist'])
ndlist = [ edges[x][0] for x in kwargs['edgelist']] + [edges[x][1] for x in kwargs['edgelist']]
# keep only unique interaction
unique = []
[unique.append(it) for it in ndlist if it not in unique]
kwargs['nodelist'] = unique
kwargs['edge_color'] = tabcol.pop()
kwargs['fig'], kwargs['ax'] = gru.draw(G, **kwargs)
legtxt = ['Gs'] + li
# plt.legend(legtxt)
#
# w : waypoint graph
#
if 'w' in graph:
G = self.Gw
if kwargs['edge_color'] == '':
kwargs['edge_color'] = 'k'
kwargs['fig'], kwargs['ax'] = gru.draw(self.Gs,
nodes=False, edges=True, alphacy=1.,
fig=kwargs['fig'], ax=kwargs['ax'], labels=False)
if 'w' in labels:
kwargs['labels'] = True
else:
kwargs['labels'] = False
fig, ax = gru.draw(G, **kwargs)
kwargs['fig'] = fig
kwargs['ax'] = ax
args = {'fig': kwargs['fig'], 'ax': kwargs['ax'], 'show': False}
if len(kwargs['edgelist']) == 0:
if kwargs['mode'] == 'cycle':
for k, ncy in enumerate(list(dict(self.Gt.node).keys())):
if k != 0:
fig, ax = self.Gt.node[ncy]['polyg'].plot(
alpha=kwargs['alphacy'], color=kwargs['colorcy'], **args)
args['fig'] = fig
args['ax'] = ax
if kwargs['mode'] == 'room':
for k, nro in enumerate(list(dict(self.Gr.node.keys()))):
if k != 0:
fig, ax = self.Gr.node[nro]['cycle'].show(**args)
args['fig'] = fig
args['ax'] = ax
kwargs['ax'].axis('scaled')
if not kwargs['axis']:
kwargs['ax'].axis('off')
if kwargs['overlay']:
imok = False
if self.display['overlay_file'] != '':
image = Image.open(os.path.join(
basename, pro.pstruc['DIRIMAGE'], self.display['overlay_file']))
imok = True
if imok:
if 'v' in self.display['overlay_flip']:
print("flip v")
image = image.transpose(Image.FLIP_LEFT_RIGHT)
if 'h' in self.display['overlay_flip']:
image = image.transpose(Image.FLIP_TOP_BOTTOM)
print("flip h")
plt.axis()
kwargs['ax'].imshow(np.array(image), extent=self.display[
'overlay_axis'], alpha=self.display['alpha'], origin='lower')
if kwargs['diffraction']:
if len(self.ddiff.keys())>0:
pt = np.array([self.Gs.pos[x] for x in self.ddiff.keys()])
pta = np.array([self.Gs.pos[x] for x in self.lnss])
kwargs['ax'].scatter(pt[:, 0], pt[:, 1], c='r', s=75)
if len(self.lnss) > 0:
kwargs['ax'].scatter(pta[:, 0], pta[:, 1], c='b', s=20)
if kwargs['show']:
plt.show()
return kwargs['fig'], kwargs['ax']
def _showGv(self, **kwargs):
""" show graph Gv (visibility)
Parameters
----------
display
fig
ax
nodes : boolean
display nodes
edges : boolean
display edges
Returns
-------
fig : figure instance
ax : axes instance
"""
defaults = {'show': False,
'ax': [],
'nodes': False,
'eded': True,
'ndnd': True,
'nded': True,
'linewidth': 2,
}
for key, value in defaults.items():
if key in kwargs:
setattr(self, key, kwargs[key])
else:
setattr(self, key, value)
kwargs[key] = value
if kwargs['ax'] == []:
fig = plt.figure()
ax = fig.gca()
else:
ax = kwargs['ax']
nodes = np.array(self.Gv.nodes())
uneg = list(nodes[np.nonzero(nodes < 0)[0]])
upos = list(nodes[np.nonzero(nodes > 0)[0]])
if kwargs['nodes']:
nx.draw_networkx_nodes(self.Gv, self.Gs.pos, nodelist=upos,
node_color='blue', node_size=300, alpha=0.3)
nx.draw_networkx_nodes(self.Gv, self.Gs.pos, nodelist=uneg,
node_color='red', node_size=300, alpha=0.3)
nx.draw_networkx_labels(self.Gv, self.Gs.pos)
ndnd, nded, eded = gru.edgetype(self.Gv)
if kwargs['eded']:
nx.draw_networkx_edges(self.Gv, self.Gs.pos,
edgelist=eded, edge_color='blue', width=2)
if kwargs['ndnd']:
nx.draw_networkx_edges(self.Gv, self.Gs.pos,
edgelist=ndnd, edge_color='red', width=2)
if kwargs['nded']:
nx.draw_networkx_edges(self.Gv, self.Gs.pos,
edgelist=nded, edge_color='green', width=2)
if kwargs['show']:
plt.show()
return ax
[docs] def waypointGw(self, nroom1, nroom2):
""" get the waypoint between room1 and room2
Parameters
----------
nroom1
nroom2
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('TA-Office.lay')
>>> L.build()
Notes
-----
nodes of Gw are no longer room number
"""
rooms = nx.dijkstra_path(self.Gw, nroom1, nroom2)
return(rooms, [tuple(self.Gw.pos[i]) for i in rooms])
[docs] def thwall(self, offx, offy):
""" Create a list of wall tuples (Transit.world format )
Parameters
----------
offx
offy
Returns
-------
walls : list of wall tuples (Transit format)
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('DLR.lay')
>>> walls = L.thwall(0,0)
"""
keyn = list(dict(self.Gs.node).keys())
walls = []
for nd in keyn:
if nd > 0:
#v1.1 nb = self.Gs.neighbors(nd)
nb = list(dict(self.Gs[nd]).keys())
pta = self.Gs.pos[nb[0]]
phe = self.Gs.pos[nb[1]]
pn = self.Gs.node[nd]['norm']
name = self.Gs.node[nd]['name']
transition = self.Gs.node[nd]['transition']
sl = self.sl[name]
thick = sum(sl['lthick'])
p1 = np.array(pta) + \
np.array((pn[0], pn[1])) * thick / 2. + \
np.array([offx, offy])
p2 = np.array(phe) + \
np.array((pn[0], pn[1])) * thick / 2. + \
np.array([offx, offy])
p3 = np.array(phe) - \
np.array((pn[0], pn[1])) * thick / 2. + \
np.array([offx, offy])
p4 = np.array(pta) - \
np.array((pn[0], pn[1])) * thick / 2. + \
np.array([offx, offy])
wall = (tuple(p1), tuple(p2), tuple(p3), tuple(p4))
if not transition and name != 'AIR':
walls.append(wall)
return(walls)
[docs] def ptin(self, pt=np.array((0, 0, 0))):
""" check if a point is in the Layout
Parameters
----------
pt : point (ndarray)
Returns
-------
boolean : True if inside
See Also
--------
ispoint
"""
pt = pt[:2]
x = np.array((self.ax[:2]))
y = np.array((self.ax[2:]))
# being in [xmin xmax]
c0 = pt[0] <= x[1] and pt[0] >= x[0]
# being in [ymin ymax]
c1 = pt[1] <= y[1] and pt[1] >= y[0]
return (c0 & c1)
[docs] def ptGs2cy(self, n=-1):
""" Gs node to cycle
Parameters
----------
upt : point (ndarray)
Returns
-------
ncy : cycle number
Notes
-----
If a cycle contains the Gs pointt this function returns the cycle(s) number
"""
if n > 0:
return self.Gs.node[n]['ncycles']
else:
nseg = list(dict(self.Gs[n]).keys())
cy = []
for nn in nseg:
cy.extend(self.ptGs2cy(nn))
cy = np.unique(cy).tolist()
return cy
[docs] def isindoor(self,pt=np.array([0,0])):
""" test if a point is indoor
Parameters
----------
pt : np.array 1x2
2d point
Returns
-------
b1 : boolean
True if indoor
"""
cy = self.pt2cy(pt)
b1 = self.Gt.node[cy]['indoor']
return b1
[docs] def pt2cy(self, pt=np.array((0, 0))):
""" point to cycle
Parameters
----------
pt : point (ndarray)
Returns
-------
ncy : cycle number
Notes
-----
If a cycle contains point pt this function returns the cycle number
See Also
--------
Layout.cy2pt
"""
ptsh = sh.Point(pt[0], pt[1])
cycle_exists = False
for ncy in list(dict(self.Gt.node).keys()):
if ncy > 0:
criter1 = self.Gt.node[ncy]['polyg'].touches(ptsh)
criter2 = self.Gt.node[ncy]['polyg'].contains(ptsh)
if (criter1 or criter2):
cycle_exists = True
return(ncy)
if not cycle_exists:
raise NameError(str(pt) + " is not in any cycle")
[docs] def cy2pt(self, cy=0, h=1.2):
"""returns a point into a given cycle
Parameters
----------
cy : int
cycle number
h : float
point height
Returns
-------
point : nd.array
3d point
See Also
--------
Layout.pt2cy
"""
if cy in self.Gt.nodes():
pt = np.array((self.Gt.pos[cy]))
pt = np.hstack((pt, h))
return(pt)
else:
raise NameError("cycle " + str(cy) + " not in self.Gt")
[docs] def pt2ro(self, pt=np.array((0, 0))):
""" point to room
Parameters
----------
pt : point (ndarray)
Returns
-------
nr : Room number
Notes
-----
If a room contains point pt this function returns the room number
"""
ptsh = sh.Point(pt[0], pt[1])
ptshinroom = False
for nr in list(dict(self.Gr.node.keys())):
if self.Gr.node[nr]['polyg'].contains(ptsh)\
or self.Gr.node[nr]['polyg'].touches(ptsh):
ptshinroom = True
return(nr)
if not ptshinroom:
raise NameError(str(pt) + " is not in any room")
[docs] def seg2ro(self, seg):
""" return room number of a point
Parameters
----------
seg : int
Returns
-------
nr : Room number
Notes
-----
If a room contains point pt this function returns the room number
"""
rooms = []
for nr in list(dict(self.Gr.node.keys())):
# if seg in self.Gt.node[self.Gr.node[nr]['cycle']]['vnodes']:
ncy = self.Gr.node[nr]['cycle']
if seg in self.Gt.node[ncy]['cycle'].cycle:
rooms.append(nr)
return rooms
[docs] def room2segments(self, room):
""" returns the segments of a room
Parameters
----------
room : int
Returns
-------
seg : list
"""
try:
# old vnodes was there
ncy = self.Gr.node[room]['cycle']
seg = self.Gt.node[ncy].cycle
except:
raise NameError(str(room) + " is not in not on Gr")
u = np.where(seg >= 0)
seg = seg[u]
return np.sort(seg.tolist())
[docs] def room2nodes(self, room):
""" returns the nodes of a room
Parameters
----------
room : int
Returns
-------
nod : sorted list
"""
try:
ncy = self.Gr.node[room]['cycle']
nod = self.Gt.node[ncy].cycle
#nod = self.Gt.node[self.Gr.node[room]['cycle']]['vnodes']
except:
raise NameError(str(room) + " is not in not on Gr")
u = np.where(nod < 0)
nod = nod[u]
return np.sort(nod.tolist())
[docs] def get_diffslab(self,npt,lz):
""" get the 2 slabs associated to a diffraction point
Parameters
----------
lnpt : diffraction point numbers (node of Gs)
lz : array of candidate heights of the diffraction point
Notes
-----
As a diffraction point may involve iso segments the nature
of the diffraction interaction depends on a height parameter
This function extacts the couple of slab from this information
Returns
-------
- a list of 2-segments . the length of this list == length of lz
- a list of slab tuples. the length of this list == length of lz
[[443, 529], [444, 530]]
[['WALL', 'WALL'], ['AIR', 'AIR']]
"""
assert(npt in self.ddiff), logger.error('npt not a diffraction point')
lcy = self.ddiff[npt][0]
ls = []
llz = len(lz)
dz_seg= {z:[] for z in range(llz)}
dz_sl= {z:[] for z in range(llz)}
for cy in lcy:
vn = set(self.Gt.node[cy]['polyg'].vnodes)
# v1.1 lneig_pt = set(nx.neighbors(self.Gs,npt))
lneig_pt = set(self.Gs[npt])
lseg = lneig_pt.intersection(vn)
lseg_valid = [ x for x in lseg if self.Gs.node[x]['name']!='_AIR']
for x in lseg_valid:
zsup = lz >self.Gs.node[x]['z'][0]
zinf = lz <=self.Gs.node[x]['z'][1]
z = zsup & zinf
uz = np.where(z)[0]
# fill dz_seg at the correct height with a lseg_valid
# and simulnaneously
# fill dz_sl at the correct height with correspondong slab
[(dz_seg[i].append(x),dz_sl[i].append(self.Gs.node[x]['name']))
for i in uz]
return dz_seg.values(),dz_sl.values()
def _find_diffractions(self, difftol=0.01,verbose = False,tqdmkwargs={}):
""" find diffractions points of the Layout
Parameters
----------
difftol : float
tolerance in radians
Returns
-------
Update self.ddiff {nseg : ([ncy1,ncy2],wedge_angle)}
"""
# dangles = self.get_Gt_angles()
#
# Problem here point number are converted into float64
if tqdmkwargs=={}:
tqdmkwargs={'total':100.,
'desc':'find_diffractions'}
dangles = {cy: np.array(geu.get_pol_angles(self.Gt.node[cy]['polyg']))
for cy in self.Gt.nodes() if cy != 0}
#
# The candidate points for being diffraction points have degree 1 or 2
# A point diffracts toward one or several cycles
#
#ldiff = list(np.hstack((self.degree[1],self.degree[2])).astype('int'))
lpnt = [x for x in self.Gs.node if (x < 0 and x not in self.degree[0])]
self.ddiff = {}
if verbose :
cpt = 1./(len(lpnt)+1)
pbar = tqdm.tqdm(tqdmkwargs)
for k in lpnt:
if verbose :
pbar.update(100.*cpt)
# list of cycles associated with point k
lcyk = self.Gs.node[k]['ncycles']
if len(lcyk) > 2:
# Subgraph of connected cycles around k
Gtk = nx.subgraph(self.Gt, lcyk)
# ordered list of connections between cycles
try:
lccyk = nx.find_cycle(Gtk)
except:
pdb.set_trace()
# list of segment neighbours
neigh = list(dict(self.Gs[k]).keys())
# sega : list of air segment in neighors
sega = [n for n in neigh if
(self.Gs.node[n]['name'] == 'AIR' or
self.Gs.node[n]['name'] == '_AIR')]
sega_iso = [n for n in sega if len(self.Gs.node[n]['iso']) > 0]
sega_eff = list(set(sega).difference(set(sega_iso)))
nsector = len(neigh) - len(sega)
dsector = {i: [] for i in range(nsector)}
#
# team building algo
#
ct = 0
# if k ==-44:
# pdb.set_trace()
for ccy in lccyk:
#segsep = self.Gt[ccy[0]][ccy[1]]['segment'][0]
segsep = self.Gt[ccy[0]][ccy[1]]['segment']
# filter only segments connected to point k (neigh)
lvseg = [x for x in segsep if x in neigh]
if len(lvseg) == 1 and (lvseg[0] in sega_eff): # same sector
dsector[ct].append(ccy[1])
else: # change sector
ct = (ct + 1) % nsector
dsector[ct].append(ccy[1])
# typslab = self.Gs.node[segsep]['name']
# if (typslab=='AIR' or typslab=='_AIR'): # same sector
# dsector[ct].append(ccy[1])
# else: # change sector
# ct=(ct+1)%nsector
# dsector[ct].append(ccy[1])
# lcy2.append(ccy[1])
# lcy1,lcy2 = lcy2,lcy1
dagtot = {s: 0 for s in range(nsector)}
save = []
for s in dsector:
for cy in dsector[s]:
da = dangles[cy]
u = np.where(da[0, :].astype('int') == k)[0][0]
save.append((cy, da[1, u]))
dagtot[s] = dagtot[s] + da[1, u]
for s in dagtot:
if dagtot[s] > (np.pi + difftol):
self.ddiff[k] = (dsector[s], dagtot[s])
break
# if agtot1 > (np.pi+tol):
# self.ddiff[k]=(lcy1,agtot1)
# elif 2*np.pi-agtot1 > (np.pi+tol):
# self.ddiff[k]=(lcy2,2*np.pi-agtot1)
else:
# diffraction by half-plane detected
if k in self.degree[1]:
self.ddiff[k] = (lcyk, 2 * np.pi)
[docs] def buildGr(self):
""" build the graph of rooms Gr
Notes
-----
adjascent rooms are connected
Gr is at startup a deep copy of Gt
The difficulty here is to take into account the AIR transition
segments
"""
self.Gr = copy.deepcopy(self.Gt)
self.Gr.remove_node(0)
self.Gr.remove_edges_from(self.Gt.edges())
for e in list(self.Gt.edges()):
if ((not 0 in e) and
(self.Gt.node[e[0]]['indoor']) and
(self.Gt.node[e[1]]['indoor']) ):
seg = self.Gt[e[0]][e[1]]['segment']
seg = np.unique(seg)
trans_seg = [n for n in seg
if (self.Gs.node[n]['transition'])
and n not in self.segboundary]
if trans_seg != []:
self.Gr.add_edge(e[0],e[1],segment=trans_seg)
deg = dict(self.Gr.degree())
#pdb.set_trace()
self.Gr.remove_nodes_from([n for n in deg if deg[n] == 0])
[docs] def buildGw(self):
""" build Graph of waypaths
See Also
--------
buildGr
Notes
-----
for all edges of Gr (adjascent room)
if room1 and room2 have a common transition
"""
self.Gw = nx.Graph(name='Gw')
self.Gw.pos = {}
d_id = max(self.Gr.nodes()) # for numerotation of Gw nodes
d_id_index = d_id + 1
for e in self.Gr.edges(): # iterator on Gr edges
self.Gw.add_node(e[0], room=e[0], door=False)
self.Gw.add_node(e[1], room=e[1], door= False)
# transitions of room e[0]
# trans1 = self.Gr.node[e[0]]['segment']
# # transitions of room e[1]
# trans2 = self.Gr.node[e[1]]['segment']
# Id = np.intersect1d(trans1, trans2)[0] # list of common doors
# import ipdb
# ipdb.set_trace()
Ids = self.Gr[e[0]][e[1]]['segment']
# here is supposed that 2 room may have more than 1 door in common
for Id in Ids:
#v1.1 unode = self.Gs.neighbors(Id) # get edge number of common doors
unode = list(dict(self.Gs[Id]).keys()) # get edge number of common doors
up0 = self.Gs.pos[unode[0]]
up1 = self.Gs.pos[unode[1]]
name = self.Gs.node[Id]['name']
pn = self.Gs.node[Id]['norm']
sl = self.sl[name]
thick = (sum(sl['lthick']) / 2.) + 0.2
# for ""doors"" extra waypoints points are added
# in front and back of the aperture.
# this is not done for AIR slabs
if 'AIR' not in name:
# middle of the common door
pdoor0 = (np.array(up0) + pn[:2] * thick +
np.array(up1) + pn[:2] * thick) / 2.
pdoor1 = (np.array(up0) - pn[:2] * thick +
np.array(up1) - pn[:2] * thick) / 2.
P0 = sh.Point(pdoor0)
P1 = sh.Point(pdoor1)
ep0 = self.Gr.pos[e[0]]
ep1 = self.Gr.pos[e[1]]
if self.Gr.node[e[0]]['polyg'].contains(P0):
upd0 = d_id_index
self.Gw.pos[upd0] = pdoor0
self.Gw.add_node(upd0, room=e[0], door=True)
# if self.seginline(pdoor0,ep0).shape[1] <= 1:
self.Gw.add_edges_from([(e[0],upd0)])
d_id_index = d_id_index + 1
upd1 = d_id_index
self.Gw.pos[upd1] = pdoor1
self.Gw.add_node(upd1, room=e[1], door=True)
# if self.seginline(pdoor1,ep1).shape[1] <= 1:
self.Gw.add_edges_from([(e[1],upd1)])
d_id_index = d_id_index + 1
else:
upd0 = d_id_index
self.Gw.pos[upd0] = pdoor0
self.Gw.add_node(upd0, room=e[1], door=True)
# if self.seginline(pdoor0,ep1).shape[1] <= 1:
self.Gw.add_edges_from([(e[1],upd0)])
d_id_index = d_id_index + 1
upd1 = d_id_index
self.Gw.pos[upd1] = pdoor1
self.Gw.add_node(upd1, room=e[0], door=True)
# if self.seginline(pdoor1,ep0).shape[1] <= 1:
self.Gw.add_edges_from([(e[0],upd1)])
d_id_index = d_id_index + 1
self.Gw.add_edges_from([(upd0, upd1)])
else:
self.Gw.add_edges_from([(e[0],e[1])])
self.Gw.pos.update(self.Gr.pos)
[docs] def info(self):
""" gives information about the Layout
"""
print("filestr : ", self._filename)
# print("filematini : ", self.filematini)
# print("fileslabini : ", self.fileslabini)
try:
print("filegeom : ", self.filegeom)
except:
print("geomfile (.off) has no been generated")
# self.boundary()
print("boundaries ", self.ax)
print("number of Points :", self.Np)
print("number of Segments :", self.Ns)
print("number of Sub-Segments :", self.Nss)
try:
print("Gs Nodes : ", self.Gs.number_of_nodes())
print("Gs Edges : ", self.Gs.number_of_edges())
except:
print("no Gs graph")
try:
print("Gt Nodes : ", self.Gt.number_of_nodes())
print("Gt Edges : ", self.Gt.number_of_edges())
print("vnodes = Gt.node[Nc]['polyg'].vnodes")
print("poly = Gt.node[Nc]['polyg']")
except:
print("no Gt graph")
try:
print("Gr Nodes :", self.Gr.number_of_nodes())
print("Gr Edges :", self.Gr.number_of_edges())
except:
print("no Gr graph")
[docs] def facets3D(self, edlist, name='Layer', subseg=False):
""" create facet 3D for geomview
Parameters
----------
edlist
name : string
subseg : boolean
"""
filename = name + '.list'
filestruc = pyu.getlong(filename, pro.pstruc['DIRGEOM'])
fos = open(filestruc, "w")
fos.write("LIST{\n")
for e in edlist:
filename = self.facet3D(e, subseg)
if filename == 'void':
pass
else:
chaine = '{<' + filename + "}\n"
fos.write(chaine)
fos.write("}\n")
fos.close()
[docs] def numseg(self, ta, he, first=True):
""" get segment number from 2 points index
Parameters
----------
ta : int <0
he : int <0
first : Boolean
if True returns only one among the several iso segments
else returns a np.array of iso segments
Returns
-------
nseg : > 0
if 0 not a segment
"""
# v1.1 nta = np.array(nx.neighbors(self.Gs, ta))
# v1.1 nhe = np.array(nx.neighbors(self.Gs, he))
nta = np.array(list(dict(self.Gs[ta]).keys()))
nhe = np.array(list(dict(self.Gs[he]).keys()))
nseg = np.intersect1d(nta, nhe)
if len(nseg > 0):
if first:
return(nseg[0])
else:
return nseg
else:
return(0)
[docs] def isseg(self, ta, he):
""" test if ta<->he is a segment
Parameters
----------
ta : int <0
he : int <0
Returns
-------
boolean
See Also
--------
editor.py
"""
# transpose point numbering
upnt = [ x for x in self.Gs.nodes() if x < 0 ]
ta = np.nonzero(np.array(upnt) == ta)[0][0]
he = np.nonzero(np.array(upnt) == he)[0][0]
res = [x for x in zip(self.tahe[0], self.tahe[1])
if (((x[0] == ta) & (x[1] == he)) |
((x[0] == he) & (x[1] == ta))) ]
if len(res) > 0:
return True
else:
return False
[docs] def ispoint(self, pt, tol=0.05):
""" check if pt is a point of the Layout
Parameters
----------
pt : point (2,1)
tol : float
default (0.05 meters)
if True the point number (<0) is returned
else 0 is return
Returns
-------
pt : point number if point exists 0 otherwise
See Also
--------
pylayers.util.geomutil.Polygon.setvnodes
"""
# print"ispoint : pt ", pt
pts = np.array(list(self.Gs.pos.values())).T
ke = np.array(list(self.Gs.pos.keys()))
diff = pts - pt.reshape(2, 1)
v = np.sqrt(np.sum(diff * diff, axis=0))
nz = (v > tol)
b = nz.prod()
if b == 1:
# if all layout points are different from pt
#return(0,np.min(v))
return(0)
else:
nup = np.where(nz == False)[0]
if len(nup) == 1:
return(ke[nup][0])
else:
mi = np.where(min(v[nup]) == v[nup])[0]
return(ke[nup[mi]][0])
[docs] def onseg(self, pt, tol=0.01):
""" segment number from point (deprecated)
return segment number which contains point pt
Parameters
----------
pt np.array(1x2)
tol = 0.01 tolerance
"""
pts = np.array(self.Gs.pos.values()).T # structure points
ke = np.array(list(dict(self.Gs.pos).keys())) # point keys
n = np.shape(pts)[1]
nbu = np.array([])
if (n > 0):
num = np.arange(n) #
b = self.inbox(pt, tol)
ta = self.tahe[0, b]
he = self.tahe[1, b]
nb = num[b]
n = len(nb)
p = np.outer(pt, np.ones(n))
# printta
v1 = p - pts[:, ta]
v2 = pts[:, he] - p
nv1 = np.sqrt(v1[0, :] * v1[0, :] + v1[1, :] * v1[1, :])
nv2 = np.sqrt(v2[0, :] * v2[0, :] + v2[1, :] * v2[1, :])
v1n = v1 / nv1
v2n = v2 / nv2
ps = v1n[0, :] * v2n[0, :] + v1n[1, :] * v2n[1, :]
u = abs(1. - ps) < tol
nbu = nb[u]
return nbu
[docs] def facet3D(self, e, subseg=False):
""" calculate 3D facet from segment
Parameters
---------
s : int
segment number
subseg : boolean
default False
"""
P1 = np.array(np.zeros(3), dtype=np.float64)
P2 = np.array(np.zeros(3), dtype=np.float64)
P3 = np.array(np.zeros(3), dtype=np.float64)
P4 = np.array(np.zeros(3), dtype=np.float64)
# v1.1 nebr = self.Gs.neighbors(s)
nebr = list(dict(self.Gs[s]).keys())
n1 = nebr[0]
n2 = nebr[1]
P1[0:2] = np.array(self.Gs.pos[n1])
P1[2] = self.Gs.node[s]['z'][0]
P2[0:2] = np.array(self.Gs.pos[n2])
P2[2] = self.Gs.node[s]['z'][0]
P3[0:2] = np.array(self.Gs.pos[n2])
P3[2] = self.Gs.node[s]['z'][1]
P4[0:2] = np.array(self.Gs.pos[n1])
P4[2] = self.Gs.node[s]['z'][1]
cold = pyu.coldict()
if subseg:
nsseg = len(self.Gs.node[s]['ss_name'])
else:
nsseg = 0
filename = 'fa' + str(s) + '.off'
filestruc = pyu.getlong(filename, pro.pstruc['DIRGEOM'])
fos = open(filestruc, "w")
fos.write("OFF\n")
fos.write("%d %d \n\n" % (1 + (nsseg + 1) * 4, nsseg + 1))
fos.write("0.000 0.000 0.000\n")
if subseg:
try:
for k, name in enumerate(self.Gs.node[s]['ss_name']):
P1[2] = self.Gs.node[s]['ss_z'][k][0]
P2[2] = self.Gs.node[s]['ss_z'][k][0]
P3[2] = self.Gs.node[s]['ss_z'][k][1]
P4[2] = self.Gs.node[s]['ss_z'][k][1]
fos.write("%6.3f %6.3f %6.3f \n" % (P1[0], P1[1], P1[2]))
fos.write("%6.3f %6.3f %6.3f \n" % (P2[0], P2[1], P2[2]))
fos.write("%6.3f %6.3f %6.3f \n" % (P3[0], P3[1], P3[2]))
fos.write("%6.3f %6.3f %6.3f \n" % (P4[0], P4[1], P4[2]))
except:
print('no subsegment on ', s)
return('void')
else:
name = self.Gs.node[s]['name']
fos.write("%6.3f %6.3f %6.3f \n" % (P1[0], P1[1], P1[2]))
fos.write("%6.3f %6.3f %6.3f \n" % (P2[0], P2[1], P2[2]))
fos.write("%6.3f %6.3f %6.3f \n" % (P3[0], P3[1], P3[2]))
fos.write("%6.3f %6.3f %6.3f \n" % (P4[0], P4[1], P4[2]))
if subseg:
for k, name in enumerate(self.Gs.node[s]['ss_name']):
colname = sl[name]['color']
colhex = cold[colname]
col = pyu.rgb(colhex) / 255.
fos.write("4 %i %i %i %i %6.3f %6.3f %6.3f 0.4\n" % (1 + 4 * k, 2 + 4 * k,
3 + 4 * k, 4 + 4 * k, col[0], col[1], col[2]))
else:
name = self.Gs.node[s]['name']
colname = sl[name]['color']
colhex = cold[colname]
col = pyu.rgb(colhex) / 255.
fos.write("4 %i %i %i %i %6.3f %6.3f %6.3f 0.4\n" % (1, 2,
3, 4, col[0], col[1], col[2]))
return(filename)
[docs] def geomfile(self, centered=False):
""" create a .off geomview file
Parameters
----------
centered : Boolean
if True the layout is centered around its center of gravity
Notes
-----
The `.off` file can be vizualized through the show3 method
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('DLR.lay')
>>> pg = L.geomfile()
"""
# calculate center of gravity
if centered:
pg = np.sum(self.pt, axis=1) / np.shape(self.pt)[1]
else:
pg = np.array([0, 0])
# en = self.Ns # number of segments
en = len(np.where(np.array(list(dict(self.Gs.node).keys())) > 0)[0])
if en != self.Ns:
logger.warning("wrong number of segments, consistency problem in layout")
#cen = self.Nss
# d : dictionnary of layout sub segments
#
d = self.subseg()
cen = 0
for k in d:
lss = d[k]
cen = cen + len(lss)
if cen != self.Nss:
logger.warning("wrong number of subsegments, consistency problem in layout")
sl = self.sl
#
# Create a polygon for each segment and subsegment
#
P1 = np.array(np.zeros([3, en + cen], dtype=np.float64))
P2 = np.array(np.zeros([3, en + cen], dtype=np.float64))
P3 = np.array(np.zeros([3, en + cen], dtype=np.float64))
P4 = np.array(np.zeros([3, en + cen], dtype=np.float64))
ik = 0
dikn = {}
for i in list(dict(self.Gs.node).keys()):
if i > 0: # segment
if ((self.Gs.node[i]['name'] != 'AIR') and
(self.Gs.node[i]['name'] != '_AIR')):
#v1.1 nebr = self.Gs.neighbors(i)
nebr = list(dict(self.Gs[i]).keys())
n1 = nebr[0]
n2 = nebr[1]
P1[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P1[2, ik] = self.Gs.node[i]['z'][0]
P2[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P2[2, ik] = self.Gs.node[i]['z'][0]
P3[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P3[2, ik] = self.Gs.node[i]['z'][1]
P4[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P4[2, ik] = self.Gs.node[i]['z'][1]
dikn[ik] = i
ik = ik + 1
else:
en = en - 1
# d = self.subseg()
# k : ss_name v: seg number
cpt = 0
subseg = {}
# pdb.set_trace()
for k in d.keys():
for l in d[k]:
ids = l[0]
subseg[cpt] = ids
order = l[1]
cpt = cpt + 1
# v1.1 nebr = self.Gs.neighbors(l[0])
nebr = list(dict(self.Gs[l[0]]).keys())
n1 = nebr[0]
n2 = nebr[1]
# printik,n1,n2
P1[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P1[2, ik] = self.Gs.node[ids]['ss_z'][order][0]
# printP1[:,ik]
P2[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P2[2, ik] = self.Gs.node[ids]['ss_z'][order][0]
# printP2[:,ik]
P3[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P3[2, ik] = self.Gs.node[ids]['ss_z'][order][1]
# printP3[:,ik]
P4[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P4[2, ik] = self.Gs.node[ids]['ss_z'][order][1]
# printP4[:,ik]
dikn[ik] = l
ik = ik + 1
npt = 4 * (en + cen)
_filename, ext = os.path.splitext(self._filename)
_filegeom = _filename + '.off'
self.filegeom = _filegeom
filegeom = pyu.getlong(_filegeom, pro.pstruc['DIRGEOM'])
fos = open(filegeom, "w")
fos.write("OFF\n")
fos.write("%d %d \n\n" % (npt + 1, en + cen))
fos.write("0.000 0.000 0.000\n")
for i in range(en + cen):
fos.write("%6.3f %6.3f %6.3f \n" % (P1[0, i], P1[1, i], P1[2, i]))
fos.write("%6.3f %6.3f %6.3f \n" % (P2[0, i], P2[1, i], P2[2, i]))
fos.write("%6.3f %6.3f %6.3f \n" % (P3[0, i], P3[1, i], P3[2, i]))
fos.write("%6.3f %6.3f %6.3f \n" % (P4[0, i], P4[1, i], P4[2, i]))
cold = pyu.coldict()
# ke = cold.keys()
#
for i in range(en + cen):
q = 4 * i
if i < en:
#ne = i + 1
ne = dikn[i]
name = self.Gs.node[ne]['name']
else:
ne = dikn[i][0]
order = dikn[i][1]
#nss = i - en
##ne = subseg[nss]
name = self.Gs.node[ne]['ss_name'][order]
# if (i<en):
# name = self.name[i]
# else:
# core = self.ce[subseg[i-en]][0]
# name = sl.di[core]
colname = sl[name]['color']
colhex = cold[colname]
col = pyu.rgb(colhex) / 255.
fos.write("4 %i %i %i %i %6.3f %6.3f %6.3f 0.4\n" % (q +
1, q + 2, q + 3, q + 4, col[0], col[1], col[2]))
fos.close()
return pg
def _show3(self, centered=False, newfig=False, opacity=1., ceil_opacity=1., show_ceil=False, cyid=False, **kwargs):
""" mayavi 3D vizualisation
Parameters
----------
newfig : Boolean
create a new mayavi Figure
opacity : float ([0,1])
set slab opacity
ceil_opacity : float
centered : Boolean
if True the layout is centered around its center of gravity
cyid : boolean
display cycle number
show_ceil: boolean
display ceil or not
Notes
-----
The `.off` file can be vizualized through the show3 method
Examples
--------
.. plot::
:include-source:
>>> from pylayers.gis.layout import *
>>> L = Layout()
"""
#
# calculate center of gravity of the layout
#
if centered:
pg = np.sum(self.pt, axis=1) / np.shape(self.pt)[1]
else:
pg = np.array([0, 0])
# en = self.Ns # number of segments
en = len(np.where(np.array(list(dict(self.Gs.node).keys())) > 0)[0])
if en != self.Ns:
logger.warning(
"wrong number of segment consistency problem in layout")
#cen = self.Nss
# d : dictionnary of layout sub segments
#
d = self.subseg()
cen = 0
for k in d:
lss = d[k]
cen = cen + len(lss)
if cen != self.Nss:
logger.warning(
"wrong number of subsegment consistency problem in layout")
sl = self.sl
#
# Create a 3D polygon for each segment and subsegment
#
P1 = np.array(np.zeros([3, en + cen], dtype=np.float64))
P2 = np.array(np.zeros([3, en + cen], dtype=np.float64))
P3 = np.array(np.zeros([3, en + cen], dtype=np.float64))
P4 = np.array(np.zeros([3, en + cen], dtype=np.float64))
ik = 0
dikn = {}
#
# segments which are not _AIR or AIR
#
for i in list(dict(self.Gs.node).keys()):
if i > 0: # segment
if ((self.Gs.node[i]['name'] != 'AIR') and
(self.Gs.node[i]['name'] != '_AIR')):
#v1.1 nebr = self.Gs.neighbors(i)
nebr = list(dict(self.Gs[i]).keys())
n1 = nebr[0]
n2 = nebr[1]
P1[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P1[2, ik] = self.Gs.node[i]['z'][0]
P2[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P2[2, ik] = self.Gs.node[i]['z'][1]
P3[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P3[2, ik] = self.Gs.node[i]['z'][1]
P4[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P4[2, ik] = self.Gs.node[i]['z'][0]
dikn[ik] = i
ik = ik + 1
else:
en = en - 1
# d = self.subseg()
# k : ss_name v: seg number
cpt = 0
subseg = {}
for k in d.keys():
for l in d[k]:
ids = l[0]
subseg[cpt] = ids
order = l[1]
cpt = cpt + 1
# v1.1 nebr = self.Gs.neighbors(l[0])
nebr = list(dict(self.Gs[l[0]]).keys())
n1 = nebr[0]
n2 = nebr[1]
# printik,n1,n2
P1[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P1[2, ik] = self.Gs.node[ids]['ss_z'][order][0]
# printP1[:,ik]
P2[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P2[2, ik] = self.Gs.node[ids]['ss_z'][order][0]
# printP2[:,ik]
P3[0:2, ik] = np.array(self.Gs.pos[n2]) - pg
P3[2, ik] = self.Gs.node[ids]['ss_z'][order][1]
# printP3[:,ik]
P4[0:2, ik] = np.array(self.Gs.pos[n1]) - pg
P4[2, ik] = self.Gs.node[ids]['ss_z'][order][1]
# printP4[:,ik]
dikn[ik] = l
ik = ik + 1
npt = 4 * (en + cen)
npt_s = (en + cen)
points = np.hstack((P1[:, 0:npt_s], P2[:, 0:npt_s]))
points = np.hstack((points, P3[:, 0:npt_s]))
points = np.hstack((points, P4[:, 0:npt_s]))
points = points.T
boxes = np.empty((int(npt / 4), 4), dtype='int')
b = np.arange(int(npt / 4))
boxes[:, 0] = b
boxes[:, 1] = b + npt_s
boxes[:, 2] = b + 2 * npt_s
boxes[:, 3] = b + 3 * npt_s
# _filename,ext = os.path.splitext(self._filename)
# _filegeom = _filename+'.off'
# self.filegeom=_filegeom
# filegeom = pyu.getlong(_filegeom, pro.pstruc['DIRGEOM'])
# fos = open(filegeom, "w")
# fos.write("OFF\n")
# fos.write("%d %d \n\n" % (npt + 1, en + cen))
# fos.write("0.000 0.000 0.000\n")
# for i in range(en + cen):
# fos.write("%6.3f %6.3f %6.3f \n" % (P1[0, i], P1[1, i], P1[2, i]))
# fos.write("%6.3f %6.3f %6.3f \n" % (P2[0, i], P2[1, i], P2[2, i]))
# fos.write("%6.3f %6.3f %6.3f \n" % (P3[0, i], P3[1, i], P3[2, i]))
# fos.write("%6.3f %6.3f %6.3f \n" % (P4[0, i], P4[1, i], P4[2, i]))
cold = pyu.coldict()
color = np.zeros((4 * (cen + en), 3))
for i in range(en + cen):
# q = 4 * i
if i < en:
ne = dikn[i]
name = self.Gs.node[ne]['name']
else:
ne = dikn[i][0]
order = dikn[i][1]
name = self.Gs.node[ne]['ss_name'][order]
colname = sl[name]['color']
colhex = cold[colname]
color[i, :] = pyu.rgb(colhex)
color[i + npt_s, :] = pyu.rgb(colhex)
color[i + 2 * npt_s, :] = pyu.rgb(colhex)
color[i + 3 * npt_s, :] = pyu.rgb(colhex)
colname = sl['FLOOR']['color']
colhex = cold[colname]
colf = np.repeat((pyu.rgb(colhex))[np.newaxis, :], 4, axis=0)
color = np.vstack((color, colf))
# trick for correcting color assignement
sc = tvtk.UnsignedCharArray()
sc.from_array(color)
# manage floor
# if Gt doesn't exists
try:
self.ma.coorddeter()
# z=np.ones(self.ma.xy.shape[1])
z = np.zeros(self.ma.xy.shape[1])
F = np.vstack((self.ma.xy, z))
tri = np.arange(len(z))
meshf = tvtk.PolyData(points=F.T, polys=np.array([tri]))
meshf.point_data.scalars = sc
meshf.point_data.scalars.name = 'scalars'
surff = mlab.pipeline.surface(meshf, opacity=opacity)
mlab.pipeline.surface(mlab.pipeline.extract_edges(surff),
color=(0, 0, 0), )
# otherwise
except:
floorx = np.array((points[:, 0].min(), points[:, 0].max()))
floory = np.array((points[:, 1].min(), points[:, 1].max()))
zmin = np.min(points[:, 2])
Pf = np.array([floorx[0], floory[0], zmin])
Pf = np.vstack((Pf, np.array([floorx[0], floory[1], zmin])))
Pf = np.vstack((Pf, np.array([floorx[1], floory[1], zmin])))
Pf = np.vstack((Pf, np.array([floorx[1], floory[0], zmin])))
points = np.vstack((points, Pf))
bf = np.arange(npt, npt + 4)
boxes = np.vstack((boxes, bf))
mesh = tvtk.PolyData(points=points, polys=boxes)
mesh.point_data.scalars = sc
mesh.point_data.scalars.name = 'scalars'
if newfig:
mlab.clf()
f = mlab.figure(bgcolor=(1, 1, 1))
else:
f = mlab.gcf()
f.scene.background = (1, 1, 1)
f.scene.disable_render = True
surf = mlab.pipeline.surface(mesh, opacity=opacity)
mlab.pipeline.surface(mlab.pipeline.extract_edges(surf),
color=(0, 0, 0), )
f.children[-1].name = 'Layout ' + self._filename
if show_ceil == True:
if len(self.Gt.nodes()) != 0:
uin = [kn for kn in self.Gt.nodes() if self.Gt.node[kn]
['indoor'] == True]
ptc = np.ndarray(shape=(3, 0))
boxc = np.ndarray(shape=(0, 3))
cpt = 0
for u in uin:
p = self.Gt.node[u]['polyg']
no = self.Gt.node[u]['polyg'].vnodes[
self.Gt.node[u]['polyg'].vnodes > 0]
for n in no:
if self.Gs.node[n]['z'][1] != 40000000:
h = self.Gs.node[n]['z'][1]
break
vert = {"vertices": np.array(p.exterior.xy).T}
dt = triangle.triangulate(vert)
nbpt = len(dt['vertices'])
pt = np.vstack((dt['vertices'].T, [h] * nbpt))
box = dt['triangles']
# if u == 114:
# import ipdb
# ipdb.set_trace()
# box = np.roll(box,1,1)
ptc = np.hstack((ptc, pt))
boxc = np.vstack((boxc, box + cpt))
cpt = cpt + nbpt
# if box.shape[0] == 2 :
# import ipdb
# ipdb.set_trace()
# print(cpt,nbpt)
# print(box)
# print(pt)
# break
# manage Ceil color
colname = sl['CEIL']['color']
colhex = cold[colname]
colf = np.repeat((pyu.rgb(colhex))[np.newaxis, :], cpt, axis=0)
# color = np.vstack((color, colf))
color=colf
# trick for correcting color assignement
sc = tvtk.UnsignedCharArray()
sc.from_array(color)
meshc = tvtk.PolyData(points=ptc.T, polys=boxc)
meshc.point_data.scalars = sc
meshc.point_data.scalars.name = 'scalars'
mlab.pipeline.surface(
meshc, opacity=ceil_opacity, reset_zoom=False)
# ptc =
# ptcxy = np.array([self.Gt.node[u]['polyg'].exterior.xy[0],self.Gt.node[u]['polyg'].exterior.xy[1]])
# ptcz = [self.Gs.node[self.Gt.node[u]['polyg'].vnodes[1]]['z'][1]]*len(self.Gt.node[u]['polyg'].exterior.xy[0])
# ptc = np.vstack((ptcxy,ptcz))
# nbpt = ptc.shape[1]
# pdb
# ceil = tvtk.PolyData(points=ptc.T, polys=np.arange(nbpt).reshape(1,nbpt))
# surf2 = mlab.pipeline.surface(ceil, opacity=opacity)
# import ipdb
# ipdb.set_trace()
if cyid:
if len(self.Gt.nodes()) > 0:
pk = self.Gt.pos.keys()
v = np.array(self.Gt.pos.values())
[mlab.text3d(v[ik, 0], v[ik, 1], 0.5, str(k))
for ik, k in enumerate(pk)]
# if segpt:
# seg = dict(filter(lambda x: x[0]>0,self.Gs.pos.items()))
# pt = dict(filter(lambda x: x[0]<0,self.Gs.pos.items()))
# pseg = np.array(seg.values())
# ppt = np.array(pt.values())
# [mlab.text3d(pseg[ik,0],pseg[ik,1],0.5,str(k)) for ik,k in enumerate(seg)]
# [mlab.text3d(ppt[ik,0],ppt[ik,1],3.,str(k)) for ik,k in enumerate(pt)]
f.scene.disable_render = False
return(f)
[docs] def show3(self, bdis=True, centered=True):
""" geomview display of the indoor structure
Parameters
----------
bdis boolean (default True)
boolean display (call geowview if True)
centered : boolean
if True center the layout before display
"""
pg = self.geomfile(centered=centered)
filename = pyu.getlong(self.filegeom, pro.pstruc['DIRGEOM'])
if (bdis):
#chaine = "geomview -nopanel -b 1 1 1 " + filename + " 2>/dev/null &"
chaine = "geomview -b 1 1 1 " + filename + " 2>/dev/null &"
os.system(chaine)
else:
return(filename)
return(pg)
[docs] def signature(self, iTx, iRx):
""" Determine signature between node iTx and node iRx
Parameters
----------
cy1 : int
source cycle
cy2 : int
target cycle
Returns
-------
sigarr :
signature :
Warnings
--------
This a temporary function
There is some algorithmic work to find the best way to determine signature
T4 : limit the ndt to only edges and nodes in visibility from Tx
"""
# Here we take all the vnodes >0 from the room
#
# Practically those list of nodes should depend on pTx , pRx
#
try:
self.Gi
except:
raise NameError(
'Interaction graph layout.Gi must be build before signature computation')
if isinstance(iTx, np.ndarray):
NroomTx = self.pt2ro(iTx)
elif isinstance(iTx, int):
NroomTx = iTx
else:
raise NameError('iTx must be an array or a room number')
if isinstance(iRx, np.ndarray):
NroomRx = self.pt2ro(iRx)
elif isinstance(iRx, int):
NroomRx = iRx
else:
raise NameError('iRx must be an array or a room number')
if not self.Gr.has_node(NroomTx) or not self.Gr.has_node(NroomRx):
raise AttributeError('Tx or Rx is not in Gr')
#
# .. todo:: modifier inter afin de ne pas retenir les points non diffractants
#
ndt = self.Gt.node[self.Gr.node[NroomTx]['cycle']]['inter']
ndr = self.Gt.node[self.Gr.node[NroomRx]['cycle']]['inter']
sigarr = np.array([]).reshape(2, 0)
for nt in ndt:
for nr in ndr:
addpath = False
if (type(nt) != type(nr)):
try:
path = nx.dijkstra_path(self.Gi, nt, nr)
addpath = True
except:
pass
# print'no path between ',nt,nr
elif (nt != nr):
try:
path = nx.dijkstra_path(self.Gi, nt, nr)
addpath = True
except:
pass
# print'no path between ',nt,nr
else:
addpath = True
path = [nt]
if addpath:
sigarr = np.hstack((sigarr, np.array([[0], [0]])))
for interaction in path:
it = eval(interaction)
if type(it) == tuple:
sigarr = np.hstack((sigarr,
np.array([[it[0]], [1]])))
elif it < 0:
sigarr = np.hstack((sigarr,
np.array([[it], [-1]])))
else:
sigarr = np.hstack((sigarr, np.array([[it], [2]])))
return sigarr
[docs] def plot(self, **kwargs):
""" plot the layout with shapely MultiLineString
Parameters
---------
show : boolean
fig :figure
ax :
labels : list
nodes : boolean
Returns
-------
fig, ax
Examples
--------
>>> L= Layout('Munich.lay',bbuild=False)
>>> L.plot(show=True)
"""
#fig = kwargs.pop('fig', plt.gcf())
#ax = kwargs.pop('ax', plt.gca())
fig, ax = plt.subplots(facecolor='none')
bnodes = kwargs.pop('bnodes', False)
bsegs = kwargs.pop('bsegs', True)
ax.axis(self.ax)
fig.canvas.draw()
xc = (self.ax[0] + self.ax[1])/2
yc = (self.ax[2] + self.ax[3])/2
# if isinstance(labels, bool):
# labels = ['s', 't', 'v', 'i', 'w']
# elif isinstance(labels, str):
# labels = labels
# else:
# labels = []
k = list(self.Gs.pos.keys())
v = list(self.Gs.pos.values())
kk = np.array(k)
vv = np.array(v)
w = [str(x) for x in kk]
#if 's' in labels:
# [ax.text(vv[i, 0], vv[i, 1], w[i]) for i in range(len(w))]
if bnodes:
point = ax.scatter([xc], [yc], color=[0,0,1], alpha=1)
point.set_offsets(vv)
ax.draw_artist(point)
#ax.scatter(vv[:, 0], vv[:, 1])
pdb.set_trace()
if bsegs:
ML = sh.MultiLineString(list(self._shseg.values()))
pt = np.array([l.xy for l in ML])
line, = plt.plot(pt[0,0],pt[0,1],color='k')
line.set_data(pt)
#self.pltlines(ML, color='k', fig=fig, ax=ax)
plt.show()
return fig, ax
[docs] def get_Sg_pos(self, sigarr):
""" return position of the signatures
Parameters
----------
sigarr : signature
See Also
--------
showSig
"""
signature = sigarr[0]
sposfull = np.zeros((len(signature), 2))
iz = np.nonzero(signature != 0)[0]
spos = np.array([self.Gs.pos[i] for i in signature if i != 0])
sposfull[iz, :] = spos
return (sposfull)
[docs] def plot_segments(self, lns, **kwargs):
""""
Parameters
----------
lns
*kwargs
"""
defaults = {'show': False,
'fig': None,
'ax': None,
'color': 'b',
'linewidth': 1}
for key, value in defaults.items():
if key not in kwargs:
kwargs[key] = value
if kwargs['fig'] is None:
fig = plt.figure()
ax = fig.add_subplot(111)
elif kwargs['ax'] is None:
ax = kwargs['fig'].add_subplot(111)
else:
fig = kwargs['fig']
ax = kwargs['ax']
# v1.1 nth = np.array(map(lambda n: nx.neighbors(self.Gs, n), lns))
nth = np.array(map(lambda n: self.Gs[n], lns))
nt = nth[:, 0]
nh = nth[:, 1]
# pt : 2 x Ns
pt = np.array(map(lambda n:
[self.Gs.pos[n][0], self.Gs.pos[n][1]], nt)).T
# ph : 2 x Ns
ph = np.array(map(lambda n:
[self.Gs.pos[n][0], self.Gs.pos[n][1]], nh)).T
fig, ax = plu.displot(pt, ph, fig=fig, ax=ax, color=kwargs['color'])
return fig, ax
[docs] def showSig(self, sigarr, Tx=None, Rx=None, fig=[], ax=None):
""" Show signature
Parameters
----------
Tx : np.array (2,1)
Transmitter coordinates
Rx : np.array (2,1)
Receipter coordinates
sr : boolean
show room signature
Returns
-------
fig : figure instance
ax : axes instance
lines : lines instance
Examples
--------
"""
sig = sigarr[0]
if fig == []:
fig = plt.figure()
ax = fig.add_subplot(111)
elif ax is None:
ax = fig.add_subplot(111)
lines = []
ps = self.get_Sg_pos(sigarr)
nz = np.nonzero(sig == 0)[0]
mask = np.zeros((2, len(sig)))
mask[:, nz] = 1
vertices = np.ma.masked_array(ps.T, mask)
lines.extend(ax.plot(vertices[0, :], vertices[1, :], color='k'))
if Tx != []:
itx = np.unique(sig[nz[1:-1] + 1], return_index=True)[1]
itx2 = np.kron(itx, [1, 1])
tx = ps[itx2]
tx[range(0, len(tx), 2)] = Tx
lines.extend(ax.plot(tx[:, 0], tx[:, 1], color='r'))
if Rx != []:
irx = np.unique(sig[nz[1:-1] - 1], return_index=True)[1]
irx2 = np.kron(irx, [1, 1])
rx = ps[irx2]
rx[range(0, len(rx), 2)] = Rx
lines.extend(ax.plot(rx[:, 0], rx[:, 1], color='b'))
return (fig, ax, lines)
# lines=[]
# for s in sig:
# l=[self.Gs.pos[s[ii]] for ii in xrange(len(s))]
# if Tx!=None and Rx!=None:
# l.insert(0,Tx)
# l.insert(-1,Rx)
# ls=sh.LineString(l)
# x,y=ls.xy
# lines.extend(ax.plot(x,y,'k',lw=0.1,alpha=0.2))
# return (fig,ax,lines)
# def distwall(self, p, nroom):
# """ calculate distance to wall
#
# Parameters
# ----------
#
# p : ndarray
# point coordinate
#
# nroom : int
# room number of p
#
# Returns
# -------
#
# dist
# list of distances to walls of room nroom
#
# Notes
# -----
#
# Return dist a list of all the distances to the walls of a room
#
#
# """
# pp = sh.Point(p[0], p[1])
#
# dist = []
# p0_xy = []
# p1_xy = []
#
# vnode = self.Gr.node[nroom]['cycle'].cycle
#
# # for j in range(len(Gr[nroom]['vnodes'])):
# for j in range(len(vnodes)):
# nn = self.b_Gr[5]['vnodes'][j]
# nta = G1.tahe[0, nn - 1]
# nhe = G1.tahe[1, nn - 1]
# p0 = np.array([G1.pt[0, nta], G1.pt[1, nta]])
# p1 = np.array([G1.pt[0, nhe], G1.pt[1, nhe]])
# p0_xy.insert(j, p0)
# p1_xy.insert(j, p1)
#
# pstartwll = np.array(p0_xy)
# pfinwll = np.array(p1_xy)
#
# for i in range(len(self.b_Gr[nroom]['vnodes'])):
# line_wall = sh.LineString([(pstartwll[i, 0],
# pstartwll[i, 1]), (pfinwll[i, 0], pfinwll[i, 1])])
# dist.insert(i, line_wall.distance(pp))
# return(dist)
[docs] def randTxRx(self):
"""returns random coordinates for Tx and Rx.
Returns
-------
p_Tx : numpy.ndarray
A point of the placement of the Tx
p_Rx : numpy.ndarray
A point of the placement of the Rx
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('defstr.lay')
>>> p_Tx,p_Rx = L.randTxRx()
Notes
-----
ex fn Tx_Rx_pos
"""
# self.boundary()
Tx_x = rd.uniform(self.ax[0], self.ax[1])
Tx_y = rd.uniform(self.ax[2], self.ax[3])
Rx_x = rd.uniform(self.ax[0], self.ax[1])
Rx_y = rd.uniform(self.ax[2], self.ax[3])
p_Tx = np.array([Tx_x, Tx_y])
p_Rx = np.array([Rx_x, Rx_y])
return(p_Tx, p_Rx)
def get_boundary(self):
""" get and update Layout boundary
"""
xmax = max(p[0] for p in self.Gs.pos.values())
xmin = min(p[0] for p in self.Gs.pos.values())
ymax = max(p[1] for p in self.Gs.pos.values())
ymin = min(p[1] for p in self.Gs.pos.values())
self.ax = (xmin,xmax,ymin,ymax)
[docs] def boundary(self, **kwargs) :
""" add a blank boundary around layout
Parameters
----------
percx : float
percentage of Dx for x offset calculation (default 0.15)
percy : float
percentage of Dy for y offset calculation (default 0.15)
xlim : tuple
minD : minimum distance for boundary
force : boolean
force modification of boundaries even if one boundary already
exists
minD : int
minimal distance over x and y
self.lboundary is the list of the nodes of the added boundary
self.axn is the zone without the boundary extension
self.ax is updated
Examples
--------
>>> from pylayers.gis.layout import *
>>> L = Layout('defstr.lay')
>>> L.boundary()
Notes
-----
This function calls g2npy
"""
percx = kwargs.pop('percx',0.15)
percy = kwargs.pop('percy',0.15)
xlim = kwargs.pop('xlim',())
force = kwargs.pop('force', False)
minD = kwargs.pop('minD', 10)
bg2npy = kwargs.pop('bg2npy', True)
if not self.hasboundary or force:
if xlim != ():
xmin = xlim[0]
xmax = xlim[1]
ymin = xlim[2]
ymax = xlim[3]
elif len(self.Gs.pos.values()) != 0:
xmax = max(p[0] for p in self.Gs.pos.values())
xmin = min(p[0] for p in self.Gs.pos.values())
ymax = max(p[1] for p in self.Gs.pos.values())
ymin = min(p[1] for p in self.Gs.pos.values())
else:
xmin = -20.
xmax = 20.
ymin = -10.
ymax = 10.
Dx = np.maximum(xmax - xmin, minD)
Dy = np.maximum(ymax - ymin, minD)
dx = Dx * percx
dy = Dy * percy
n1 = self.add_fnod((xmin - dx, ymin - dy))
n2 = self.add_fnod((xmax + dx, ymin - dy))
n3 = self.add_fnod((xmax + dx, ymax + dy))
n4 = self.add_fnod((xmin - dx, ymax + dy))
self.lboundary = [n1, n2, n3, n4]
self.segboundary = []
ns1 = self.add_segment(n1, n2, name='_AIR')
ns2 = self.add_segment(n2, n3, name='_AIR')
ns3 = self.add_segment(n3, n4, name='_AIR')
ns4 = self.add_segment(n4, n1, name='_AIR')
self.segboundary.append(ns1)
self.segboundary.append(ns2)
self.segboundary.append(ns3)
self.segboundary.append(ns4)
self.axn = (xmin, xmax, ymin, ymax)
self.ax = (xmin - dx, xmax + dx, ymin - dy, ymax + dy)
self.display['box'] = self.ax
self.hasboundary = True
elif xlim!=():
# change points coordinates
self.Gs.pos[self.lboundary[0]] = (xlim[0], xlim[2])
self.Gs.pos[self.lboundary[1]] = (xlim[1], xlim[2])
self.Gs.pos[self.lboundary[2]] = (xlim[1], xlim[3])
self.Gs.pos[self.lboundary[3]] = (xlim[0], xlim[3])
self.ax = xlim
self.display['box'] = xlim
if bg2npy:
self.g2npy()
[docs] def off_overlay(self, dx=0, dy=0):
""" offset overlay image
Parameters
----------
dx : float
dy : float
"""
axis = (self.ax[0] + dx, self.ax[1] + dx,
self.ax[2] + dy, self.ax[3] + dy)
self.display['overlay_axis'] = axis
[docs] def scl_overlay(self, ax=1.0, ay=1.0):
""" scale overlay image
Parameters
----------
ax : float
ay : float
"""
axis = (self.ax[0] * ax, self.ax[1] * ax,
self.ax[2] * ay, self.ax[3] * ay)
self.display['overlay_axis'] = axis
[docs] def get_paths(self, nd_in, nd_fin):
""" returns the possible paths of graph Gs between two nodes.
Parameters
----------
nd_in: int
initial graph node (segment or point)
nd_fin: int
final graph node (segment or point)
Returns
-------
paths : list
paths between nd_in and nd_fin
"""
paths = gph.find_all_paths(self.Gs, nd_in, nd_fin)
return paths
[docs]def outputGi_func_test(args):
for k in range(10000):
y = k*k+k*k
return y
[docs]def outputGi_func(args):
# def outputGi_func(e, Gi_no, Gi_A, Gspos, sgsg, s2pc, s2pu):
# for k in range(10000):
# y = k*k
# # time.sleep(0.01)
# return y
def Gspos(n):
if n>0:
#return np.mean(s2pc[n].reshape(2,2),axis=0)
return np.mean(s2pc[n].toarray().reshape(2,2),axis=0)
else:
return p2pc[-n]
e = args[0]
#Gi_no = args[1]
#Gi_A = args[2]
#p2pc = args[3]
#sgsg = args[4]
#s2pc = args[5]
#s2pu = args[6]
print(e)
i0 = e[0]
i1 = e[1]
nstr0 = i0[0]
nstr1 = i1[0]
# list of authorized outputs. Initialized void
output = []
# nstr1 : segment number of central interaction
if nstr1 > 0:
# central interaction is a segment
# pseg1 = self.s2pc[nstr1,:].toarray().reshape(2, 2).T
pseg1 = s2pc[nstr1,:].toarray().reshape(2, 2).T
# pseg1 = self.s2pc[nstr1,:].data.reshape(2, 2).T
# pseg1o = self.seg2pts(nstr1).reshape(2, 2).T
# create a Cone object
cn = cone.Cone()
# if starting from segment
if nstr0 > 0:
# pseg0 = self.s2pc[nstr0,:].toarray().reshape(2, 2).T
pseg0 = s2pc[nstr0,:].toarray().reshape(2, 2).T
# pseg0 = self.s2pc[nstr0,:].data.reshape(2, 2).T
# pseg0o = self.seg2pts(nstr0).reshape(2, 2).T
# if nstr0 and nstr1 are connected segments
if sgsg[nstr0,nstr1] == 0:
# from 2 not connected segment
cn.from2segs(pseg0, pseg1)
else:
# from 2 connected segments
cn.from2csegs(pseg0, pseg1)
# if starting from a point
else:
pt = Gspos(nstr0)
cn.fromptseg(pt, pseg1)
# list all potential successors of interaction i1
ui2 = Gi_no.index(i1)
ui = np.where(Gi_A[ui2,:]!=0)[0]
i2 = [Gi_no[u] for u in ui]
# i2 = nx.neighbors(self.Gi, i1)
# how to find neighbors without network
# ngi=L.Gi.nodes()
# A=nx.adjacency_matrix(L.Gi)
# inter = ngi[10]
# u = ngi.index(inter)
# ui = A[u,:].indices
# neigh_inter = np.array([ngi[u] for u in ui])
ipoints = [x for x in i2 if len(x)==1 ]
#ipoints = filter(lambda x: len(x) == 1, i2)
pipoints = np.array([Gspos(ip[0]) for ip in ipoints]).T
# filter tuple (R | T)
#istup = filter(lambda x : type(eval(x))==tuple,i2)
# map first argument segment number
#isegments = np.unique(map(lambda x : eval(x)[0],istup))
# isegments = np.unique(
# filter(lambda y: y > 0, map(lambda x: x[0], i2)))
isegments = np.unique([x[0] for x in i2 if x[0]>0])
# if nstr0 and nstr1 are adjescent segment remove nstr0 from
# potential next interaction
# Fix 01/2017
# This is not always True if the angle between
# the two adjascent segments is < pi/2
# nb_nstr0 = self.Gs.neighbors(nstr0)
# nb_nstr1 = self.Gs.neighbors(nstr1)
# nb_nstr0 = np.array([self.s2pu[nstr0,0],self.s2pu[nstr0,1]])
# nb_nstr1 = np.array([self.s2pu[nstr1,0],self.s2pu[nstr1,1]])
nb_nstr0 = s2pu[nstr0,:].toarray()[0]
nb_nstr1 = s2pu[nstr1,:].toarray()[0]
print('nb_nstr0',nb_nstr0)
#nb_nstr0 = s2pu[nstr0,:]
#nb_nstr1 = s2pu[nstr1,:]
# common_point = np.intersect1d(nb_nstr0,nb_nstr1)
common_point = np.array([x for x in nb_nstr0 if x in nb_nstr1])
# if len(common_point) == 1:
if common_point.any():
num0 = [x for x in nb_nstr0 if x != common_point]
num1 = [x for x in nb_nstr1 if x != common_point]
p0 = Gspos(num0[0])
p1 = Gspos(num1[0])
pc = Gspos(common_point[0])
v0 = p0-pc
v1 = p1-pc
v0n = v0/np.sqrt(np.sum(v0*v0))
v1n = v1/np.sqrt(np.sum(v1*v1))
if np.dot(v0n,v1n)<=0:
isegments = np.array([ x for x in isegments if x != nstr0 ])
# filter(lambda x: x != nstr0, isegments))
# there are one or more segments
# if len(isegments) > 0:
if isegments.any():
li1 = len(i1)
points = self.s2pc[isegments,:].toarray().T
#points = s2pc[isegments,:].T
# points = self.s2pc[isegments,:].data.reshape(4,len(isegments))
# pointso = self.seg2pts(isegments)
pta = points[0:2, :]
phe = points[2:, :]
# add difraction points
# WARNING Diffraction points are added only if a segment is seen
# it should be the case in 99% of cases
if len(ipoints) > 0:
isegments = np.hstack(
(isegments, np.array(ipoints)[:, 0]))
pta = np.hstack((pta, pipoints))
phe = np.hstack((phe, pipoints))
# cn.show()
# if i0 == (38,79) and i1 == (135,79,23):
# printi0,i1
# import ipdb
# ipdb.set_trace()
# i1 : interaction T
if li1 == 3:
typ, prob = cn.belong_seg(pta, phe)
# if bs.any():
# plu.displot(pta[:,bs],phe[:,bs],color='g')
# if ~bs.any():
# plu.displot(pta[:,~bs],phe[:,~bs],color='k')
# i1 : interaction R --> mirror
elif li1 == 2:
Mpta = geu.mirror(pta, pseg1[:, 0], pseg1[:, 1])
Mphe = geu.mirror(phe, pseg1[:, 0], pseg1[:, 1])
typ, prob = cn.belong_seg(Mpta, Mphe)
# printi0,i1
# if ((i0 == (6, 0)) & (i1 == (7, 0))):
# pdb.set_trace()
# if bs.any():
# plu.displot(pta[:,bs],phe[:,bs],color='g')
# if ~bs.any():
# plu.displot(pta[:,~bs],phe[:,~bs],color='m')
# plt.show()
# pdb.set_trace())
########
# SOMETIMES PROBA IS 0 WHEREAS SEG IS SEEN
###########
# # keep segment with prob above a threshold
# isegkeep = isegments[prob>0]
# # dict {numint : proba}
# dsegprob = {k:v for k,v in zip(isegkeep,prob[prob>0])}
# 4 lines are replaced by
# keep segment with prob above a threshold
utypseg = typ != 0
isegkeep = isegments[utypseg]
# dict {numint : proba}
dsegprob = {k: v for k, v in zip(isegkeep, prob[utypseg])}
#########
# output = filter(lambda x: x[0] in isegkeep, i2)
output = [x for x in i2 if x[0] in isegkeep]
# probint = map(lambda x: dsegprob[x[0]], output)
probint = [dsegprob[x[0]] for x in output]
# dict interaction : proba
dintprob = {k: v for k, v in zip(output, probint)}
# keep all segment above nstr1 and in Cone if T
# keep all segment below nstr1 and in Cone if R
else:
# central interaction is a point
# 1) Simple approach
# output interaction are all visible interactions
# 2) TO BE DONE
#
# output of the diffraction points
# exploring
# b
# + right of ISB
# + right of RSB
#
# + using the wedge cone
# + using the incident cone
#
# output = nx.neighbors(self.Gi, (nstr1,))
uout = Gi_no.index((nstr1,))
ui = np.where(Gi_A[uout,:]!=0)[0]
output = [Gi_no[u] for u in ui]
nout = len(output)
probint = np.ones(nout) # temporarybns
dintprob = {k: v for k, v in zip(output, probint)}
return (i0,i1, {'output':dintprob})
# self.Gi.add_edge(i0, i1, output=dintprob)
if __name__ == "__main__":
plt.ion()
doctest.testmod()
# L = Layout('Servon Sur Vilaine',verbose=True,dist_m=60)
# L.build()