Skip to content

Distance to public green

More about green access

In this notebook we will compute a distance lattice for the public greenenrey in the nearby neighborhood of the building.

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 scipy.interpolate import RegularGridInterpolator

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)
print(stencil)
[[[0 0 0]
  [0 1 0]
  [0 0 0]]

 [[0 1 0]
  [1 0 1]
  [0 1 0]]

 [[0 0 0]
  [0 1 0]
  [0 0 0]]]

0.3. Load the envelope lattice as the avialbility lattice

# loading the lattice from csv
lattice_path = os.path.relpath('../data/voxelized_envelope_10.8.csv')
avail_lattice = tg.lattice_from_csv(lattice_path)
init_avail_lattice = tg.to_lattice(np.copy(avail_lattice), avail_lattice)

# loading the lattice from csv
lattice_path = os.path.relpath('../data/voxelized_envelope_3.6.csv')
avail_lattice_highres = tg.lattice_from_csv(lattice_path)

1. Distance Field Construction

1.1. Extract the connectivity graph from the lattice based on the defined stencil

# find the number of all voxels
vox_count = avail_lattice.size 
print(vox_count)
# initialize the adjacency matrix
adj_mtrx = np.zeros((vox_count,vox_count))

# Finding the index of the available voxels in avail_lattice
full_lattice = avail_lattice * 0 + 1
avail_index = np.array(np.where(full_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 = avail_lattice.find_neighbours_masked(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)
540

1.2. Compute distances on the graph

# compute the distance of all voxels to all voxels using floyd warshal algorithm
dist_mtrx = nx.floyd_warshall_numpy(g)

1.4. Construct Distance to Green Lattice

# select the corresponding row in the matrix
gr_1_dist = dist_mtrx[1]

# find the maximum valid value
max_valid = np.ma.masked_invalid(gr_1_dist).max()

# set the infinities to one more than the maximum valid values
gr_1_dist[gr_1_dist == np.inf] = max_valid + 1
# select the corresponding row in the matrix
gr_2_dist = dist_mtrx[422]

# find the maximum valid value
max_valid = np.ma.masked_invalid(gr_2_dist).max()

# set the infinities to one more than the maximum valid values
gr_2_dist[gr_2_dist == np.inf] = max_valid + 1
# select the corresponding row in the matrix
gr_3_dist = dist_mtrx[506]

# find the maximum valid value
max_valid = np.ma.masked_invalid(gr_3_dist).max()

# set the infinities to one more than the maximum valid values
gr_3_dist[gr_3_dist == np.inf] = max_valid + 1
# finding the minimum distance between two entrance 
# fields (aka finding the closest entrance and replacing 
# the distance with the distance to that entrance)
gr_dist_temp1 = np.minimum(gr_1_dist, gr_2_dist)
gr_dist = np.minimum(gr_dist_temp1, gr_3_dist)

# mapping the values from (0, max) to (1, 0)
gr_flat = 1 - gr_dist / np.max(gr_dist)

# constructing the lattice
gr_acc_lattice = tg.to_lattice(gr_flat.reshape(avail_lattice.shape), avail_lattice)
### 1.5. Interpolation
def interpolate(info_lowres, base_highres):
    # line spaces
    x_space = np.linspace(info_lowres.minbound[0], info_lowres.maxbound[0],info_lowres.shape[0])
    y_space = np.linspace(info_lowres.minbound[1], info_lowres.maxbound[1],info_lowres.shape[1])
    z_space = np.linspace(info_lowres.minbound[2], info_lowres.maxbound[2],info_lowres.shape[2])

    # interpolation function
    interpolating_function = RegularGridInterpolator((x_space, y_space, z_space), info_lowres, bounds_error=False, fill_value=None)

    # high_res lattice
    full_lattice = base_highres + 1

    # sample points
    sample_points = full_lattice.centroids

    # interpolation
    interpolated_values = interpolating_function(sample_points)

    # lattice construction
    info_highres = tg.to_lattice(interpolated_values.reshape(base_highres.shape), base_highres)

    # nulling the unavailable cells
    info_highres *= base_highres

    return info_highres
gr_acc_highres = interpolate(gr_acc_lattice, avail_lattice_highres)

1.6. Visualize the distance lattice

# 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

# load the mesh from file
context_path = os.path.relpath('../data/extended_context.obj')
context_mesh = tm.load(context_path)

# initiating the plotter
p = pv.Plotter(notebook=True)

# Create the spatial reference
grid = pv.UniformGrid()

# Set the grid dimensions: shape because we want to inject our values
grid.dimensions = gr_acc_highres.shape
# The bottom left corner of the data set
grid.origin = gr_acc_highres.minbound
# These are the cell sizes along each axis
grid.spacing = gr_acc_highres.unit

# Add the data values to the cell data
grid.point_arrays["Green Access"] = gr_acc_highres.flatten(order="F")  # Flatten the Lattice

# adding the meshes
p.add_mesh(tri_to_pv(context_mesh), opacity=1.0, style='surface')

# adding the volume
opacity = np.array([0.0,0.6,0.6,0.6,0.6,0.6,0.6]) * 0.6
p.add_volume(grid, cmap="coolwarm", clim=[0.0, 1.0] ,opacity=opacity)

# plotting
p.show(use_ipyvtk=True)
[(1437.4594008982308, 1436.248814398231, 1449.288430048231),
 (18.23971549999999, 17.02912900000001, 30.06874465),
 (0.0, 0.0, 1.0)]

1.6. Save Entrance Access Lattice to CSV

# save the sun access latice to csv

csv_path = os.path.relpath('../data/public_greenery.csv')
ent_acc_highres.to_csv(csv_path)

Credits

__author__ = "Shervin Azadi and Pirouz Nourian"
__changes_made_by__ = "Frank Vahstal"
__license__ = "MIT"
__version__ = "1.0"
__url__ = "https://github.com/frankvahstal/spatial_computing_workshops"
__summary__ = "Spatial Computing Design Studio Workshop on Interpolation of Distance Fields for Generative Spatial Relations"