Geo-Lab / renderer.py
HANSOL
Fix: Simplify imports for HuggingFace - renderer at root
c1a46a8
"""
๐ŸŽจ Terrain Renderer - Plotly 3D ์‹œ๊ฐํ™”
๋ถ„๋ฆฌ๋œ ๋ชจ๋“ˆ๋กœ HuggingFace Spaces ํ˜ธํ™˜์„ฑ ํ–ฅ์ƒ
"""
import numpy as np
import plotly.graph_objects as go
import os
try:
from PIL import Image
except ImportError:
Image = None
def render_terrain_plotly(elevation, title, add_water=True, water_level=0,
texture_path=None, force_camera=True,
water_depth_grid=None, sediment_grid=None,
landform_type=None):
"""Plotly ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ 3D Surface - ์‚ฌ์‹ค์  ํ…์Šค์ฒ˜(Biome) ์ ์šฉ
Args:
elevation: 2D numpy array - ๊ณ ๋„ ๋ฐ์ดํ„ฐ
title: ๊ทธ๋ž˜ํ”„ ์ œ๋ชฉ
add_water: ๋ฌผ ํ‘œ๋ฉด ์ถ”๊ฐ€ ์—ฌ๋ถ€
water_level: ํ•ด์ˆ˜๋ฉด ๋†’์ด
texture_path: ํ…์Šค์ฒ˜ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ
force_camera: ์นด๋ฉ”๋ผ ์œ„์น˜ ๊ณ ์ • ์—ฌ๋ถ€
water_depth_grid: ๋ฌผ ๊นŠ์ด ๊ทธ๋ฆฌ๋“œ
sediment_grid: ํ‡ด์ ๋ฌผ ๊ทธ๋ฆฌ๋“œ
landform_type: 'river', 'coastal', 'glacial', 'volcanic', 'karst', 'arid'
"""
h, w = elevation.shape
x = np.arange(w)
y = np.arange(h)
# ๊ฒฝ์‚ฌ๋„ ๊ณ„์‚ฐ
dy, dx = np.gradient(elevation)
slope = np.sqrt(dx**2 + dy**2)
# Biome Index (0: ๋ฌผ/๋ชจ๋ž˜, 1: ํ’€, 2: ์•”์„, 3: ๋ˆˆ)
biome = np.zeros_like(elevation)
biome[:] = 1 # ๊ธฐ๋ณธ: ํ’€
# ํ‡ด์ ์ง€ ํŒ๋ณ„
sand_level = water_level + 5 if add_water else elevation.min() + 10
is_deposit = np.zeros_like(elevation, dtype=bool)
if sediment_grid is not None:
is_deposit = (sediment_grid > 0.5)
else:
is_deposit = (elevation < sand_level) & (slope < 0.5)
biome[is_deposit] = 0
# ์•”์„ (๊ฒฝ์‚ฌ๊ฐ€ ๊ธ‰ํ•œ ๊ณณ)
biome[slope > 1.2] = 2
# ์ง€ํ˜• ์œ ํ˜•๋ณ„ ์ฒ˜๋ฆฌ
if landform_type == 'glacial':
biome[elevation > 50] = 3
biome[slope > 1.5] = 2
elif landform_type in ['river', 'coastal']:
if water_depth_grid is not None:
is_water = water_depth_grid > 0.5
biome[is_water] = 0
biome[elevation < 0] = 0
elif landform_type == 'arid':
biome[slope < 0.8] = 0
# ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
noise = np.random.normal(0, 0.2, elevation.shape)
biome_noisy = np.clip(biome + noise, 0, 3).round(2)
# ์ปฌ๋Ÿฌ์Šค์ผ€์ผ ์„ค์ •
if landform_type == 'glacial':
realistic_colorscale = [
[0.0, '#E6C288'], [0.25, '#E6C288'],
[0.25, '#556B2F'], [0.5, '#556B2F'],
[0.5, '#808080'], [0.75, '#808080'],
[0.75, '#E0FFFF'], [1.0, '#FFFFFF']
]
colorbar_labels = ["ํ‡ด์ (ๅœŸ)", "์‹์ƒ(่‰)", "์•”์„(ๅฒฉ)", "๋น™ํ•˜(ๆฐท)"]
elif landform_type in ['river', 'coastal']:
realistic_colorscale = [
[0.0, '#4682B4'], [0.25, '#4682B4'],
[0.25, '#556B2F'], [0.5, '#556B2F'],
[0.5, '#808080'], [0.75, '#808080'],
[0.75, '#D2B48C'], [1.0, '#D2B48C']
]
colorbar_labels = ["์ˆ˜์—ญ(ๆฐด)", "์‹์ƒ(่‰)", "์•”์„(ๅฒฉ)", "์‚ฌ์งˆ(็ ‚)"]
elif landform_type == 'arid':
realistic_colorscale = [
[0.0, '#EDC9AF'], [0.25, '#EDC9AF'],
[0.25, '#CD853F'], [0.5, '#CD853F'],
[0.5, '#808080'], [0.75, '#808080'],
[0.75, '#DAA520'], [1.0, '#DAA520']
]
colorbar_labels = ["์‚ฌ๋ง‰(็ ‚)", "์•”์งˆ(ๅท–)", "์•”์„(ๅฒฉ)", "๋ชจ๋ž˜(ๆฒ™)"]
else:
realistic_colorscale = [
[0.0, '#E6C288'], [0.25, '#E6C288'],
[0.25, '#556B2F'], [0.5, '#556B2F'],
[0.5, '#808080'], [0.75, '#808080'],
[0.75, '#A0522D'], [1.0, '#A0522D']
]
colorbar_labels = ["ํ‡ด์ (ๅœŸ)", "์‹์ƒ(่‰)", "์•”์„(ๅฒฉ)", "ํ‘œํ† (ๅœŸ)"]
# ์‹œ๊ฐ์  ๋…ธ์ด์ฆˆ
visual_z = (elevation + np.random.normal(0, 0.2, elevation.shape)).round(2)
final_surface_color = biome_noisy
final_colorscale = realistic_colorscale
final_cmin = 0
final_cmax = 3
final_colorbar = dict(
title=dict(text="์ง€ํ‘œ ์ƒํƒœ", font=dict(color='white')),
tickvals=[0.37, 1.12, 1.87, 2.62],
ticktext=colorbar_labels,
tickfont=dict(color='white')
)
# ํ…์Šค์ฒ˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ
if texture_path and os.path.exists(texture_path) and Image:
try:
img = Image.open(texture_path).convert('L')
img = img.resize((w, h))
img_array = np.array(img) / 255.0
final_surface_color = img_array
final_colorscale = 'Gray'
final_cmin = 0
final_cmax = 1
final_colorbar = dict(title="ํ…์Šค์ฒ˜ ๋ช…์•”")
except Exception as e:
print(f"Texture error: {e}")
# 3D Plot
lighting_effects = dict(ambient=0.4, diffuse=0.5, roughness=0.9, specular=0.1, fresnel=0.2)
trace_terrain = go.Surface(
z=visual_z, x=x, y=y,
surfacecolor=final_surface_color,
colorscale=final_colorscale,
cmin=final_cmin, cmax=final_cmax,
colorbar=final_colorbar,
lighting=lighting_effects,
hoverinfo='z'
)
data = [trace_terrain]
# Water Surface
if water_depth_grid is not None:
water_mask = water_depth_grid > 0.1
if np.any(water_mask):
water_z = elevation + water_depth_grid
water_z[~water_mask] = np.nan
trace_water = go.Surface(
z=water_z, x=x, y=y,
colorscale=[[0, 'rgba(30,144,255,0.7)'], [1, 'rgba(30,144,255,0.7)']],
showscale=False,
lighting=dict(ambient=0.6, diffuse=0.5, specular=0.8, roughness=0.1),
hoverinfo='skip'
)
data.append(trace_water)
elif add_water:
water_z = np.ones_like(elevation) * water_level
trace_water = go.Surface(
z=water_z, x=x, y=y,
hoverinfo='none',
lighting=dict(ambient=0.6, diffuse=0.6, specular=0.5)
)
data.append(trace_water)
# Layout
fig = go.Figure(data=data)
fig.update_layout(
title=dict(text=title, font=dict(color='white', size=16)),
uirevision='terrain_viz',
scene=dict(
xaxis=dict(title='X (m)', backgroundcolor='#1a1a2e', gridcolor='#444', color='#cccccc'),
yaxis=dict(title='Y (m)', backgroundcolor='#1a1a2e', gridcolor='#444', color='#cccccc'),
zaxis=dict(title='Elevation', backgroundcolor='#1a1a2e', gridcolor='#444', color='#cccccc'),
bgcolor='#0e1117',
camera=dict(
eye=dict(x=1.6, y=-1.6, z=0.8),
center=dict(x=0, y=0, z=-0.2),
up=dict(x=0, y=0, z=1)
) if force_camera else None,
aspectmode='manual',
aspectratio=dict(x=1, y=1, z=0.35)
),
paper_bgcolor='#0e1117',
plot_bgcolor='#0e1117',
height=700,
margin=dict(l=10, r=10, t=50, b=10),
)
return fig