Geo-Lab / engine /grid.py
HANSOL
Geo-Lab v4.1 - Clean deployment
2afa69c
import numpy as np
from dataclasses import dataclass, field
from typing import Tuple, Optional
@dataclass
class WorldGrid:
"""
์ง€๊ตฌ ์‹œ์Šคํ…œ ํ†ตํ•ฉ ๊ทธ๋ฆฌ๋“œ (World Grid)
๋ชจ๋“  ๋ฌผ๋ฆฌ์  ์ƒํƒœ(๊ณ ๋„, ๋ฌผ, ํ‡ด์ ๋ฌผ)๋ฅผ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•˜๋Š” ์ค‘์•™ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
๊ธฐ์กด์˜ ๊ฐœ๋ณ„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ทธ๋ฆฌ๋“œ์™€ ๋‹ฌ๋ฆฌ, ์ „์ง€๊ตฌ์  ํ•ด์ˆ˜๋ฉด(Sea Level)๊ณผ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.
"""
width: int = 100
height: int = 100
cell_size: float = 10.0 # ๋ฏธํ„ฐ (m)
sea_level: float = 0.0 # ํ•ด์ˆ˜๋ฉด ๊ณ ๋„ (m)
# --- ์ƒํƒœ ๋ ˆ์ด์–ด (State Layers) ---
# ๊ธฐ๋ฐ˜์•” ๊ณ ๋„ (Bedrock Elevation)
bedrock: np.ndarray = field(default=None)
# ํ‡ด์ ์ธต ๋‘๊ป˜ (Sediment Thickness)
sediment: np.ndarray = field(default=None)
# ์ˆ˜์‹ฌ (Water Depth) - ํ‘œ๋ฉด ์œ ์ถœ์ˆ˜
water_depth: np.ndarray = field(default=None)
# ์œ ๋Ÿ‰ (Discharge)
discharge: np.ndarray = field(default=None)
# ์œ ํ–ฅ (Flow Direction)
flow_dir: np.ndarray = field(default=None)
# --- ํŒŒ์ƒ ๋ ˆ์ด์–ด (Derived Layers) ---
# ์ง€ํ‘œ๋ฉด ๊ณ ๋„ (Topography = Bedrock + Sediment)
elevation: np.ndarray = field(default=None)
def __post_init__(self):
"""๊ทธ๋ฆฌ๋“œ ์ดˆ๊ธฐํ™”"""
shape = (self.height, self.width)
if self.bedrock is None:
self.bedrock = np.zeros(shape)
if self.sediment is None:
self.sediment = np.zeros(shape)
if self.water_depth is None:
self.water_depth = np.zeros(shape)
if self.discharge is None:
self.discharge = np.zeros(shape)
if self.flow_dir is None:
self.flow_dir = np.zeros(shape, dtype=int)
if self.elevation is None:
self.update_elevation()
def update_elevation(self):
"""์ง€ํ‘œ๋ฉด ๊ณ ๋„ ๊ฐฑ์‹  (๊ธฐ๋ฐ˜์•” + ํ‡ด์ ์ธต)"""
self.elevation = self.bedrock + self.sediment
def get_gradient(self) -> Tuple[np.ndarray, np.ndarray]:
"""
๊ฒฝ์‚ฌ๋„(Slope)์™€ ๊ฒฝ์‚ฌํ–ฅ(Aspect) ๊ณ„์‚ฐ
Returns:
slope (m/m): ๊ฒฝ์‚ฌ๋„
aspect (rad): ๊ฒฝ์‚ฌ ๋ฐฉํ–ฅ (0=East, pi/2=North)
"""
dy, dx = np.gradient(self.elevation, self.cell_size)
slope = np.sqrt(dx**2 + dy**2)
aspect = np.arctan2(dy, dx)
return slope, aspect
def get_water_surface(self) -> np.ndarray:
"""์ˆ˜๋ฉด ๊ณ ๋„ ๋ฐ˜ํ™˜ (์ง€ํ‘œ๋ฉด + ์ˆ˜์‹ฌ)"""
return self.elevation + self.water_depth
def is_underwater(self) -> np.ndarray:
"""ํ•ด์ˆ˜๋ฉด ๊ธฐ์ค€ ์นจ์ˆ˜ ์—ฌ๋ถ€ ํ™•์ธ"""
# ํ•ด์ˆ˜๋ฉด๋ณด๋‹ค ๋‚ฎ๊ฑฐ๋‚˜, ์ง€ํ‘œ๋ฉด์— ๋ฌผ์ด ํ๋ฅด๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ
# ์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํžˆ 'ํ•ด์ˆ˜๋ฉด' ๊ธฐ์ค€๊ณผ '๋‹ด์ˆ˜' ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Œ.
# ์ผ๋‹จ ํ•ด์ˆ˜๋ฉด(Sea Level) ๊ธฐ์ค€ ์นจ์ˆ˜ ์ง€์—ญ ๋ฐ˜ํ™˜
return self.elevation < self.sea_level
def apply_uplift(self, rate: float, dt: float = 1.0):
"""์ง€๋ฐ˜ ์œต๊ธฐ ์ ์šฉ"""
self.bedrock += rate * dt
self.update_elevation()
def add_sediment(self, amount: np.ndarray):
"""ํ‡ด์ ๋ฌผ ์ถ”๊ฐ€/์ œ๊ฑฐ"""
self.sediment += amount
# ํ‡ด์ ๋ฌผ์€ 0๋ณด๋‹ค ์ž‘์„ ์ˆ˜ ์—†์Œ (๊ธฐ๋ฐ˜์•” ์นจ์‹์€ ๋ณ„๋„ ๋กœ์ง)
self.sediment = np.maximum(self.sediment, 0)
self.update_elevation()