HANSOL commited on
Commit
d34a176
ยท
1 Parent(s): 2be4f60

Fix: Extract renderer module for HuggingFace compatibility

Browse files
app/components/renderer.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ๐ŸŽจ Terrain Renderer - Plotly 3D ์‹œ๊ฐํ™”
3
+ ๋ถ„๋ฆฌ๋œ ๋ชจ๋“ˆ๋กœ HuggingFace Spaces ํ˜ธํ™˜์„ฑ ํ–ฅ์ƒ
4
+ """
5
+ import numpy as np
6
+ import plotly.graph_objects as go
7
+ import os
8
+ try:
9
+ from PIL import Image
10
+ except ImportError:
11
+ Image = None
12
+
13
+
14
+ def render_terrain_plotly(elevation, title, add_water=True, water_level=0,
15
+ texture_path=None, force_camera=True,
16
+ water_depth_grid=None, sediment_grid=None,
17
+ landform_type=None):
18
+ """Plotly ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ 3D Surface - ์‚ฌ์‹ค์  ํ…์Šค์ฒ˜(Biome) ์ ์šฉ
19
+
20
+ Args:
21
+ elevation: 2D numpy array - ๊ณ ๋„ ๋ฐ์ดํ„ฐ
22
+ title: ๊ทธ๋ž˜ํ”„ ์ œ๋ชฉ
23
+ add_water: ๋ฌผ ํ‘œ๋ฉด ์ถ”๊ฐ€ ์—ฌ๋ถ€
24
+ water_level: ํ•ด์ˆ˜๋ฉด ๋†’์ด
25
+ texture_path: ํ…์Šค์ฒ˜ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ
26
+ force_camera: ์นด๋ฉ”๋ผ ์œ„์น˜ ๊ณ ์ • ์—ฌ๋ถ€
27
+ water_depth_grid: ๋ฌผ ๊นŠ์ด ๊ทธ๋ฆฌ๋“œ
28
+ sediment_grid: ํ‡ด์ ๋ฌผ ๊ทธ๋ฆฌ๋“œ
29
+ landform_type: 'river', 'coastal', 'glacial', 'volcanic', 'karst', 'arid'
30
+ """
31
+ h, w = elevation.shape
32
+ x = np.arange(w)
33
+ y = np.arange(h)
34
+
35
+ # ๊ฒฝ์‚ฌ๋„ ๊ณ„์‚ฐ
36
+ dy, dx = np.gradient(elevation)
37
+ slope = np.sqrt(dx**2 + dy**2)
38
+
39
+ # Biome Index (0: ๋ฌผ/๋ชจ๋ž˜, 1: ํ’€, 2: ์•”์„, 3: ๋ˆˆ)
40
+ biome = np.zeros_like(elevation)
41
+ biome[:] = 1 # ๊ธฐ๋ณธ: ํ’€
42
+
43
+ # ํ‡ด์ ์ง€ ํŒ๋ณ„
44
+ sand_level = water_level + 5 if add_water else elevation.min() + 10
45
+ is_deposit = np.zeros_like(elevation, dtype=bool)
46
+
47
+ if sediment_grid is not None:
48
+ is_deposit = (sediment_grid > 0.5)
49
+ else:
50
+ is_deposit = (elevation < sand_level) & (slope < 0.5)
51
+ biome[is_deposit] = 0
52
+
53
+ # ์•”์„ (๊ฒฝ์‚ฌ๊ฐ€ ๊ธ‰ํ•œ ๊ณณ)
54
+ biome[slope > 1.2] = 2
55
+
56
+ # ์ง€ํ˜• ์œ ํ˜•๋ณ„ ์ฒ˜๋ฆฌ
57
+ if landform_type == 'glacial':
58
+ biome[elevation > 50] = 3
59
+ biome[slope > 1.5] = 2
60
+ elif landform_type in ['river', 'coastal']:
61
+ if water_depth_grid is not None:
62
+ is_water = water_depth_grid > 0.5
63
+ biome[is_water] = 0
64
+ biome[elevation < 0] = 0
65
+ elif landform_type == 'arid':
66
+ biome[slope < 0.8] = 0
67
+
68
+ # ๋…ธ์ด์ฆˆ ์ถ”๊ฐ€
69
+ noise = np.random.normal(0, 0.2, elevation.shape)
70
+ biome_noisy = np.clip(biome + noise, 0, 3).round(2)
71
+
72
+ # ์ปฌ๋Ÿฌ์Šค์ผ€์ผ ์„ค์ •
73
+ if landform_type == 'glacial':
74
+ realistic_colorscale = [
75
+ [0.0, '#E6C288'], [0.25, '#E6C288'],
76
+ [0.25, '#556B2F'], [0.5, '#556B2F'],
77
+ [0.5, '#808080'], [0.75, '#808080'],
78
+ [0.75, '#E0FFFF'], [1.0, '#FFFFFF']
79
+ ]
80
+ colorbar_labels = ["ํ‡ด์ (ๅœŸ)", "์‹์ƒ(่‰)", "์•”์„(ๅฒฉ)", "๋น™ํ•˜(ๆฐท)"]
81
+ elif landform_type in ['river', 'coastal']:
82
+ realistic_colorscale = [
83
+ [0.0, '#4682B4'], [0.25, '#4682B4'],
84
+ [0.25, '#556B2F'], [0.5, '#556B2F'],
85
+ [0.5, '#808080'], [0.75, '#808080'],
86
+ [0.75, '#D2B48C'], [1.0, '#D2B48C']
87
+ ]
88
+ colorbar_labels = ["์ˆ˜์—ญ(ๆฐด)", "์‹์ƒ(่‰)", "์•”์„(ๅฒฉ)", "์‚ฌ์งˆ(็ ‚)"]
89
+ elif landform_type == 'arid':
90
+ realistic_colorscale = [
91
+ [0.0, '#EDC9AF'], [0.25, '#EDC9AF'],
92
+ [0.25, '#CD853F'], [0.5, '#CD853F'],
93
+ [0.5, '#808080'], [0.75, '#808080'],
94
+ [0.75, '#DAA520'], [1.0, '#DAA520']
95
+ ]
96
+ colorbar_labels = ["์‚ฌ๋ง‰(็ ‚)", "์•”์งˆ(ๅท–)", "์•”์„(ๅฒฉ)", "๋ชจ๋ž˜(ๆฒ™)"]
97
+ else:
98
+ realistic_colorscale = [
99
+ [0.0, '#E6C288'], [0.25, '#E6C288'],
100
+ [0.25, '#556B2F'], [0.5, '#556B2F'],
101
+ [0.5, '#808080'], [0.75, '#808080'],
102
+ [0.75, '#A0522D'], [1.0, '#A0522D']
103
+ ]
104
+ colorbar_labels = ["ํ‡ด์ (ๅœŸ)", "์‹์ƒ(่‰)", "์•”์„(ๅฒฉ)", "ํ‘œํ† (ๅœŸ)"]
105
+
106
+ # ์‹œ๊ฐ์  ๋…ธ์ด์ฆˆ
107
+ visual_z = (elevation + np.random.normal(0, 0.2, elevation.shape)).round(2)
108
+
109
+ final_surface_color = biome_noisy
110
+ final_colorscale = realistic_colorscale
111
+ final_cmin = 0
112
+ final_cmax = 3
113
+ final_colorbar = dict(
114
+ title=dict(text="์ง€ํ‘œ ์ƒํƒœ", font=dict(color='white')),
115
+ tickvals=[0.37, 1.12, 1.87, 2.62],
116
+ ticktext=colorbar_labels,
117
+ tickfont=dict(color='white')
118
+ )
119
+
120
+ # ํ…์Šค์ฒ˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ
121
+ if texture_path and os.path.exists(texture_path) and Image:
122
+ try:
123
+ img = Image.open(texture_path).convert('L')
124
+ img = img.resize((w, h))
125
+ img_array = np.array(img) / 255.0
126
+ final_surface_color = img_array
127
+ final_colorscale = 'Gray'
128
+ final_cmin = 0
129
+ final_cmax = 1
130
+ final_colorbar = dict(title="ํ…์Šค์ฒ˜ ๋ช…์•”")
131
+ except Exception as e:
132
+ print(f"Texture error: {e}")
133
+
134
+ # 3D Plot
135
+ lighting_effects = dict(ambient=0.4, diffuse=0.5, roughness=0.9, specular=0.1, fresnel=0.2)
136
+
137
+ trace_terrain = go.Surface(
138
+ z=visual_z, x=x, y=y,
139
+ surfacecolor=final_surface_color,
140
+ colorscale=final_colorscale,
141
+ cmin=final_cmin, cmax=final_cmax,
142
+ colorbar=final_colorbar,
143
+ lighting=lighting_effects,
144
+ hoverinfo='z'
145
+ )
146
+
147
+ data = [trace_terrain]
148
+
149
+ # Water Surface
150
+ if water_depth_grid is not None:
151
+ water_mask = water_depth_grid > 0.1
152
+ if np.any(water_mask):
153
+ water_z = elevation + water_depth_grid
154
+ water_z[~water_mask] = np.nan
155
+ trace_water = go.Surface(
156
+ z=water_z, x=x, y=y,
157
+ colorscale=[[0, 'rgba(30,144,255,0.7)'], [1, 'rgba(30,144,255,0.7)']],
158
+ showscale=False,
159
+ lighting=dict(ambient=0.6, diffuse=0.5, specular=0.8, roughness=0.1),
160
+ hoverinfo='skip'
161
+ )
162
+ data.append(trace_water)
163
+ elif add_water:
164
+ water_z = np.ones_like(elevation) * water_level
165
+ trace_water = go.Surface(
166
+ z=water_z, x=x, y=y,
167
+ hoverinfo='none',
168
+ lighting=dict(ambient=0.6, diffuse=0.6, specular=0.5)
169
+ )
170
+ data.append(trace_water)
171
+
172
+ # Layout
173
+ fig = go.Figure(data=data)
174
+ fig.update_layout(
175
+ title=dict(text=title, font=dict(color='white', size=16)),
176
+ uirevision='terrain_viz',
177
+ scene=dict(
178
+ xaxis=dict(title='X (m)', backgroundcolor='#1a1a2e', gridcolor='#444', color='#cccccc'),
179
+ yaxis=dict(title='Y (m)', backgroundcolor='#1a1a2e', gridcolor='#444', color='#cccccc'),
180
+ zaxis=dict(title='Elevation', backgroundcolor='#1a1a2e', gridcolor='#444', color='#cccccc'),
181
+ bgcolor='#0e1117',
182
+ camera=dict(
183
+ eye=dict(x=1.6, y=-1.6, z=0.8),
184
+ center=dict(x=0, y=0, z=-0.2),
185
+ up=dict(x=0, y=0, z=1)
186
+ ) if force_camera else None,
187
+ aspectmode='manual',
188
+ aspectratio=dict(x=1, y=1, z=0.35)
189
+ ),
190
+ paper_bgcolor='#0e1117',
191
+ plot_bgcolor='#0e1117',
192
+ height=700,
193
+ margin=dict(l=10, r=10, t=50, b=10),
194
+ )
195
+
196
+ return fig
pages/1_๐Ÿ“–_Gallery.py CHANGED
@@ -13,7 +13,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
13
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
14
 
15
  from engine.ideal_landforms import IDEAL_LANDFORM_GENERATORS, ANIMATED_LANDFORM_GENERATORS
16
- from app.main import render_terrain_plotly
17
 
18
  st.header("๐Ÿ“– ์ด์ƒ์  ์ง€ํ˜• ๊ฐค๋Ÿฌ๋ฆฌ")
19
  st.markdown("_๊ต๊ณผ์„œ์ ์ธ ์ง€ํ˜• ํ˜•ํƒœ๋ฅผ ๊ธฐํ•˜ํ•™์  ๋ชจ๋ธ๋กœ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค._")
 
13
  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
14
 
15
  from engine.ideal_landforms import IDEAL_LANDFORM_GENERATORS, ANIMATED_LANDFORM_GENERATORS
16
+ from app.components.renderer import render_terrain_plotly
17
 
18
  st.header("๐Ÿ“– ์ด์ƒ์  ์ง€ํ˜• ๊ฐค๋Ÿฌ๋ฆฌ")
19
  st.markdown("_๊ต๊ณผ์„œ์ ์ธ ์ง€ํ˜• ํ˜•ํƒœ๋ฅผ ๊ธฐํ•˜ํ•™์  ๋ชจ๋ธ๋กœ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค._")