Un metodo rapido e sporco è quello di disegnare solo le ombre dei tetti dell'edificio, renderle in grigio scuro (preferibilmente semitrasparente se ci sono strati di terreno sottostanti) e disegnare i poligoni dell'edificio su di essi. Le ombre del tetto sono ottenute traducendo i poligoni dell'edificio per le distanze determinate dalle altezze dell'edificio nella direzione stabilita dall'azimut e dall'altitudine della sorgente luminosa (considerata infinitamente lontana). (Di seguito viene visualizzata una formula per la quantità di traduzione.)
Questo tende a funzionare bene tranne che per le basse altitudini o gli edifici alti (come i grattacieli): guarda come le ombre degli edifici più alti e isolati sul lato destro sono separate dagli edifici stessi.
Per collegare correttamente le ombre agli edifici, è necessario includere le ombre dei muri degli edifici . Questo non è difficile da fare. L'ombra del muro che si estende tra un punto situato in P e un altro punto in Q sarà il quadrilatero delineato da {P, Q, Q ', P'} dove Q 'è l'ombra di Q e P' è l'ombra di P. Un edificio poligonale sarà una raccolta di poligoni collegati rappresentati da sequenze chiuse di punti (P (1), P (2), ..., P (n)). Per ciascuno di questi poligoni, forma l'unione delle ombre dei bordi (P (1), P (2)), (P (2), P (3)), ..., (P (n), P ( 1)). Questo è semplice da fare per mezzo di un cappio sui bordi.
Per una luce a un azimut di un grado (est del nord) e un'altitudine di s gradi (dall'orizzonte), l'ombra di un punto P con coordinate proiettate (x, y) e altezza h (tutte espresse nelle stesse unità , come metri) si trova in P '= (x - h sin (a) / tan (s), y - h cos (a) / tan (s)). Devi solo calcolare sin (a) / tan (s) e cos (a) / tan (s) una volta per l'intero strato, e per ogni poligono devi solo moltiplicare quei fattori per l'altezza una volta per ottenere gli offset per ogni ombra del punto nel poligono. (Il vero carico di lavoro computazionale è portato dal GIS, non dal tuo codice, in quanto forma i sindacati di tutti questi quadrilateri.)
Ecco un esempio dell'effetto. (L'azimut e l'altitudine sono leggermente cambiati rispetto alla prima figura, ma i poligoni e le altezze dell'edificio - che variano - sono gli stessi di prima.)
Appendice
In risposta a una richiesta, ecco il codice utilizzato per creare il secondo esempio. Sebbene quasi nessuno usi più questo linguaggio (Avenue), potrebbe anche servire come pseudocodice per creare una soluzione nel tuo GIS preferito. (A differenza della maggior parte degli pseudocodici, tuttavia, è stato testato eseguendolo effettivamente. :-) È così semplice che non dovrebbe essere necessaria alcuna spiegazione; tieni solo presente che l'indicizzazione inizia con 0, non 1 e che gli anelli poligonali sono esplicitamente chiusi (l'ultimo punto dell'elenco coincide con il primo punto).
' 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