Быстрый и грязный метод состоит в том, чтобы нарисовать тени только крыш зданий, сделать их темно-серыми (желательно полупрозрачными, если есть нижележащие слои грунта) и нарисовать полигоны зданий над ними. Тени крыши получают путем перевода полигонов здания на расстояния, определяемые высотой здания, в направлении, определяемом азимутом и высотой источника света (считается бесконечно далеко). (Формула суммы перевода приведена ниже.)
Это работает нормально, за исключением небольших высот или высоких зданий (таких как небоскребы): посмотрите, как тени от более высоких изолированных зданий на правой стороне отделены от самих зданий.
Чтобы правильно соединить тени со зданиями, необходимо включить тени от стен здания . Это не сложно сделать. Тень стены, проходящей между точкой, расположенной в точке P, и другой точкой, расположенной в точке Q, будет четырехугольником, обозначенным {P, Q, Q ', P'}, где Q '- тень Q, а P' - тень P. Многоугольное здание будет набором связанных многоугольников, представленных замкнутыми последовательностями точек (P (1), P (2), ..., P (n)). Для каждого такого многоугольника сформируйте объединение теней ребер (P (1), P (2)), (P (2), P (3)), ..., (P (n), P ( 1)). Это легко сделать с помощью петли по краям.
Для света при азимуте через градусы ( к востоку от севера) и высоты ы градусов (от горизонта), тени в точке Р с прогнозируемыми координатами (х, у) и высот ч (всего выражается в тех же единицах , например, метры) находится в P '= (x - h sin (a) / tan (s), y - h cos (a) / tan (s)). Вы должны только вычислить sin (a) / tan (s) и cos (a) / tan (s) один раз для всего слоя, и для каждого полигона вам нужно только умножить эти факторы на высоту один раз, чтобы получить смещения для каждая точка тени в многоугольнике. (Реальная вычислительная нагрузка переносится ГИС, а не вашим кодом, так как она образует объединения всех этих четырехугольников.)
Вот пример эффекта. (Азимут и высота немного изменились по сравнению с первым рисунком, но полигоны и высоты здания - которые различаются - такие же, как и раньше.)
аппендикс
В ответ на запрос вот код, использованный для создания второго примера. Хотя почти никто больше не использует этот язык (Avenue), он вполне может служить псевдокодом для создания решения в вашей любимой ГИС. (Однако, в отличие от большинства псевдокодов, он был протестирован путем его запуска. :-) Это настолько просто, что объяснение не требуется; просто знайте, что индексирование начинается с 0, а не с 1, и что кольца многоугольников явно замкнуты (последняя точка в списке совпадает с первой точкой).
' 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