- 태양의 일주운동에 따른 건물 그림자 모델 논문을 구현했습니다.
- pysolar를 이용해 태양의 운동을 계산하고, geopandas를 이용해 그림자 형상을 계산했습니다.
1. 논문 간단 요약
R. Soler-Bientz et al., “Developing a computational tool to assess shadow pattern on a horizontal plane, preliminary results”, IEEE Photovoltaic Specialists Conference p.2312, 2010. doi:10.1109/PVSC.2010.5614490
태양은 아침에 동쪽에서 떠서 남쪽 하늘을 따라 움직이다 저녁이 되면 서쪽으로 넘어갑니다.
태양광은 아주 멀리서 직진하므로 건물이 만드는 그림자는 태양의 좌표와 건물의 형상으로 구할 수 있습니다.

이 둘을 조합하면 위도와 경도가 다른 지구상 여러 위치에서 건물 그림자를 계산할 수 있습니다.

거의 같은 경도 상에 있는 다섯 도시에서 같은 시간에 생기는 그림자를 그려봅니다.
위도에 따라 태양의 위치가 달라 다른 방향과 형태의 그림자가 생깁니다.

2. 태양 일주운동
Pega Devlog: pysolar
pysolar github
ArcGIS: Points Solar Radiation
- 위도와 시간에 따른 태양 고도 변화를 그려봅니다.
- 춘분(3월 21일) 06시 일출부터 18시 일몰까지 16등분한 태양의 위치입니다.
- arcgis에서 360도를 32등분 하더군요.
- 방위각
azimuthal angle과 고도altitude로 그렸습니다.
1 | import datetime |
삽입할 그림을 파워포인트에서 도형으로 그립니다.

matplotlib의
.add_axes()를 사용해 그림을 넣을 위치를 지정합니다.그림 삽입 후
.axis("off")로 가로 세로 눈금을 떼어버립니다.
1 | from matplotlib.ticker import MultipleLocator |

3. 건물 그리기
Pega Devlog: Create Shapefile from Polygon Dots
Pega Devlog: Mapping Shapefile on Raster Map
geopandas: GeoDataFrame
- 좌표로 사각형을 만드는 함수입니다.
- 지난 글에서는 파일로 저장했지만 이번엔 메모리에 올려서 사용합니다.
1 | import geopandas as gpd |
- 이렇게 만들어진 도형은
geopandas의 GeoDataFrame입니다. - GeoDataFrame은
geometry와 함께 다른 데이터를 담을 수 있습니다.
1 | rec = create_rec(0, 0, 4, 6, 45) |

- 그린 건물을 확인합니다.
1 | fig, ax = plt.subplots() |

4. 그림자 그리기
4.1. 도시별, 시간별 태양 위치
그림자는 태양 위치와 건물 모양의 결과물입니다.
- 태양의 위치는 시간에 대한 함수로 주어집니다.
- 그리고 시간은 협정 세계시에 따라 위치별로 다릅니다.
논문에서 제시한 5개 도시는 거의 동경 75도상에 위치합니다.
그러나 적용 시간대가 다릅니다.
위의 세 도시는 UTC-5, 아래 두 도시는 UTC-4를 따릅니다.

도시별 데이터를 만들어 줍니다.
Antofagasta와 Los Lagos는 UTC-4입니다.
그러나 논문 결과는 UTC-5를 넣어야 구현됩니다.
저자의 실수로 생각됩니다.
1 | cities = ["Philadelphia", "Adderly", "Agua Blanca", "Antofagasta", "Los Lagos"] |
- 각 도시별, 시간대별 태양의 방위각과 고도를 구합니다.
- 시간도 다르기 때문에 도시별 timezone 설정을 해 줍니다.
1 | ### data |
- 결과를 dataframe으로 정리합니다.
datetime.strftime()을 사용해 시각과 분을 추출하고- 방위각과 고도를 이용해 그림자 끝점을 추출합니다.
1 | df_solars = {} |
- 데이터를 확인해 봅니다.
1 | df_solars[0].loc[10:15] |

4.2. 그림자 그리기 함수
상자 모양 건물의 그림자를 그립니다.
- 네 꼭지점에서 각기 그림자 포인트를 찾고
- 건물 밑의 네 꼭지점을 연결합니다.
앞에서 구해둔 데이터프레임을 이용합니다.
shadow_dx,shadow_dy를 적용합니다.
1 | def get_shadows(src_x, src_y, src_width, src_length, src_height, src_angle, df_solar): |
- 테스트를 해 봅니다.
1 | shadows_test1 = get_shadows(0, 0, 4, 6, 8, 45, df_solars[0]) |

- 그림으로 그려봅니다.
1 | shadows_test1.loc[17, "geometry"] |

- 오른쪽 네 개의 점은 바닥면 점,
- 왼쪽 네 개의 점은 윗면이 만든 그림자 점입니다.
- 위 함수 15번째 줄에
convex_hull을 넣어 면을 만듭니다.
1 | shadows_list.append(mpoints_i.convex_hull) |
- 다시 그려봅니다.
1 | shadows_test2 = get_shadows(0, 0, 4, 6, 8, 45, df_solars[0]) |

- 앞서 계산한 태양의 이동을 따라 그림자를 그립니다.
- 논문에서 제시한 9:30 AM의 그림자를 추가로 그립니다.
1 | from matplotlib.patches import Circle |

- 논문 그림이 거의 똑같이 재현되었습니다.
- 태양 방위각, 고도와 그림자 넓이를 수치로 비교합시다.
1 | # shadow area at 9:30 |

- 수치적으로도 거의 똑같이 재현되었습니다.