110 lines
8.4 KiB
Markdown
110 lines
8.4 KiB
Markdown
# Город сверху — генератор карты по OpenStreetMap (MVP)
|
||
|
||
Выделяете на карте небольшой город или район → по данным OSM строится подробная карта
|
||
с видом строго сверху: дороги реальной ширины с тротуарами и разметкой, парковки
|
||
с машинами, деревья, и **у каждого здания — этажи, комнаты, двери, окна, лестницы
|
||
и мебель**, нарисованные простыми геометрическими фигурами, как на плане квартиры.
|
||
|
||
Всё работает в браузере, без сервера: данные берутся из Overpass API, генерация
|
||
идёт в Web Worker'ах, готовый мир сохраняется в IndexedDB.
|
||
|
||
Машины появляются только на парковках и в гаражах; вдоль улиц они не генерируются.
|
||
|
||
## Запуск
|
||
|
||
Нужен Node.js 18+.
|
||
|
||
```bash
|
||
npm install
|
||
npm run dev # http://localhost:5173/ (пересборка на лету)
|
||
npm run build # сборка в dist/ — можно положить на любой статический хостинг
|
||
npm run typecheck
|
||
```
|
||
|
||
Для автоматических проверок сетевого клиента нужен Node.js 22+: `npm test`.
|
||
Тесты проверяют таймауты, переключение серверов и отмену без обращения к сети.
|
||
|
||
Данные сначала запрашиваются у `maps.mail.ru`, затем у `overpass-api.de` и
|
||
`overpass.private.coffee`. На каждый запрос отводится 45 секунд, включая загрузку
|
||
ответа; после ошибки или таймаута используется следующий сервер. Лимит обработки
|
||
запроса на стороне Overpass — 30 секунд. Кнопка «Отмена» прерывает запрос и ожидание
|
||
перед повтором.
|
||
|
||
Без интернета можно проверить на образце: «Другие способы» → «Сгенерировать из выгрузки
|
||
Overpass» → `samples/balzers-2013.json` (Бальцерс, Лихтенштейн, данные OSM 2013 года).
|
||
|
||
Генерация из файла без браузера (для отладки генератора):
|
||
|
||
```bash
|
||
npm run cli -- samples/balzers-2013.json 47.058 9.492 47.074 9.518 world.json
|
||
```
|
||
|
||
## Управление
|
||
|
||
- перетаскивание — сдвиг, колесо / щипок — масштаб, двойной клик — приблизить;
|
||
- справа — этаж для всей карты (⌂ — крыши), `PgUp`/`PgDn` или `[` `]`;
|
||
- клик по зданию — карточка: вид, этажность (из OSM или оценка), квартиры, спальные места,
|
||
свой переключатель этажей только для этого здания;
|
||
- «Экспорт мира» — весь мир одним файлом `.json.gz` (будущий формат для игры).
|
||
|
||
## Как устроена генерация
|
||
|
||
```
|
||
Overpass JSON ─► city.ts ──────────────► зоны, дороги, контуры зданий, деревья, парковки
|
||
│ classify.ts вид здания (по тегам, POI внутри, landuse, площади) и этажность
|
||
▼
|
||
interior.ts (в воркерах) ─► этажи: сетка 0.5 м в осях здания
|
||
│ схема: секции с подъездами | коридор | простая раскладка
|
||
│ деление на комнаты по программе (м²), несколько попыток с оценкой
|
||
│ двери = остовное дерево по графу смежности, санузлы и спальни — тупики
|
||
│ вход с фасада к дороге, окна с шагом по типу здания
|
||
▼
|
||
furnish.ts + catalog.ts ──► мебель по правилам для каждого типа комнаты
|
||
▼
|
||
finalize.ts ──────────────► общие модели предметов, округление до 1 см
|
||
```
|
||
|
||
- **Сид** здания = OSM-id ⊕ сид мира — один и тот же город всегда генерируется одинаково.
|
||
- Многоквартирные дома — **секционные**: подъезд с лестницей (и лифтом от 5 этажей),
|
||
площадка, 1–4 квартиры вокруг неё; на первом этаже — проход к входу, у домов с магазинами
|
||
вместо квартир магазины со своими входами с улицы.
|
||
- Офисы, школы, больницы, гостиницы — **коридорная** схема.
|
||
- Дома, магазины, кафе, цеха, склады, храмы, гаражи — **простая** раскладка
|
||
(у гаражных рядов — отдельные боксы с воротами).
|
||
|
||
## Модель данных мира (`src/types.ts`)
|
||
|
||
Заложено под будущую симуляцию:
|
||
|
||
| Что | Зачем потом |
|
||
|---|---|
|
||
| `Door.rooms = [комната, комната \| 'outside']` | рёбра графа навигации внутри здания |
|
||
| `Stairs` (одно место на всех этажах, `up`/`down`), лифты | переходы между этажами |
|
||
| `Unit` — квартира / магазин / офис с `roomIds` и `beds` | домохозяйства и рабочие места для жителей |
|
||
| `Prop.blocksMove`, `Prop.blocksSight`, `tags` (`sleep:2`, `sit:4`, `work`, `cook`, `storage`…) | коллизии, линия обзора, что агент может сделать с предметом |
|
||
| `Wall` с разрывами под двери и окна, `Window` | коллизии и видимость (окна прозрачны для взгляда) |
|
||
| `Road` с шириной, тротуарами, `oneway`, слоями | граф улиц для перемещения по городу |
|
||
| все объекты с `id` | хранение состояния: открытая дверь, взятый предмет |
|
||
|
||
Координаты — метры в локальной проекции вокруг центра области (x — восток, y — юг).
|
||
|
||
## Ограничения MVP
|
||
|
||
- Область до 25 км²; предупреждение о времени генерации — свыше 10 км².
|
||
Скорость и расход памяти зависят от плотности застройки и этажности.
|
||
Публичные серверы Overpass рассчитаны на умеренную нагрузку; для
|
||
публичной игры понадобится своё зеркало или заранее нарезанные данные (например, экстракт
|
||
Geofabrik → статические файлы).
|
||
- Подвалы, мансарды, балконы, береговая линия морей пока не генерируются.
|
||
- Нестандартные контуры (сильно изломанные) дают менее аккуратные планировки.
|
||
|
||
## Данные и лицензии
|
||
|
||
Данные карты © участники OpenStreetMap, лицензия ODbL. Если вы распространяете
|
||
сгенерированные миры, укажите «© OpenStreetMap contributors». Тайлы на экране выбора
|
||
области — стандартные тайлы OSM по их [правилам использования](https://operations.osmfoundation.org/policies/tiles/);
|
||
поиск — Nominatim (не чаще раза в секунду).
|
||
|
||
Идеи частично подсказаны проектом [KnoxMap](https://github.com/spytheeuclidean-a11y/knoxmap);
|
||
код написан с нуля.
|