198 lines
7.0 KiB
TypeScript
198 lines
7.0 KiB
TypeScript
// Модель мира. Все координаты в метрах в локальной проекции мира:
|
|
// x — на восток, y — на юг (как на экране). Углы в радианах.
|
|
// Модель с самого начала рассчитана на будущую симуляцию: у всего есть id,
|
|
// двери и лестницы — это связи между комнатами (граф навигации),
|
|
// у объектов есть флаги «блокирует проход / блокирует обзор».
|
|
|
|
export type Vec = [number, number];
|
|
export type Ring = Vec[];
|
|
|
|
export interface World {
|
|
version: 1;
|
|
id: string;
|
|
name: string;
|
|
createdAt: string;
|
|
seed: number;
|
|
/** Центр проекции и исходная область в градусах [south, west, north, east]. */
|
|
origin: { lat: number; lon: number };
|
|
bbox: [number, number, number, number];
|
|
/** Границы области в метрах. */
|
|
bounds: { minX: number; minY: number; maxX: number; maxY: number };
|
|
areas: Area[];
|
|
roads: Road[];
|
|
buildings: Building[];
|
|
/** Уличные объекты: деревья, машины, скамейки, фонари. */
|
|
props: Prop[];
|
|
/** Библиотека общих моделей предметов: prop.model → набор фигур. */
|
|
models: Record<string, Shape[]>;
|
|
attribution: string;
|
|
}
|
|
|
|
export type AreaKind =
|
|
| 'residential' | 'commercial' | 'industrial' | 'retail' | 'farmland' | 'farmyard'
|
|
| 'grass' | 'park' | 'forest' | 'scrub' | 'meadow' | 'orchard' | 'vineyard'
|
|
| 'water' | 'wetland' | 'beach' | 'sand' | 'parking' | 'pitch' | 'playground'
|
|
| 'cemetery' | 'construction' | 'railway' | 'school' | 'hospital' | 'pedestrian' | 'garden';
|
|
|
|
export interface Area {
|
|
id: string;
|
|
kind: AreaKind;
|
|
/** Первое кольцо — внешнее, остальные — дыры. */
|
|
rings: Ring[];
|
|
osmId?: string;
|
|
name?: string;
|
|
}
|
|
|
|
export type RoadKind =
|
|
| 'motorway' | 'trunk' | 'primary' | 'secondary' | 'tertiary' | 'residential'
|
|
| 'unclassified' | 'service' | 'living_street' | 'pedestrian' | 'track'
|
|
| 'footway' | 'cycleway' | 'path' | 'steps' | 'rail' | 'tram' | 'river' | 'stream' | 'canal' | 'ditch';
|
|
|
|
export interface Road {
|
|
id: string;
|
|
kind: RoadKind;
|
|
pts: Vec[];
|
|
/** Ширина проезжей части (или русла) в метрах. */
|
|
width: number;
|
|
/** Ширина тротуара с каждой стороны, 0 — нет. */
|
|
sidewalk: number;
|
|
lanes: number;
|
|
oneway: boolean;
|
|
layer: number;
|
|
bridge: boolean;
|
|
tunnel: boolean;
|
|
name?: string;
|
|
osmId?: string;
|
|
}
|
|
|
|
export type BuildingKind =
|
|
| 'house' | 'apartments' | 'mixed' | 'retail' | 'restaurant' | 'office' | 'industrial'
|
|
| 'warehouse' | 'school' | 'hospital' | 'hotel' | 'church' | 'civic' | 'garage' | 'shed' | 'farm';
|
|
|
|
export interface Building {
|
|
id: string;
|
|
osmId?: string;
|
|
kind: BuildingKind;
|
|
/** Подтип из OSM-тегов/POI: 'supermarket', 'bakery', 'pharmacy'… */
|
|
use?: string;
|
|
name?: string;
|
|
address?: string;
|
|
footprint: Ring;
|
|
/** Внутренние дворы (дыры в контуре). */
|
|
holes: Ring[];
|
|
/** Площадь контура, м². */
|
|
area: number;
|
|
levels: number;
|
|
/** Откуда взялась этажность: 'osm' | 'height' | 'estimate'. */
|
|
levelsSource: 'osm' | 'height' | 'estimate';
|
|
/** Локальная система здания: поворот сетки планировки. */
|
|
frame: { origin: Vec; angle: number };
|
|
floors: Floor[];
|
|
/** Помещения-юниты: квартиры, магазины, офисы — будущие «домохозяйства» и «рабочие места». */
|
|
units: Unit[];
|
|
/** Сколько спальных мест (оценка жильцов). */
|
|
beds: number;
|
|
seed: number;
|
|
}
|
|
|
|
export interface Unit {
|
|
id: string;
|
|
kind: 'home' | 'shop' | 'office' | 'service' | 'common';
|
|
level: number;
|
|
roomIds: string[];
|
|
beds: number;
|
|
}
|
|
|
|
export type RoomKind =
|
|
| 'hall' | 'landing' | 'living' | 'kitchen' | 'bedroom' | 'bath' | 'wc' | 'storage' | 'corridor'
|
|
| 'stairs' | 'lift' | 'lobby' | 'sales' | 'backroom' | 'office' | 'openoffice' | 'meeting'
|
|
| 'dining' | 'prokitchen' | 'workshop' | 'hall_ind' | 'classroom' | 'staff' | 'ward'
|
|
| 'guestroom' | 'nave' | 'garage' | 'utility' | 'void';
|
|
|
|
export interface Room {
|
|
id: string;
|
|
kind: RoomKind;
|
|
/** Контур комнаты (может быть несколько колец; дыры — по чётности). Рисовать с клипом по контуру здания. */
|
|
rings: Ring[];
|
|
area: number;
|
|
labelPos: Vec;
|
|
unitId?: string;
|
|
}
|
|
|
|
export interface Wall {
|
|
a: Vec;
|
|
b: Vec;
|
|
thickness: number;
|
|
exterior: boolean;
|
|
}
|
|
|
|
export interface Door {
|
|
id: string;
|
|
a: Vec;
|
|
b: Vec;
|
|
/** Комнаты по обе стороны; 'outside' — улица. Это ребро графа навигации. */
|
|
rooms: [string, string];
|
|
/** 'opening' — проём без полотна (арка, выход на лестницу). */
|
|
kind: 'interior' | 'entrance' | 'unit' | 'garage' | 'opening';
|
|
/** Сторона, куда открывается полотно (точка внутри комнаты). */
|
|
swingTo: Vec;
|
|
}
|
|
|
|
export interface Window {
|
|
a: Vec;
|
|
b: Vec;
|
|
roomId: string;
|
|
}
|
|
|
|
export interface Stairs {
|
|
id: string;
|
|
rings: Ring[];
|
|
/** Ось марша: от низа к верху. */
|
|
from: Vec;
|
|
to: Vec;
|
|
width: number;
|
|
up: boolean;
|
|
down: boolean;
|
|
lift?: boolean;
|
|
/** id комнаты-лестничной клетки на этом этаже. */
|
|
roomId: string;
|
|
}
|
|
|
|
export interface Floor {
|
|
level: number;
|
|
rooms: Room[];
|
|
walls: Wall[];
|
|
doors: Door[];
|
|
windows: Window[];
|
|
stairs: Stairs[];
|
|
props: Prop[];
|
|
}
|
|
|
|
/** Примитив в локальных координатах предмета (центр предмета в 0,0; «спинка» к стене при y<0). */
|
|
export type Shape =
|
|
| { t: 'rect'; x: number; y: number; w: number; h: number; r?: number; s?: ShapeStyle }
|
|
| { t: 'circle'; x: number; y: number; r: number; s?: ShapeStyle }
|
|
| { t: 'line'; x1: number; y1: number; x2: number; y2: number; s?: ShapeStyle };
|
|
|
|
/** Стиль: 'base' — основной предмет, 'soft' — ткань/подушка, 'dark' — техника/акцент, 'green' — растение, 'glass', 'metal'. */
|
|
export type ShapeStyle = 'base' | 'soft' | 'dark' | 'green' | 'glass' | 'metal' | 'wood' | 'water' | 'line' | 'car' | 'fabric' | 'accent';
|
|
|
|
export interface Prop {
|
|
id: string;
|
|
kind: string;
|
|
pos: Vec;
|
|
rot: number;
|
|
w: number;
|
|
d: number;
|
|
/** Фигуры предмета; после сборки мира обычно вынесены в world.models (см. model). */
|
|
shapes?: Shape[];
|
|
model?: string;
|
|
blocksMove: boolean;
|
|
blocksSight: boolean;
|
|
roomId?: string;
|
|
/** Цвет для машин и т.п. (иначе по стилю). */
|
|
color?: string;
|
|
/** Для симуляции: можно сидеть/спать/хранить и т.п. */
|
|
tags?: string[];
|
|
}
|