Um método rápido e sujo é desenhar apenas as sombras dos telhados dos edifícios, transformá-los em cinza escuro (de preferência semitransparentes se houver camadas de solo subjacentes) e desenhar os polígonos do edifício sobre eles. As sombras do telhado são obtidas traduzindo os polígonos do edifício pelas distâncias determinadas pelas alturas do edifício na direção estabelecida pelo azimute e pela altitude da fonte de luz (considerada infinitamente distante). (Uma fórmula para a quantidade de tradução aparece abaixo.)
Isso tende a funcionar bem, exceto em baixas altitudes ou prédios altos (como arranha-céus): veja como as sombras dos prédios mais altos e isolados no lado direito são separadas dos prédios.
Para conectar as sombras adequadamente aos edifícios, você precisa incluir as sombras das paredes do edifício . Isso não é difícil de fazer. A sombra da parede que se estende entre um ponto localizado em P e outro ponto localizado em Q será o quadrilátero delineado por {P, Q, Q ', P'} onde Q 'é a sombra de Q e P' é a sombra de P. Um edifício poligonal será uma coleção de polígonos conectados, representados por seqüências fechadas de pontos (P (1), P (2), ..., P (n)). Para cada um desses polígonos, forme a união das sombras das arestas (P (1), P (2)), (P (2), P (3)), ..., (P (n), P ( 1)). Isso é fácil de fazer por meio de um loop sobre as bordas.
Para uma luz com um azimute de um graus (leste do norte) e uma altitude de S graus (a partir do horizonte), a sombra de um ponto P com coordenadas projectadas (x, y) e a altura h (todos expressos nas mesmas unidades , como metros), está localizado em P '= (x - h sen (a) / tan (s), y - h cos (a) / tan (s)). Você só precisa calcular sin (a) / tan (s) e cos (a) / tan (s) uma vez para toda a camada, e para cada polígono, você só precisa multiplicar esses fatores pela altura uma vez para obter as compensações para cada sombra de ponto no polígono. (A carga de trabalho computacional real é transportada pelo GIS, não pelo seu código, pois forma as uniões de todos esses quadriláteros.)
Aqui está um exemplo do efeito. (O azimute e a altitude mudaram ligeiramente em comparação com a primeira figura, mas os polígonos e alturas dos edifícios - que variam - são os mesmos de antes.)
Apêndice
Em resposta a uma solicitação, aqui está o código usado para criar o segundo exemplo. Embora quase ninguém mais use esse idioma (Avenue), ele poderia servir como pseudocódigo para criar uma solução em seu GIS favorito. (Diferente da maioria dos pseudocódigos, no entanto, ele foi testado com a execução. :-) É tão simples que nenhuma explicação deve ser necessária; apenas lembre-se de que a indexação começa com 0, não 1, e que os anéis dos polígonos são explicitamente fechados (o último ponto da lista coincide com o primeiro).
' S
' Return the shadow of a shape.
' Field calculator example:
' av.run("S", {[shape], [height], 200, 35})
'======================================================================'
theShape = SELF.Get(0) ' A projected polygon
xHeight = SELF.Get(1) ' Expressed in the projected units
xAzimuth = SELF.Get(2).AsRadians ' Any angle (in degrees) east of north
xAltitude = SELF.Get(3).AsRadians ' Angle between 0 and 90 (vertical)
'
' Compute the shadow offsets.
'
xSpread = 1/xAltitude.Tan
x = -xHeight * xSpread * xAzimuth.Sin
y = -xHeight * xSpread * xAzimuth.Cos
xy = x@y
'
' Begin with the original shape.
'
p = theShape.Clone
'
' Adjoin the wall shadows.
'
for each lPts in theShape.AsList ' Loop over the rings
for each i in 1..(lPts.Count-1) ' Loop over edges in this ring
l = {lPts.Get(i-1), lPts.Get(i), lPts.Get(i)+xy, lPts.Get(i-1)+xy}
p = p.ReturnUnion(Polygon.Make({l}))
end
end
return p
' end of script