Shafts and shortest path finding
In this notebook, we will first place the agents in an optimal place by loading in previously computed csv's. Next, we will manually place shafts to make sure that there will be a shaft on the highest floor levels. Finally, we will compute shortest paths between: 1. an agent and a shaft 2. a shaft and another shaft on the ground floor 3. a shaft and another shaft on a higher floor level
The inputs of this notebook are the final voxelized envelope, the full voxelized envelope and the immediate context. We need the full voxelized envelope without the valley for computing shafts on a higher floor level. The immediate context is only used for visualisation
0. Initialization
0.1. Load required libraries
import os
import topogenesis as tg
import pyvista as pv
import trimesh as tm
import numpy as np
import networkx as nx
from sklearn.cluster import KMeans
np.random.seed(0)
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
import pandas as pd
import copy
import scipy as sp
# extra import function
def lattice_from_csv(file_path):
# read metadata
meta_df = pd.read_csv(file_path, nrows=3)
shape = np.array(meta_df['shape'])
unit = np.array(meta_df['unit'])
minbound = np.array(meta_df['minbound'])
# read lattice
lattice_df = pd.read_csv(file_path, skiprows=5)
# create the buffer
buffer = np.array(lattice_df['value']).reshape(shape)
# create the lattice
l = tg.to_lattice(buffer, minbound=minbound, unit=unit)
return l
0.2. Define the Neighborhood (Stencil)
# creating neighborhood definition
stencil = tg.create_stencil("von_neumann", 1, 1)
# setting the center to zero
stencil.set_index([0,0,0], 0)
# creating neighborhood definition
stencil2 = tg.create_stencil("von_neumann", 1, 1)
# setting the center to zero
stencil2.set_index([0, 0, 0], 0)
stencil2.set_index([0, 0, 1], 0)
stencil2.set_index([0, 0, -1], 0)
# creating neighborhood definition - center with 0 neighbours
s_z = tg.create_stencil("von_neumann", 0, 1)
# setting the center to zero
s_z.set_index([0, 0, 0], 0)
# setting z neighbours to 1
s_z.set_index([0, 0,-1], 1)
s_z.set_index([0, 0, 1], 1)
# creating neighborhood definition - center with 1x neighbours
s_xy = tg.create_stencil("von_neumann", 1, 1)
# setting the center to zero
s_xy.set_index([0, 0, 0], 0)
# setting z neighbours to 0
s_xy.set_index([0, 0, 1], 0)
s_xy.set_index([0, 0, -1], 0)
0.3. Load the envelope lattice as the avialbility lattice
# loading the envelope lattice from csv
lattice_path = os.path.relpath('../data/final_envelope_new.csv')
avail_lattice = lattice_from_csv(lattice_path)
init_avail_lattice = tg.to_lattice(np.copy(avail_lattice), avail_lattice)
# loading the lattice full lattice from csv
lattice_path = os.path.relpath('../data/envelope_highres_new.csv')
full_lattice = lattice_from_csv(lattice_path)
init_full_lattice = tg.to_lattice(np.copy(full_lattice), full_lattice)
#loading the immediate context as obj
immediate_context = os.path.relpath('../data/immediate_context.obj')
immediate_context_mesh = tm.load(immediate_context)
0.4. Load Agents Information
# loading program (agents information) from CSV
prgm_path = os.path.relpath('../data/program.csv')
agn_info = np.genfromtxt(prgm_path, delimiter=',')[1:, 1:]
# extract agent ids
agn_ids = agn_info[:, 0]
# extract agent preferences
agn_prefs = agn_info[:, 1:]
# extract agent preference to expand in the z-direction
agn_expandz = agn_info[:, 38]
# extract maximum voxels of each agent agent. This represents the maximu8m area & volume
agn_vox_req = agn_info[:, 39]
agn_silent_level = agn_info[:, 43]
agn_noise_repel = agn_info[:, 44]
agn_info_df = pd.read_csv('../data/program.csv')
#print (agn_info_df["student_housing_acc"])
# loading the lattice from csv
sun_acc_path = os.path.relpath('../data/sun_access_highres.csv')
sun_acc_lattice = lattice_from_csv(sun_acc_path)
# loading the lattice from csv
ent1_acc_path = os.path.relpath('../data/ent1_access.csv')
ent1_acc_lattice = lattice_from_csv(ent1_acc_path)
# loading the lattice from csv
ent2_acc_path = os.path.relpath('../data/ent2_access.csv')
ent2_acc_lattice = lattice_from_csv(ent2_acc_path)
# loading the lattice from csv
ent3_1_acc_path = os.path.relpath('../data/ent3.1_access.csv')
ent3_1_acc_lattice = lattice_from_csv(ent3_1_acc_path)
# loading the lattice from csv
ent3_2_acc_path = os.path.relpath('../data/ent3.2_access.csv')
ent3_2_acc_lattice = lattice_from_csv(ent3_2_acc_path)
# loading the lattice from csv
ent3_3_acc_path = os.path.relpath('../data/ent3.3_access.csv')
ent3_3_acc_lattice = lattice_from_csv(ent3_3_acc_path)
# loading the lattice from csv
ent4_acc_path = os.path.relpath('../data/ent4_access.csv')
ent4_acc_lattice = lattice_from_csv(ent4_acc_path)
# loading the lattice from csv
ent5_acc_path = os.path.relpath('../data/ent5_access.csv')
ent5_acc_lattice = lattice_from_csv(ent5_acc_path)
# loading the lattice from csv
ent6_acc_path = os.path.relpath('../data/ent6_access.csv')
ent6_acc_lattice = lattice_from_csv(ent6_acc_path)
# loading the lattice from csv
ent7_acc_path = os.path.relpath('../data/ent7_access.csv')
ent7_acc_lattice = lattice_from_csv(ent7_acc_path)
# loading the lattice from csv
noise_acc_path = os.path.relpath('../data/HeerBokelweg_noise.csv')
noise_acc_lattice = lattice_from_csv(noise_acc_path)
# loading the lattice from csv
public_green_acc_path = os.path.relpath('../data/public_greenery_highres.csv')
public_green_acc_lattice = lattice_from_csv(public_green_acc_path)
# loading the lattice from csv
intern_green_acc_path = os.path.relpath('../data/green_openings_3.6.csv')
intern_green_acc_lattice = lattice_from_csv(intern_green_acc_path)
# loading the lattice from csv
intern_facade_acc_path = os.path.relpath('../data/inner_facade_acces.csv')
intern_facade_acc_lattice = lattice_from_csv(intern_facade_acc_path)
# loading the lattice from csv
ent6test_acc_path = os.path.relpath('../data/ent6test1.csv')
ent6test_acc_lattice = lattice_from_csv(ent6test_acc_path)
env_info_dict = {
#"ent1_acces": "" ,
#"ent2_acces": "" ,
#"ent3_acces": "" ,
#"ent4_acces": "" ,
#"ent5_acces": "" ,
#"ent6_acces": "" ,
#"ent7_acces": "" ,
#"student_housing_acc": "" ,
#"assisted_living_acc": "" ,
#"starter_housing_acc": "" ,
#"restaurant_acc": "" ,
#"shop_acc": "" ,
#"cocooking_acc": "" ,
#"pub_acc": "" ,
#"gym_acc": "" ,
#"arcade_acc": "" ,
#"cinema_acc": "" ,
#"office_acc": "" ,
#"cowork_acc": "" ,
#"library_acc": "" ,
#"fablabs_acc": "" ,
#"catering_acc": "" ,
#"catering2_acc": "" ,
#"catering3_acc": "" ,
#"coffeehub_acc": "" ,
#"expandz": "" ,
#"vox_req": "" ,
"noise_acc": noise_acc_lattice ,
#"public_green_acc": public_green_acc_lattice ,
#"intern_green_acc": intern_green_acc_lattice ,
#"inner_facade_acc": intern_facade_acc_lattice ,
}
env_info_list = []
env_info_dict_copy = env_info_dict. copy()
env_info_list.append(env_info_dict_copy)
env_info_base = copy.deepcopy(env_info_list)
0.5. Extract the connectivity graph
# find the neighbours in the lattice
def find_neighbours_masked(lattice, stencil, loc):
neigh_locs = np.argwhere(stencil) - stencil.origin + loc
neigh_filter = np.all(neigh_locs > -1, axis=1) * np.all(neigh_locs < np.array(lattice.shape), axis=1)
neigh_3d = neigh_locs[neigh_filter]
neigh_1d = [np.ravel_multi_index(n_loc, avail_lattice.shape) for n_loc in neigh_3d]
return(neigh_1d)
# find the number of all voxels
vox_count = avail_lattice.size
# initialize the adjacency matrix
adj_mtrx = np.zeros((vox_count,vox_count))
# Finding the index of the available voxels in avail_lattice
avail_index = np.array(np.where(avail_lattice == 1)).T
# fill the adjacency matrix using the list of all neighbours
for vox_loc in avail_index:
# find the 1D id
vox_id = np.ravel_multi_index(vox_loc, avail_lattice.shape)
# retrieve the list of neighbours of the voxel based on the stencil
vox_neighs = find_neighbours_masked(avail_lattice, stencil, loc = vox_loc)
# iterating over the neighbours
for neigh in vox_neighs:
# setting the entry to one
adj_mtrx[vox_id, neigh] = 1.0
# construct the graph
g = nx.from_numpy_array(adj_mtrx)
# import the adj matrix
import pickle
dist_mtrx_loaded = pickle.load( open( "../data/dist_mtrx.p", "rb" ) )
1. Give the agents an optimal location
1.1. Agent initialization
# initialize the occupation lattice
occ_lattice = avail_lattice * 0 - 1
# Finding the index of the available voxels in avail_lattice
avail_flat = avail_lattice.flatten()
avail_index = np.array(np.where(avail_lattice == 1)).T
# count the number of spaces (rows) and intiialize an agent for each space
agn_num = len(agn_info)
# adding the origins to the agents locations
agn_locs = []
# retrieving the entrance access value of the free neighbours
for a_id in agn_ids:
voxel_vals = []
pot_voxels = []
# retrieve agent preferences;
a_pref = agn_prefs[int(a_id)]
a_pref_dict = agn_info_df.loc[a_id]
# Voxel Evaluation Loop
for pot_vox in avail_index:
if avail_lattice[tuple(pot_vox)]:
global_vox_value = 1.0
# for every lattice in the environment informations
for info_key, info_lattice in env_info_dict.items():
vox_val = info_lattice[tuple(pot_vox)]
print(vox_val)
# agn_vox_val = np.power(vox_val, a_pref[i])
agn_vox_val = np.power(vox_val, a_pref_dict[info_key])
global_vox_value *= agn_vox_val
# add the neighbour value to the list of values
voxel_vals.append(global_vox_value)
pot_voxels.append(pot_vox)
# convert to numpy array
voxel_vals = np.array(voxel_vals)
# convert to numpy array
pot_voxels = np.array(pot_voxels)
# select the neighbour with highest value
selected_int = np.argmax(voxel_vals)
# find 3D intiger index of selected neighbour
selected_neigh_3d_id = tuple(pot_voxels[selected_int].T)
# find the location of the newly selected neighbour
selected_neigh_loc = np.array(selected_neigh_3d_id).flatten()
# add the newly selected neighbour location to agent locations
agn_locs.append([selected_neigh_loc])
# set the newly selected neighbour as UNavailable (0) in the availability lattice
avail_lattice[selected_neigh_3d_id] = 0
# set the newly selected neighbour as OCCUPIED by current agent
occ_lattice[selected_neigh_3d_id] = a_id
def dynamic_noise_lattice(agn_locs, avail_lattice):
# define the noise range
noise_range = [10.0, 60.0]
# initialize noise sources
noise_src_points = []
noise_src_levels = []
# iterate over agents
for a_id in range(len(agn_locs)):
# extract agent locations
a_locs = agn_locs[a_id]
# retrieve the silent level of the agent
a_noise_level_mapped = 1 - agn_data.loc[a_id]["silent_level"]
# mapping the [0,1] values to noise level (db)
a_noise_level = a_noise_level_mapped * (noise_range[1] - noise_range[0]) + noise_range[0]
# for each agent location
for a_loc in a_locs:
# append the noise source information
noise_src_points.append(a_loc)
noise_src_levels.append(a_noise_level)
# convert to numpy array
noise_src_points = np.array(noise_src_points)
# create full lattice
full_lattice = avail_lattice * 0 + 1
# extract the coordiantes of the centroid of all voxel
vox_centroids = full_lattice.centroids
# extract voxel indices of all voxels
vox_indices = np.array(np.where(full_lattice==1)).T
# initializing the sum lattice of noise
sum_noise_lats = avail_lattice * 0.0
# for each source of noise
for src_point, src_level in zip(noise_src_points,noise_src_levels):
# initialize the occupation lattice
dist_latice = avail_lattice * 0.0
for cen, ind in zip(vox_centroids, vox_indices):
# compute the euclidian distance
dist_latice[tuple(ind)] = sp.spatial.distance.euclidean(cen, src_point)
# computing the noise lattice from dist lattice
noise_latice = src_level - 20 * np.log10(dist_latice) - 8
# summing
sum_noise_lats += np.power(10, noise_latice / 10.0)
# computing the final aggregation
agg_noise_lats = 10 * np.log10(sum_noise_lats)
# normalizing the noise values
normalized_silence_lattice = 1 - (agg_noise_lats - np.min(agg_noise_lats)) / (np.max(agg_noise_lats) - np.min(agg_noise_lats))
return normalized_silence_lattice
1.2. Visualizing the agents seeds
p = pv.Plotter(notebook=True)
base_lattice = occ_lattice
# Set the grid dimensions: shape + 1 because we want to inject our values on the CELL data
grid = pv.UniformGrid()
grid.dimensions = np.array(base_lattice.shape) + 1
# The bottom left corner of the data set
grid.origin = base_lattice.minbound - base_lattice.unit * 0.5
# These are the cell sizes along each axis
grid.spacing = base_lattice.unit
# adding the avilability lattice
init_avail_lattice.fast_vis(p)
# convert mesh to pv_mesh
def tri_to_pv(tri_mesh):
faces = np.pad(tri_mesh.faces, ((0, 0),(1,0)), 'constant', constant_values=3)
pv_mesh = pv.PolyData(tri_mesh.vertices, faces)
return pv_mesh
# adding the meshes
p.add_mesh(tri_to_pv(immediate_context_mesh), color='#aaaaaa')
# Add the data values to the cell data
grid.cell_arrays["Agents"] = base_lattice.flatten(order="F").astype(int) # Flatten the array!
# filtering the voxels
threshed = grid.threshold([-0.1, agn_num - 0.9])
# adding the voxels
p.add_mesh(threshed, name='sphere', show_edges=True, opacity=1.0, show_scalar_bar=False)
# p.add_slider_widget(create_mesh, [0, n_frames], title='Time', value=0, event_type="always", style="classic", pointa=(0.1, 0.1), pointb=(0.9, 0.1))
p.show(use_ipyvtk=True)
2. Creation of vertical shaft
2.1. Manually set cluster center
# manually set cluster centers
cluster_center_manual = {
0: [[10,12,1]],
1: [[23,18,1]],
2: [[35,10,1]],
3: [[13,6,1]],
4: [[21,6,1]],
5: [[19,12,1]],
6: [[35,4,1]],
7: [[35,17,1]],
}
cluster_center_0 = cluster_center_manual[0]
cluster_center_1 = cluster_center_manual[1]
cluster_center_2 = cluster_center_manual[2]
cluster_center_3 = cluster_center_manual[3]
cluster_center_4 = cluster_center_manual[4]
cluster_center_5 = cluster_center_manual[5]
cluster_center_6 = cluster_center_manual[6]
cluster_center_7 = cluster_center_manual[7]
cluster_center = cluster_center_0 + cluster_center_1 + cluster_center_2 + cluster_center_3 + cluster_center_4 + cluster_center_5 + cluster_center_6 + cluster_center_7 #+ cluster_center_8
# let the cluster center go in the z direction
shft_lattice = occ_lattice * 0
for cl_cen in cluster_center:
shft_lattice[cl_cen[0],cl_cen[1],:] = 1
shft_lattice *= init_avail_lattice
2.2. Visualize Vertical Shafts
base_lattice = shft_lattice
# Set the grid dimensions: shape + 1 because we want to inject our values on the CELL data
grid = pv.UniformGrid()
grid.dimensions = np.array(base_lattice.shape) + 1
# The bottom left corner of the data set
grid.origin = base_lattice.minbound - base_lattice.unit * 0.5
# These are the cell sizes along each axis
grid.spacing = base_lattice.unit
# adding the avilability lattice
init_avail_lattice.fast_vis(p)
# convert mesh to pv_mesh
def tri_to_pv(tri_mesh):
faces = np.pad(tri_mesh.faces, ((0, 0),(1,0)), 'constant', constant_values=3)
pv_mesh = pv.PolyData(tri_mesh.vertices, faces)
return pv_mesh
# adding the meshes
p.add_mesh(tri_to_pv(immediate_context_mesh), style = 'surface')
# Add the data values to the cell data
grid.cell_arrays["Agents"] = base_lattice.flatten(order="F").astype(int) # Flatten the array!
# filtering the voxels
threshed = grid.threshold([0.9, 1.1])
# adding the voxels
p.add_mesh(threshed, name='sphere', show_edges=True, opacity=1.0, show_scalar_bar=False)
p.show(use_ipyvtk=True)
3. Creation of Horizontal Corridors
3.1. Extract the connectivity graph from the lattice based on the horizontal stencil
# Extract the connectivity graph of the envelope lattice
def find_neighbours_masked(lattice, stencil, loc):
neigh_locs = np.argwhere(stencil) - stencil.origin + loc
neigh_filter = np.all(neigh_locs > -1, axis=1) * np.all(neigh_locs < np.array(lattice.shape), axis=1)
neigh_3d = neigh_locs[neigh_filter]
neigh_1d = [np.ravel_multi_index(n_loc, avail_lattice.shape) for n_loc in neigh_3d]
return(neigh_1d)
# find the number of all voxels
vox_count = avail_lattice.size
# initialize the adjacency matrix
adj_mtrx = np.zeros((vox_count,vox_count))
# Finding the index of the available voxels in avail_lattice
avail_index = np.array(np.where(avail_lattice == 1)).T
# fill the adjacency matrix using the list of all neighbours
for vox_loc in avail_index:
# find the 1D id
vox_id = np.ravel_multi_index(vox_loc, avail_lattice.shape)
# retrieve the list of neighbours of the voxel based on the stencil
vox_neighs = find_neighbours_masked(init_avail_lattice, stencil, loc = vox_loc)
# iterating over the neighbours
for neigh in vox_neighs:
# setting the entry to one
adj_mtrx[vox_id, neigh] = 1.0
# construct the graph
g = nx.from_numpy_array(adj_mtrx)
occ_ind = np.array(np.where(occ_lattice > -1)).T
3.2. Find the shortest path between an agent and a shaft and construct the corridor
# initialize corridor lattice
cor_lattice = shft_lattice * 0
cor_flat = cor_lattice.flatten()
# for each voxel that needs to have access to shafts
for a_vox in occ_ind:
# slice the corridor lattice horizontally
# add the previously created corridors as competing destination to shafts
cor_floor = shft_lattice[:,:,a_vox[2]] + cor_lattice[:,:,a_vox[2]]
# find the vertical shaft voxel indices
shaft_vox_inds = np.array(np.where(cor_floor > 0)).T
paths = []
path_lens = []
for shft_ind in shaft_vox_inds:
# construct the destination address
dst_vox = np.array([shft_ind[0],shft_ind[1],a_vox[2]])
# construct 1-dimensional indices
src_ind = np.ravel_multi_index(a_vox, shft_lattice.shape)
dst_ind = np.ravel_multi_index(dst_vox, shft_lattice.shape)
# find the shortest path
try:
path = nx.algorithms.shortest_paths.astar.astar_path(g, src_ind, dst_ind)
paths.append(path)
path_lens.append(len(path))
except:
print("disconnected:", a_vox, init_avail_lattice[tuple(a_vox)], dst_vox, init_avail_lattice[tuple(dst_vox)])
path_order = np.array(path_lens).argsort()
if len(paths) > 0:
shortest_path = paths[path_order[0]]
# set the shortest path occupied in the
cor_flat[shortest_path] = 1
# reshape the flat lattice
cor_lattice = cor_flat.reshape(cor_lattice.shape)
3.3. Find the shortest paths between the shafts on the ground floor
# find the shortest path between them
cor_lattice2 = shft_lattice * 0
# initialize corridor lattice
cor_flat = cor_lattice2.flatten()
# slice the corridorlattice horizontally (same z value)
cor_floor = shft_lattice[:,:,1] + cor_lattice[:,:,a_vox[2]]
# find the vertical shaft voxel indices
shaft_vox_inds = np.array(np.where(cor_floor > 0)).T
# for each voxel that needs to have access to shafts
for src_shft_ind in shaft_vox_inds:
#find the distance and the path to every other shaft
paths = []
path_lens = []
for dst_shft_ind in shaft_vox_inds:
# construct the destination address
src_vox = np.array([src_shft_ind[0],src_shft_ind[1],0])
dst_vox = np.array([dst_shft_ind[0],dst_shft_ind[1],0])
# construct 1-dimensional indices
src_ind = np.ravel_multi_index(src_vox, shft_lattice.shape)
dst_ind = np.ravel_multi_index(dst_vox, shft_lattice.shape)
try:
path = nx.algorithms.shortest_paths.astar.astar_path(g, src_ind, dst_ind)
#regel hieronder
if len(path) > 1:
paths.append(path)
path_lens.append(len(path))
except:
pass
path_order = np.array(path_lens).argsort()
if len(paths) > 0:
shortest_path = paths[path_order[0]]
cor_flat[shortest_path] = 1
if len(paths) > 1:
snd_shortest_path = paths[path_order[1]]
cor_flat[snd_shortest_path] = 1
cor_lattice2 = cor_flat.reshape(cor_lattice2.shape)
3.4. Find the shortest paths between the shafts on the third floor
3.4.1. Extract the connectivity graph
# Extract the connectivity graph of the full envelope
def find_neighbours_masked(lattice, stencil, loc):
neigh_locs = np.argwhere(stencil) - stencil.origin + loc
neigh_filter = np.all(neigh_locs > -1, axis=1) * np.all(neigh_locs < np.array(lattice.shape), axis=1)
neigh_3d = neigh_locs[neigh_filter]
neigh_1d = [np.ravel_multi_index(n_loc, full_lattice.shape) for n_loc in neigh_3d]
return(neigh_1d)
# find the number of all voxels
vox_count = full_lattice.size
# initialize the adjacency matrix
adj_mtrx = np.zeros((vox_count,vox_count))
# Finding the index of the available voxels in avail_lattice
full_index = np.array(np.where(full_lattice == 1)).T
# fill the adjacency matrix using the list of all neighbours
for vox_loc in full_index:
# find the 1D id
vox_id = np.ravel_multi_index(vox_loc, full_lattice.shape)
# retrieve the list of neighbours of the voxel based on the stencil
vox_neighs = find_neighbours_masked(init_full_lattice, stencil, loc = vox_loc)
# iterating over the neighbours
for neigh in vox_neighs:
# setting the entry to one
adj_mtrx[vox_id, neigh] = 1.0
# construct the graph
g = nx.from_numpy_array(adj_mtrx)
occ_ind = np.array(np.where(occ_lattice > -1)).T
3.4.2 Find the shortest path and create the corridors
# find the shortest path between them
cor_lattice3 = shft_lattice * 0
# initialize corridor lattice
cor_flat = cor_lattice3.flatten()
# slice the corridorlattice horizontally (same z value)
cor_floor = shft_lattice[:,:,1] + cor_lattice3[:,:,a_vox[2]]
# find the vertical shaft voxel indices
shaft_vox_inds = np.array(np.where(cor_floor > 0)).T
# for each voxel that needs to have access to shafts
for src_shft_ind in shaft_vox_inds:
#find the distance and the path to every other shaft
paths = []
path_lens = []
for dst_shft_ind in shaft_vox_inds:
# construct the destination address
src_vox = np.array([src_shft_ind[0],src_shft_ind[1],3])
dst_vox = np.array([dst_shft_ind[0],dst_shft_ind[1],3])
# construct 1-dimensional indices
src_ind = np.ravel_multi_index(src_vox, shft_lattice.shape)
dst_ind = np.ravel_multi_index(dst_vox, shft_lattice.shape)
try:
path = nx.algorithms.shortest_paths.astar.astar_path(g, src_ind, dst_ind)
#regel hieronder
if len(path) > 1:
paths.append(path)
path_lens.append(len(path))
except:
pass
#print("disconnected:", a_vox, init_avail_lattice[tuple(a_vox)], dst_vox, init_avail_lattice[tuple(dst_vox)])
path_order = np.array(path_lens).argsort()
if len(paths) > 0:
shortest_path = paths[path_order[0]]
# set the shortest path occupied in the
cor_flat[shortest_path] = 1
if len(paths) > 1:
snd_shortest_path = paths[path_order[1]]
cor_flat[snd_shortest_path] = 1
cor_lattice3 = cor_flat.reshape(cor_lattice3.shape)
final_lattice = shft_lattice + cor_lattice + cor_lattice2 + cor_lattice3
3.5. Visualize the accessability lattice
p = pv.Plotter(notebook=True)
base_lattice = final_lattice
# Set the grid dimensions: shape + 1 because we want to inject our values on the CELL data
grid = pv.UniformGrid()
grid.dimensions = np.array(base_lattice.shape) + 1
# The bottom left corner of the data set
grid.origin = base_lattice.minbound - base_lattice.unit * 0.5
# These are the cell sizes along each axis
grid.spacing = base_lattice.unit
# adding the avilability lattice
#avail_lattice.fast_vis(p)
# convert mesh to pv_mesh
def tri_to_pv(tri_mesh):
faces = np.pad(tri_mesh.faces, ((0, 0),(1,0)), 'constant', constant_values=3)
pv_mesh = pv.PolyData(tri_mesh.vertices, faces)
return pv_mesh
# adding the meshes
p.add_mesh(tri_to_pv(immediate_context_mesh), style = 'surface')
# Add the data values to the cell data
grid.cell_arrays["Agents"] = base_lattice.flatten(order="F").astype(int) # Flatten the array!
# filtering the voxels
threshed = grid.threshold([0.9, 2.1])
# adding the voxels
p.add_mesh(threshed, name='sphere', show_edges=True, opacity=1.0, show_scalar_bar=False, cmap="tab20")
p.show(use_ipyvtk=True)
3.6. Save as csv
# save the corridor lattice as a csv
csv_path = os.path.relpath('../data/corridors_bridges_new.csv')
final_lattice.to_csv(csv_path)
Credits
__author__ = "Shervin Azadi and Pirouz Nourian"
__changes_made_by__ = "Lotte Zwolsman"
__license__ = "MIT"
__version__ = "1.0"
__url__ = "https://github.com/frankvahstal/spatial_computing_workshops"
__summary__ = "Spatial Computing Design Studio Workshop on Path Finding and Corridorfor Generative Spatial Relations"