View analysis with Isovist

Danil Nagy
Generative Design
Published in
12 min readFeb 27, 2017

The methods of structural and environmental analysis described in the previous two sections aim to quantify a building’s performance based on external physical forces in the environment. A very different but equally important measure of a building’s performance is the quality of the building’s interior spaces, and how well they accommodate the building’s program and the needs and health of the building’s occupants.

Such human-level measures of space have seen major development in the last few decades. The most popular method for measuring human behavior inside architectural space is crowd simulation, which uses a series of virtual agents to simulate the perception and behavior of humans in space. This is a type of dynamic simulation which works by allowing the virtual agents to play out their behaviors over a series of time steps. While this type of analysis can provide extremely useful measures of space, its dynamic nature means that each analysis can take a long time to run. Thus it is difficult to use directly within an automated generative design workflow.

For generative design, we would like to develop a set of measures that can quantify something about the human-level perception of a space but do so statically through a single calculation. One very common technique for doing so is the isovist, which calculates how much of the space is visible from any point in the space. The isovist is computed by projecting a series of vectors from the point and seeing where the vectors intersect with geometry in the space. These points can then be connected to each other to form the total ‘volume’ of visible space. Although the isovist can be calculated as a volume in 3-dimensional space, in architectural applications it is typical to compute only the 2-dimensional isovist in a given plan, as this makes the calculation much faster.

Grasshopper provides an Isovist component for computing the 2-dimensional isovist. Let’s go through the process of setting up a basic isovist analysis using an example of a simple architectural floor plan. You can follow along by downloading this grasshopper file, which contains nodes for creating two simple floor plans, one with a single room as obstruction, and one with a grid of columns. If you get stuck along the way you can also download the final working version of the definition here.

Calculating a single isovist

To calculate a single isovist we can use Grasshopper’s Isovist component which takes in four inputs:

  • Plane (P) — the point or plane from which to compute the isovist.
  • Count (N) — the number of rays to project from the point (this controls the resolution of the isovist).
  • Radius (R) — the distance to project the rays (this controls the ‘view distance’ or the radius around the point that the isovist will consider as visible).
  • Obstacles (O) — objects which block views from the point. Since the Isovist component only works in 2-d, the obstacles are expected to be curves in the same plane as the point used for analysis.

To calculate one isovist in the basic floor plan, we first create the analysis point using the Construct Point component in Grasshopper and create two number sliders to control the point’s x and y coordinates. We connect this point to the ‘P’ input of the Isovist component. Next we specify the ’N’ input based on the desired resolution of analysis. For one isovist you can use a high resolution to create an accurate outline. However, you may want to lower this value to control computation time when we start to aggregate a series of isovist analyses over the whole floor plan. Finally we set the ‘R’ value according to the scale of our floor plan. In our case, a value of ‘500' will be large enough to capture the maximum view distance across the space.

The Isovist component outputs a list of points representing the ends of the collision vectors. To visualize the ‘area’ of visible space around the point we can connect these points directly to the ‘V’ input of a Polyline component in Grasshopper, which will create a polyline through all the points. Make sure you also set the ‘C’ input to ‘True’ so that it forms a closed curve. You can then input the polyline into a Boundary Surfaces components to create a visible surface within the polyline.

Generating an analysis grid

A single isovist provides a useful visualization of the extent of a plan that can be seen from a single point. For the purposes of generative design, however, it would be useful if we could compute a series of isovists over the whole plan and then use them to calculate a set of numerical measures of the human-level experience of the space.

As in the solar analysis example, we will perform the analysis with the help of a mesh. We will use the mesh to generate a series of test points in the plan, and then use the same mesh again to visualize the results of the analysis. In this case our mesh needs to have a regular spacing of vertices and be confined to the walkable area of the plan. To create this mesh we first use the Boundary Surfaces component to convert the plan’s boundary curves to a single planar trimmed surface, and then use the Mesh Brep component to convert the trimmed surface to a mesh.

The Mesh Brep component can convert any set of surfaces to meshes, including joined polysurfaces and trimmed surfaces as we have here. Since it needs to account for complex surface topology, this component cannot give us as much control over the vertex spacing of the resulting mesh as the Mesh UV component we saw previously. However, we can adjust some aspects of the meshing process by using a Settings (Custom) component to define a set of mesh settings and then inputting the settings into the Mesh Brep component.

In this case we will set the ‘Min Edge’ and ‘Max Edge’ settings to our desired spacing for the analysis grid. Setting this value smaller will give us a finer mesh with more sample points, while setting it larger will give us a coarser mesh with less sample points. You will have to tune this parameter later to manage the trade-off between the accuracy of the analysis and the time it takes to calculate it.

One issue with the Isovist component in Grasshopper is that it will give an error if the analysis point is located on any of the obstacle curves. Since we generated our analysis mesh directly from the obstacle curves, many of the mesh’s vertices will be located on the curves. Thus, before we use the mesh vertices as sample points for the isovist component we need to separate them according to whether they fall on the boundaries of the mesh.

To do this we can use a combination of nodes to extract the vertices of the mesh, find the vertices which are on the boundaries of the mesh, and use this information to split the vertices into two lists. First we use the Deconstruct Mesh component to extract the vertices of the analysis mesh. Then we use the Mesh Edges component to extract the edges from the mesh. This component breaks the edges into groups based on their type. In this case we are interested in the E1 edges, which are the one that only touch one face and thus occur on the boundary of the mesh. Once we have these boundary edges (also called naked edges) we can extract their end points using the End Points node, and then combine all the points into one list using the Merge node.

Now we have a list of all the points on the mesh boundary, but we really want to figure out which of the mesh vertices these points represent. To do this we use the Closest Point node to find the closest point among the list of points we just created to each of the mesh vertices. We connect the vertices of the mesh to the Point (P) input which represents the points we search from, and we connect the list of boundary points to the Cloud (C) input which represents the set of points from which the closest one will be found. Then we use the Equals node to test whether the distance between each vertex and its closest point is equal to zero, which indicates that the vertex is on the edge. Finally, we can use a Dispatch component to split the list of vertices based on whether it occurs on the edge of the mesh.

This gives us a separate list of points found inside the space which we can use for isovist analysis. We can plug these points directly into the Isovist node to produce a series of isovists over the whole space. If the Grasshopper file freezes or takes a long time to execute you may want to reduce either the resolution of the analysis mesh or the resolution of each isovist.

Extracting metrics

As you can see from the image above, simply visualizing a set of isovist geometries can be difficult to interpret. Likewise, the visualization alone does not provide us with any numerical metrics which we can use as objectives for our generative design workflow. To use isovist analysis for generative design we need to convert the geometric representation of the isovists to numerical measures that can give us a quantitative measure of the space.

There has been a large amount of research over the last 40 or so years about using isovists to extract quantitative measures from architectural space. One of the earliest was the work of M. L. Benedikt (1979), who provided a set of measures which could be extracted from isovists to quantify spatial experience. Two of the measures Benedikt focused on in particular were the area of the isovist (which describes the total amount of area visible from a point) and the perimeter length of the isovist boundary (which describes the ‘jaggedness’ or complexity of the view, or how quickly the view changes as you leave the point). These measures quantify different aspects of how a person may experience the space, and together give a fuller description of the space.

For example, a cramped space such as a hallway will have low values for both area and perimeter length. A completely open space will have high values for area and medium values for perimeter length. An open space with many obstacles such as a grid of columns will have medium values for area and high values for perimeter length. Over the years most of the research in using isovists for architectural analysis has been folded into a field of study called Space Syntax, which works on developing tools and methodologies, including those using isovists, for statically simulating spatial experience.

In this case, we will use Grasshopper’s Area and Length components to quantify the isovists according to Benedikt’s measures. As before, we can use the Mass Addition component to add up all the measures and derive a single metric for the entire space. We can then use these metrics to optimize the space according to our preferences. For example, we may want to maximize visibility while minimizing complexity to create a space that is at once open and easy to navigate.

Visualizing results

Now that we have computed a series of isovists across our floor plan and used them to calculate two measures for the space, we can visualize these measures on the floor plan using the analysis mesh we generated earlier.

The first step is to remap the area and perimeter length values we calculated earlier to a range of 0.0 to 1.0 so that we can use them to create a range of colors for visualization. We can do this by first calculating the bounds of the data using the Bounds component, and then inputting this domain as the ‘Source (S)’ input of the Remap Numbers component. This component will remap each number input into the ‘Value (V)’ input from the ‘Source (S)’ domain to the ‘Target (T)’ domain, which both default to ‘0 to 1’. This gives us a normalized range of values with the largest area and largest perimeter length normalized to 1.0 and the smallest area and perimeter length normalized to 0.0.

Now that we have these values we can use them to generate a range of colors for our mesh. Previously we used a Gradient component to map one set of values onto a gradient of colors. However, in this case we would like to visualize two separate measures on the mesh. To do this we can use the Colour RGB (f) component in Grasshopper, which composes colors based on normalized 0–1 values for each color channel (Red, Green, Blue). We can use the color channels to simultaneously represent up to three different sets of data on the mesh.

In addition to the analysis colors, we also need to account for the colors of the vertices on the edges of the mesh which we could not use in our analysis. We will set the color of these vertices to white using the Colour Swatch node in Grasshopper. To order the colors in the same way as the vertices in the original mesh we need to create a list of white color values the same size as the list of boundary points, which we can do using a combination of the List Length and Repeat components. Finally, we use the Weave component to recombine the color data in the same order as the original list of mesh vertices.

The Dispatch and Weave components are inverses of each other. While Dispatch uses a pattern of true/false booleans to split a set of data into two lists, Weave uses the pattern to put them back together. Dispatch and Weave are often used together to create complex conditionals in Grasshopper. Using these components you can first split data into two lists, perform different operations on each resulting list, and then put the data back together in the original order.

Finally, we can use the Construct Mesh component to build the visualization mesh using the vertices and edges coming from the Deconstruct Mesh component created previously and the set of colors output from the Weave component. If we use the ‘area’ measure to drive the ‘Red’ channel of the color and the ‘perimeter length’ measure to drive the ‘Green’ channel of the color we get the following result:

You can see how the two measures combine to form a variety of colors in the mesh. We can also look at the two measures separately by disconnecting one or the other input:

You can see that these images are somewhat different from each other based on the quality that they measure. In the left image, lighter regions of the floor plan are more open while darker regions are more enclosed, as measured by the area of the isovist generated at that location. In the right image, lighter regions have higher visual complexity while darker regions have lower visual complexity as measured by the length of the isovist’s perimeter. Putting the channels together, we can interpret the colors in the composite image the following ways:

  • Yellow areas (high Red and Green channels) are areas which are both very open and visually complex, for example the large open area to the left of the obstacle.
  • Orange-ish areas (higher Red than Green) are areas which are open but have lower visual complexity, for example the area at the upper left of the plan.
  • Darker yellow/mustard (higher Green than Red) are areas which are less open but have high visual complexity, for example the area in the lower left of the plan.
  • Black areas (low Red and Green channels) are areas which are both very closed and visually not complex, for example the areas directly next to the flat faces of the obstacle.

For comparison, we can perform the same visualization over the other floor plan provided, which has a large open area at the bottom and a grid of columns at the top which create more visual complexity.

As we saw in this demonstration, isovists provide a useful set of tools for quantifying a space based on how it is experienced at the human scale. A single isovist can tell us which parts of the floor plan are visible from any given location in the space. By using a set of isovists spread evenly over a floor plan, we can derive overall measures which talk about the general perception of a space. Since these measures are computed statically, we can also use them directly in the generative design workflow to optimize for better spaces over time.

--

--