Shadowing Envelope
0. Initialization
importing all necessary libraries and specifying the inputs
import os
import topogenesis as tg
import pyvista as pv
import trimesh as tm
import numpy as np
# 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
1. Import Meshes
1.1 Load Meshes
envelope_path = os.path.relpath('../data/meshes/compulsory_envelope.obj')
context_path = os.path.relpath('../data/meshes/immediate_context.obj')
# load the mesh from file
envelope_mesh = tm.load(envelope_path)
context_mesh = tm.load(context_path)
# Check if the mesh is watertight
print(envelope_mesh.is_watertight)
print(context_mesh.is_watertight)
1.2 Visualize Meshes
# initiating the plotter
p = pv.Plotter(notebook=True)
# adding the meshes
p.add_mesh(tri_to_pv(envelope_mesh), color='#abd8ff')
p.add_mesh(tri_to_pv(context_mesh), color='#aaaaaa')
# plotting
# p.show()
2. Import Lattice
2.1. Load both the Envelope and Shadow Lattice
# loading the lattice from csv
lattice = os.path.relpath('../data/meshes/voxelized_envelope_highres.csv')
envelope_lattice = tg.lattice_from_csv(lattice)
2.2. Visualize the Envelope Lattice
# initiating the plotter
p = pv.Plotter()
# fast visualization of the lattice
envelope_lattice.fast_vis(p)
# adding the meshes
p.add_mesh(tri_to_pv(context_mesh), color='#aaaaaa')
# plotting
# p.show()
2.3 Store shadowing information in a Lattice
# Loading the shadow lattice from csv
shadow_lattice = os.path.relpath('../data/fields/shadowing.csv')
shadow_envelope_lattice = tg.lattice_from_csv(shadow_lattice)
2.4. Visualize the shadowing
# initiating the plotter
p = pv.Plotter(notebook=True)
l = shadow_envelope_lattice
# remapping
l = 250 * (l - l.min()) / l.max()
# Create the spatial reference
grid = pv.UniformGrid()
# Set the grid dimensions: shape because we want to inject our values
grid.dimensions = l.shape
# The bottom left corner of the data set
grid.origin = l.minbound
# These are the cell sizes along each axis
grid.spacing = l.unit
# Add the data values to the cell data
grid.point_arrays["Shadowing"] = l.flatten(order="F") # Flatten the Lattice
# adding the meshes
p.add_mesh(tri_to_pv(context_mesh), opacity=0.1, style='wireframe')
# adding the volume
opacity = np.array([0,0.6,0.6,0.6,0.6,0.6,0.6])*1.5
p.add_volume(grid, cmap="coolwarm", clim=[0.5, 1.0],opacity=opacity, shade=True)
# plotting
p.show()
3. Remove Result in shadow Lattice
3.0. Interpolating the shadowing result into higher resolution
3.1. Defining maximum shadowing
# defining the shadow envelope lattice with values calcultated in shadowing
shadow_envelope_lattice
# shadowing treshold
shadowing_treshold = 0.3 # number is subject to change
# removing values above set treshold and setting them to zero
new_envelope_lattice = np.where(shadow_envelope_lattice > shadowing_treshold,0,shadow_envelope_lattice)
# set all usable values to 1
usable_lattice = np.where(new_envelope_lattice > 0, 1,new_envelope_lattice)
usable_lattice = usable_lattice.astype(bool)
usable_lattice = tg.to_lattice(usable_lattice, shadow_envelope_lattice)
usable_lattice.shape
3.2. Visualization of leftover voxels
p = pv.Plotter(notebook=True)
base_lattice = usable_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 boundingbox wireframe
p.add_mesh(grid.outline(), color="grey", label="Domain")
# # adding the availability lattice
# init_avail_lattice.fast_vis(p)
# adding the meshes
p.add_mesh(tri_to_pv(context_mesh), color='#aaaaaa')
# adding axes
p.add_axes()
p.show_bounds(grid="back", location="back", color="#aaaaaa")
def create_mesh(value):
lattice = (shadow_envelope_lattice < value) * envelope_lattice
# Add the data values to the cell data
grid.cell_arrays["Agents"] = 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)
return
p.add_slider_widget(create_mesh, [0, 1.0], title='Time', value=0, event_type="always", style="classic")
#plotting
cpos = [(314.348192231551, 283.381630231551, 296.74455709155103),
(65.08283250000001, -12.333572500000002, 21.07374465),
(0.0, 0.0, 1.0)]
p.camera_position = cpos
p.window_size = 2000, 1000
p.show(use_ipyvtk=True)
p.screenshot("../data/images/Shadow")
print(p.camera_position)
4. Finalize Lattice work and save to csv
4.1. Save Usable Lattice inta a CSV
# # save the sun access latice to csv
csv_path = os.path.relpath('../data/meshes/useable_lattice.csv')
usable_lattice.to_csv(csv_path)