Инсоляция

Обзор

Анализ инсоляции оценивает, сколько времени место получает прямой солнечный свет среди зданий известной высоты и, при необходимости, с учётом рельефа. objectnat.get_insolation() рассчитывает суточные часы солнца на регулярной сетке приёмников на земле; objectnat.get_facade_insolation() — для точек на фасадах на каждом этаже выбранных зданий. Обе функции принимают один день или период. Типичные задачи — проверка нормативов инсоляции для детских площадок и жилья, сравнение сценариев застройки и размещение растений, которым нужно прямое солнце.

Тени на земле в жилом районе 21 июня, кадры через 15 минут

Освещённая и затенённая земля 21 июня 2026 года в районе из примера (Васильевский остров, Санкт-Петербург, 59,96° с. ш.), кадр каждые 15 минут от восхода до заката. В заголовке — московское время (UTC+3), высота и азимут солнца.

Метод

Положение солнца. Для каждого моделируемого дня положение солнца вычисляется каждые time_step_min минут (в серединах интервалов местных солнечных суток) по алгоритму NOAA с учётом атмосферной рефракции; заявленная точность алгоритма около 0,01°. Дата и центр территории определяют путь солнца, поэтому учитываются широта и сезон. Положения ниже min_sun_elevation (градусы) считаются отсутствием солнца.

Сцена. Здания — выдавленные контуры с плоскими крышами. Высота здания берётся из height_column; если её нет — из storeys_column × storey_height; если нет обоих значений — из default_height. Здания без высоты пропускаются с предупреждением. Рельеф необязателен и задаётся как

  • GeoDataFrame полигонов с высотами в terrain_height_column (например, зоны высот), растеризуемый с ячейками terrain_cell; перекрывающиеся полигоны дают наибольшее значение;

  • путь к GeoTIFF (нужен rasterio);

  • кортеж (heights, transform, crs) из двумерного массива, ориентированного на север аффинного преобразования в порядке rasterio и проецированной системы координат.

Здания стоят на рельефе по своему контуру, а приёмники размещаются на высоте receiver_height над рельефом. Расчёт идёт в локальной метрической системе координат (системе растра, если он задан, иначе в оценённой зоне UTM). Азимуты отсчитываются от истинного севера с поправкой на разницу между истинным севером и севером сетки (сближение меридианов).

Проверка тени. Для каждого приёмника и каждого положения солнца строится луч к солнцу. Приёмник освещён, если луч проходит выше каждой пересекаемой стены здания и выше рельефа. Луч прослеживается, только пока он ниже самой высокой крыши или точки рельефа в сцене, поэтому лучи к высокому солнцу заканчиваются рано и почти ничего не стоят. Проверка выполняется в расширении ObjectNat на Rust параллельно по приёмникам.

Суточная статистика. Для каждого приёмника и дня расширение на Rust возвращает число освещённых шагов времени и самый длинный непрерывный освещённый отрезок. Из них получаются три величины, все в часах:

  • sun_hours: среднесуточное прямое солнце за моделируемые дни;

  • min_sun_hours: прямое солнце в худший моделируемый день;

  • max_continuous_hours: наибольшая непрерывная продолжительность инсоляции в худший день (минимум по дням от наибольшего суточного отрезка). Нормативы инсоляции обычно задают минимум для этой величины; например, СанПиН 1.2.3685-21 (Россия) устанавливает минимальную непрерывную инсоляцию жилья и детских площадок.

Шаги времени дискретны, поэтому каждое значение кратно time_step_min.

Периоды. date=("2026-04-22", "2026-08-22") моделирует каждый day_step-й день периода и его последний день; сцена строится один раз.

Инсоляция на земле

objectnat.get_insolation() размещает приёмники с шагом grid_step метров внутри area (по умолчанию — охватывающего прямоугольника зданий) вне контуров зданий. Включайте в buildings здания вокруг территории: их тени падают на неё.

Результат — точки приёмников с sun_hours, min_sun_hours и max_continuous_hours; sun_hours равно 0 на земле, куда прямое солнце не попадает ни в один моделируемый день. attrs содержат моделируемые дни days, day_length_hours (среднее время, когда солнце выше min_sun_elevation) и сетку, поэтому objectnat.rasterize() превращает любой столбец в растр для карт, файлов GeoTIFF и веб-карт (см. Растры). Растр показывает часы непрерывной цветовой шкалой; пороги, например норматив, применяются к столбцам напрямую, например receivers["max_continuous_hours"] >= 2.5.

objectnat.get_insolation(buildings, date, *, area=None, height_column='height', storeys_column=None, storey_height=3.0, default_height=None, terrain=None, terrain_height_column='height', terrain_cell=5.0, grid_step=2.0, time_step_min=10.0, day_step=7, min_sun_elevation=0.0, receiver_height=0.0, max_workers=None)[исходный код]

Часы прямого солнечного света на земле за день или за период среди зданий известной высоты и рельефа.

Солнце прослеживается в течение каждого моделируемого дня с шагом time_step_min (положение солнца по NOAA для даты и места территории, с рефракцией), поэтому его путь меняется с широтой и сезоном. Для каждой точки регулярной сетки и каждого положения солнца выше min_sun_elevation строится луч к солнцу; точка освещена, если луч проходит выше каждой пересекаемой стены здания и выше рельефа. Здания — выдавленные контуры с плоскими крышами, стоящие на рельефе. Результат показывает, сколько часов солнца получает каждое место и какие места всё время остаются в тени.

Параметры:
  • buildings (geopandas.GeoDataFrame) – Контуры зданий (Polygon/MultiPolygon) в любой системе координат. Включайте и здания вокруг изучаемой территории: тени падают и от них.

  • date (datetime.date | str | tuple) – Один день ("2026-06-21") или период (start, end), оба дня включительно (("2026-04-22", "2026-08-22")). Каждый день рассчитывается от восхода до заката.

  • area (gpd.GeoDataFrame | gpd.GeoSeries | shapely geometry | None, optional) – Где размещать приёмники. Геометрии shapely считаются заданными в системе координат buildings. По умолчанию — охватывающий прямоугольник зданий.

  • height_column (str | None, optional) – Столбец с высотами зданий в метрах. По умолчанию "height".

  • storeys_column (str | None, optional) – Столбец с числом этажей; используется (умноженный на storey_height), если высоты нет.

  • storey_height (float, optional) – Высота одного этажа в метрах. По умолчанию 3.

  • default_height (float | None, optional) – Высота для зданий без обоих значений. Без неё такие здания пропускаются с предупреждением.

  • terrain (gpd.GeoDataFrame | str | os.PathLike | tuple | None, optional) –

    Высоты земли в метрах, одно из:

    • GeoDataFrame полигонов с высотой в terrain_height_column (например, зоны высот); он растеризуется с ячейками terrain_cell, перекрывающиеся полигоны дают наибольшее значение, а места, не покрытые полигонами, считаются отсутствием данных;

    • путь к GeoTIFF (нужен rasterio);

    • кортеж (heights, transform, crs) из двумерного массива, аффинного преобразования (a, b, c, d, e, f) как в rasterio (x = a * col + c, y = e * row + f, на север, без поворота) и проецированной системы координат.

    Растры задают систему координат расчёта; NaN отмечает отсутствие данных. Без рельефа земля ровная.

  • terrain_height_column (str, optional) – Столбец высоты в GeoDataFrame рельефа. По умолчанию "height".

  • terrain_cell (float, optional) – Размер ячейки в метрах для растеризации GeoDataFrame рельефа. По умолчанию 5.

  • grid_step (float, optional) – Шаг приёмников в метрах. По умолчанию 2.

  • time_step_min (float, optional) – Шаг времени в минутах; сутки должны делиться на него без остатка. По умолчанию 10.

  • day_step (int, optional) – Для периода — моделировать каждый day_step-й день (последний день периода включается всегда). По умолчанию 7.

  • min_sun_elevation (float, optional) – Положения солнца ниже этого угла (градусы) считаются отсутствием солнца, например чтобы, как в нормативах инсоляции, не учитывать низкое утреннее и вечернее солнце. По умолчанию 0.

  • receiver_height (float, optional) – Высота приёмников над землёй в метрах. По умолчанию 0.

  • max_workers (int | None, optional) – Число потоков (None — все ядра).

Результат:

Точки приёмников в системе координат buildings; точки внутри зданий исключаются. Столбцы:

  • sun_hours: среднесуточное прямое солнце в часах (0 для земли, куда прямое солнце не попадает ни в один моделируемый день);

  • min_sun_hours: часы в худший день;

  • max_continuous_hours: наибольшая непрерывная продолжительность инсоляции в худший день (наименьший из суточных наибольших отрезков), для которой нормативы инсоляции обычно задают минимум.

attrs содержат days (моделируемые даты) и day_length_hours (среднее время, когда солнце выше min_sun_elevation) и записывают сетку, поэтому rasterize() превращает любой столбец в Raster.

Тип результата:

gpd.GeoDataFrame

Исключение:
  • ValueError – При отсутствии системы координат, пустых входных данных, неизвестных столбцах высот, некорректном шаге времени или периоде.

  • ImportError – Если terrain — путь к файлу, а rasterio не установлен.

Часы прямого солнца 21 марта и 21 июня

Часы прямого солнца 21 марта и 21 июня 2026 года на территории 500 × 400 м (обведена), grid_step=2, time_step_min=10; приёмники растеризованы функцией objectnat.rasterize() в одной цветовой шкале. Высота зданий — storeys_count × 3 м.

Средние часы солнца и наибольшая непрерывная инсоляция за период

Период 22 апреля – 22 августа 2026 года с day_step=7 (19 моделируемых дней), приёмники растеризованы objectnat.rasterize() в одной шкале. Слева: среднесуточные часы солнца. Справа: наибольшая непрерывная продолжительность инсоляции в худший день.

Часы солнца без гряды к югу от территории и с ней, и их разность

Та же территория 21 марта на ровной земле и с синтетической грядой высотой 50 м, вытянутой с запада на восток, с гребнем в 50 м к югу от территории, заданной массивом (heights, transform, crs) (пунктирные изолинии в метрах). Низкое солнце в равноденствие светит с юга. В южных 40 м территории, у подножия гряды, приёмники теряют в среднем 7 ч в сутки, и две трети из них вообще не получают прямого солнца; до 180 м севернее отдельные места всё ещё теряют 1–2 ч. Холм под самой территорией мало что меняет, потому что здания и приёмники поднимаются вместе с землёй.

Инсоляция фасадов

objectnat.get_facade_insolation() размещает точки вдоль каждой стены зданий, пересекающих area (внешних и дворовых стен), с шагом spacing метров, в 0,1 м перед стеной, на каждом этаже на высоте window_height над уровнем пола. На стенах, общих с соседним зданием, точек нет. Число этажей — значение этажности, если оно задано, иначе высота, делённая на storey_height. Точка учитывает солнце, только пока солнце находится перед её фасадом не ближе min_facade_angle градусов (по горизонтали) к плоскости фасада, а луч к солнцу не перекрыт другими зданиями или рельефом. Тени отбрасывают все здания из buildings, в том числе за пределами area.

В результате по одной точке на позицию на стене и этаж со столбцами building (метка индекса здания), floor (1 — первый этаж), height над землёй, facade_azimuth (направление, куда обращён фасад, в градусах по часовой стрелке от истинного севера), sun_hours, min_sun_hours и max_continuous_hours. С norm_hours добавляется meets_norm (max_continuous_hours >= norm_hours). Группировка точек по building и floor показывает, какие этажи и фасады не проходят по нормативу; сравнение расчётов с проектируемым зданием и без него показывает, какие окна оно затеняет.

objectnat.get_facade_insolation(buildings, date, *, area=None, height_column='height', storeys_column=None, storey_height=3.0, default_height=None, terrain=None, terrain_height_column='height', terrain_cell=5.0, spacing=3.0, window_height=1.2, floors=None, time_step_min=10.0, day_step=7, min_sun_elevation=0.0, min_facade_angle=0.0, norm_hours=None, max_workers=None)[исходный код]

Часы прямого солнечного света на фасадах зданий по этажам: какие окна получают солнце, а какие нет.

Расчётные точки размещаются вдоль каждой стены зданий в area (внешних и дворовых стен) с шагом spacing метров, на каждом этаже на высоте window_height над уровнем пола, прямо перед стеной. На стенах, общих с соседним зданием, точек нет. Точка освещена, если солнце находится перед её фасадом не ближе min_facade_angle к плоскости фасада, а луч к солнцу проходит выше всех других стен и рельефа, как в get_insolation(). Тени отбрасывают все здания, в том числе за пределами area.

Параметры:
  • buildings (geopandas.GeoDataFrame) – Контуры зданий с высотами, как в get_insolation().

  • date (datetime.date | str | tuple) – Один день или период (start, end), как в get_insolation().

  • area (gpd.GeoDataFrame | gpd.GeoSeries | shapely geometry | None, optional) – Здания, пересекающие эту территорию, получают точки на фасадах (геометрии shapely в системе координат buildings). По умолчанию — все здания.

  • height_column (str | None) – Высоты зданий, как в get_insolation(). Число этажей — значение этажности, если оно задано, иначе высота, делённая на storey_height (не меньше одного этажа).

  • storeys_column (str | None) – Высоты зданий, как в get_insolation(). Число этажей — значение этажности, если оно задано, иначе высота, делённая на storey_height (не меньше одного этажа).

  • storey_height (float) – Высоты зданий, как в get_insolation(). Число этажей — значение этажности, если оно задано, иначе высота, делённая на storey_height (не меньше одного этажа).

  • default_height (float | None) – Высоты зданий, как в get_insolation(). Число этажей — значение этажности, если оно задано, иначе высота, делённая на storey_height (не меньше одного этажа).

  • terrain (GeoDataFrame | str | PathLike | tuple | None) – Высоты земли, как в get_insolation().

  • terrain_height_column (str) – Высоты земли, как в get_insolation().

  • terrain_cell (float) – Высоты земли, как в get_insolation().

  • spacing (float, optional) – Расстояние между точками вдоль стены в метрах; более короткие стены получают одну точку. По умолчанию 3.

  • window_height (float, optional) – Высота точек над уровнем каждого этажа в метрах. По умолчанию 1.2.

  • floors (Sequence[int] | None, optional) – Только эти этажи (1 — первый этаж). По умолчанию все этажи.

  • time_step_min (float) – Выборка положений солнца, как в get_insolation().

  • day_step (int) – Выборка положений солнца, как в get_insolation().

  • min_sun_elevation (float) – Выборка положений солнца, как в get_insolation().

  • min_facade_angle (float, optional) – Солнце ближе этого угла (градусы, по горизонтали) к плоскости фасада не учитывается. По умолчанию 0: учитывается любое солнце перед фасадом.

  • norm_hours (float | None, optional) – Требуемая непрерывная инсоляция в часах; добавляет meets_norm (max_continuous_hours >= norm_hours).

  • max_workers (int | None, optional) – Число потоков (None — все ядра).

Результат:

По одной точке на позицию на стене и этаж в системе координат buildings со столбцами building (метка индекса здания), floor, height (над землёй), facade_azimuth (направление, куда обращён фасад, в градусах по часовой стрелке от истинного севера), sun_hours, min_sun_hours и max_continuous_hours (как в get_insolation()) и, при norm_hours, meets_norm. attrs содержат days и day_length_hours.

Тип результата:

gpd.GeoDataFrame

Непрерывная инсоляция фасадов на 1, 5 и 10 этажах и доля точек, получающих 2,5 ч

Точки на фасадах (spacing=3) 22 апреля 2026 года, окрашенные по наибольшей непрерывной продолжительности инсоляции, для 1, 5 и 10 этажей, и доля точек, получающих не меньше 2,5 ч непрерывного солнца, по этажам (norm_hours=2.5). Число точек на этаже указано в скобках. Порог 2,5 ч — пример; используйте норматив и расчётный день, которые относятся к проекту.

Ограничения

  • Крыши плоские. Скатные крыши, балконы, лоджии, карнизы и деревья не моделируются.

  • Точки на фасадах лежат перед внешней поверхностью стены; оконные откосы (толщина стены) не моделируются, поэтому углы солнца, которые срезал бы глубокий оконный проём, всё равно учитываются, если их не исключает min_facade_angle.

  • Учитывается только прямой солнечный свет; рассеянный свет неба и отражённый свет не учитываются, облачность игнорируется.

  • Результаты дискретны по времени (time_step_min) и пространству (grid_step, spacing); непрерывный период может быть занижен или завышен на один шаг времени с каждого конца.

  • Точность результата ограничена высотами зданий: высоты, полученные из этажности (storeys × storey_height), могут отличаться от измеренных на несколько метров.

Пример в ноутбуке

Инсоляция: часы солнца на земле и на фасадах