-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
5_advanced_isovist_network.Rmd
109 lines (90 loc) · 4.36 KB
/
5_advanced_isovist_network.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
---
title: "Space Syntax analysis in R"
subtitle: "5. Advanced: Isovist networks"
author:
- name: "Petros Koutsolampros"
- name: "Chrystalla Psathiti"
output: html_notebook
---
This document is the fourth part of a workshop that presents a workflow for working with spatial data common to the space syntax field in the R programming language. Find all parts here:
1. [Basic functionality of R](./1_r_basics.Rmd)
2. [Spatial data and its forms](./2_spatial_data.Rmd)
3. [Space Syntax Analysis using the alcyon package](./3_space_syntax_analysis.Rmd)
4. [Advanced: Graphs and J-Graphs](./4_advanced_j_graphs.Rmd)
5. [Advanced: Isovist networks](./5_advanced_isovist_network.Rmd)
## Isovist networks
Another interesting use of graphs in Space Syntax is to create isovist networks i.e. networks of intervisible locations. This has been applied to identify properties of different seats in an open-plan office space, for example by Beck, M. P. (2015) at their paper: “Slicing the Cake: An Isovist-Based Analysis of Computerised Workplace Configuration
First, load the library:
```{r setup, echo = FALSE}
library(alcyon)
```
Then, load the office plan (officeSf), the location of the seats (officeSeatsSf) and the location of the points of directions (points in front of seats, officeSeatsDirectionSf). Because the directions and the seats don't have the same order, we will re-order the directions by matching their ID on the seat ID.
```{r}
officeSf = st_read("data/office/office_plan.mif",
geometry_column = 1L, quiet = TRUE)
officeSeatsSf = st_read("data/office/office_seats.mif",
geometry_column = 1L, quiet = TRUE)
officeSeatsDirectionSf = st_read("data/office/office_seats_direction.mif",
geometry_column = 1L, quiet = TRUE)
officeSeatsDirectionSf = officeSeatsDirectionSf[match(officeSeatsDirectionSf$id,
officeSeatsSf$id), ]
```
Plot everything, with the plan underneath:
```{r}
plot(officeSf, reset = F)
plot(officeSeatsSf, add = T, col = "red")
plot(officeSeatsDirectionSf, add = T, pch = 4, col = "blue")
```
Find out which of the elements of the floor plans we need to be "blocking" the view (walls, columns etc.) and only select those, leaving out low elements (furniture layer) or transparent ones (glass layer)
```{r}
plot(officeSf[officeSf$Layer %in% c("wall", "concr", "0", "floor"),])
```
Then, calculate the angles between the seat point and the direction point and provide that to the alcyon::isovist() function so that it can give us the isovist polygons.
```{r}
boundaryMap = as(officeSf[officeSf$Layer %in% c("wall", "concr", "0", "floor"),
c()], "ShapeMap")
seatCoords = st_coordinates(officeSeatsSf)
directionCoords = st_coordinates(officeSeatsDirectionSf)
angles <- atan2(directionCoords[, "Y"] - seatCoords[, "Y"],
directionCoords[, "X"] - seatCoords[, "X"])
angles <- ifelse(angles < 0.0, 2 * pi + angles, angles)
isoPolygons = isovist(boundaryMap,
x = seatCoords[, "X"],
y = seatCoords[, "Y"],
angle = angles,
viewAngle = pi / 2)
```
We can plot one or more isovists on the floorplan.
```{r}
plot(officeSf, col = "gray", reset = F)
plot(isoPolygons[10, "Isovist Area"], add = T)
```
Here, use the function sf::st_within() to tell us which points are within which polygons (i.e. which seats are within other seats' field of view). We need to increase by 1, as igraph does not like vertices to start from 0
```{r}
edges = lapply(1:33, function(idx) {
fromId = officeSeatsSf[idx, ]$id
toId = officeSeatsSf[st_within(officeSeatsSf, isoPolygons[idx, ],
sparse = F), ]$id
if(length(toId) > 0) {
return(cbind(fromId, toId))
} else {
return(c())
}
})
edgeList = do.call(rbind, edges)
isovistGraph = igraph::graph_from_edgelist(edgeList + 1)
```
Plot the graph, providing a layout where the nodes are centered on each seat.
```{r}
plot(officeSf, col = "gray", reset = F)
plot(isovistGraph,
layout=st_coordinates(officeSeatsSf$geometry),
vertex.size = igraph::degree(isovistGraph) * 5000,
vertex.label.cex = 0.75,
vertex.label.dist = 300,
edge.arrow.size = 0.5,
edge.width = igraph::edge_betweenness(isovistGraph) * 0.1,
edge.color = "blue",
rescale = F,
add = T)
```