The top-line question about how to find the shadow that a building casts at a particular day, and time, is not generally one that GIS systems answer. Geographic information systems tend to focus on the earth, and not so much on the sun. However, with a 3D modelling system we can find the answer with some work.
First, we need to know were the sun is. The best reference for this that I could find is here, and the algorithm is also implemented in the Python package Pysolar.
Next, we need a way to render the building, and evaluate how the sun at the given position would cause it to cast a shadow. For this a modelling system like Blender or POV-ray could work well. The code implementation below uses POV-ray and the excellent vapory wrapper.
from pysolar import solar
import datetime
from vapory import Camera, LightSource, Sphere, Texture, Pigment, Scene, Plane, Box, Finish, Normal
from math import sin, cos, radians
def sun_location(altitude, azimuth, from_point, dist_to_sun=100):
"""given an altitude and azimuth to the sun, an assumed
distance to the sun of 100, and a point of origin
find the XYZ location of the sun
Note: the reference system from pysolar is:
http://pysolar.readthedocs.io/en/latest/index.html#location-calculation
The azimuth to the sun is realtive to South, so subtract 270
to get Easterly-based directions.
"""
x_from, y_from, z_from = from_point
#
x_sun = dist_to_sun * sin(radians(azimuth-270))
y_sun = dist_to_sun * sin(radians(altitude))
z_sun = dist_to_sun * cos(radians(azimuth-270))
return x_sun, y_sun, z_sun
# calculate the sun's position in the sky on a given day
d = datetime.datetime(2016, 2, 21, 12, 0, 0)
altitude = solar.get_altitude(44.800682, -68.770021, d)
azimuth = solar.get_azimuth(44.800682, -68.770021, d)
sun_loc = sun_location(altitude, azimuth, [0,0,0], dist_to_sun=100)
# create a light source for the scene with the sun's location
light = LightSource( sun_loc, 'color', [1,1,1] )
# set up some screne elements
camera = Camera( 'location', [0,2,-3], 'look_at', [0,0,2] )
plane = Plane([0, 1, 0], 0, Texture( Pigment( 'color', [1,1,1] )))
building = Box([0,0,0], [0.5, 0.5, 0.5],
Texture( Pigment( 'color', [0.5,0.5,0.5])),
'rotate', [0, 40, 0])
# set up the scene in POV-Ray with the given elements
scene = Scene( camera = camera ,
objects= [light, plane, building],
included = ["colors.inc"]) # headers that POV-Ray may need
scene.render("my_scene.png",
width = 600, height=400,
antialiasing = 0.01,
quality=1) # quality=1 => no shadow/reflection, quality=10 is 'normal'
It's not beautiful, but here is what the rendered image for the box-like building looks like:
There are a variety of issues to work through, such as:
- properly locating the building in a geographic coordinate system
- the effects of local terrain variation on the shadow
- occlusion of the sun by other objects