HANSOL commited on
Commit ยท
e60b579
1
Parent(s): a8ee0d8
Add 6 new landforms, improve animation, add Overview page
Browse files- app/pages/1_๐_Gallery.py +6 -0
- engine/ideal_landforms.py +288 -0
- pages/1_๐_Gallery.py +44 -64
- pages/2_๐บ๏ธ_Overview.py +124 -0
app/pages/1_๐_Gallery.py
CHANGED
|
@@ -54,6 +54,7 @@ if category == "๐ ํ์ฒ ์งํ":
|
|
| 54 |
"๐๏ธ V์๊ณก (V-Valley)": "v_valley",
|
| 55 |
"๐ ๋ง์ํ์ฒ (Braided River)": "braided_river",
|
| 56 |
"๐ง ํญํฌ (Waterfall)": "waterfall",
|
|
|
|
| 57 |
}
|
| 58 |
elif category == "๐บ ์ผ๊ฐ์ฃผ ์ ํ":
|
| 59 |
landform_options = {
|
|
@@ -61,6 +62,7 @@ elif category == "๐บ ์ผ๊ฐ์ฃผ ์ ํ":
|
|
| 61 |
"๐ฆถ ์กฐ์กฑ์ ์ผ๊ฐ์ฃผ (Bird-foot)": "bird_foot_delta",
|
| 62 |
"๐ ํธ์ ์ผ๊ฐ์ฃผ (Arcuate)": "arcuate_delta",
|
| 63 |
"๐ ์ฒจ๋์ ์ผ๊ฐ์ฃผ (Cuspate)": "cuspate_delta",
|
|
|
|
| 64 |
}
|
| 65 |
elif category == "โ๏ธ ๋นํ ์งํ":
|
| 66 |
landform_options = {
|
|
@@ -70,6 +72,7 @@ elif category == "โ๏ธ ๋นํ ์งํ":
|
|
| 70 |
"๐ ํผ์ค๋ฅด๋ (Fjord)": "fjord",
|
| 71 |
"๐ฅ ๋๋ผ๋ฆฐ (Drumlin)": "drumlin",
|
| 72 |
"๐ชจ ๋นํด์ (Moraine)": "moraine",
|
|
|
|
| 73 |
}
|
| 74 |
elif category == "๐ ํ์ฐ ์งํ":
|
| 75 |
landform_options = {
|
|
@@ -92,6 +95,9 @@ elif category == "๐๏ธ ๊ฑด์กฐ ์งํ":
|
|
| 92 |
"๐ฐ ํก์ฌ๊ตฌ (Transverse Dune)": "transverse_dune",
|
| 93 |
"โญ ์ฑ์ฌ๊ตฌ (Star Dune)": "star_dune",
|
| 94 |
"๐ฟ ๋ฉ์ฌ/๋ทฐํธ (Mesa/Butte)": "mesa_butte",
|
|
|
|
|
|
|
|
|
|
| 95 |
}
|
| 96 |
else: # ํด์ ์งํ
|
| 97 |
landform_options = {
|
|
|
|
| 54 |
"๐๏ธ V์๊ณก (V-Valley)": "v_valley",
|
| 55 |
"๐ ๋ง์ํ์ฒ (Braided River)": "braided_river",
|
| 56 |
"๐ง ํญํฌ (Waterfall)": "waterfall",
|
| 57 |
+
"๐ง ์ฒ์ ์ฒ (Perched River)": "perched_river",
|
| 58 |
}
|
| 59 |
elif category == "๐บ ์ผ๊ฐ์ฃผ ์ ํ":
|
| 60 |
landform_options = {
|
|
|
|
| 62 |
"๐ฆถ ์กฐ์กฑ์ ์ผ๊ฐ์ฃผ (Bird-foot)": "bird_foot_delta",
|
| 63 |
"๐ ํธ์ ์ผ๊ฐ์ฃผ (Arcuate)": "arcuate_delta",
|
| 64 |
"๐ ์ฒจ๋์ ์ผ๊ฐ์ฃผ (Cuspate)": "cuspate_delta",
|
| 65 |
+
"๐ ์์ค์ถ์ด๋ฆฌ (Estuary)": "estuary",
|
| 66 |
}
|
| 67 |
elif category == "โ๏ธ ๋นํ ์งํ":
|
| 68 |
landform_options = {
|
|
|
|
| 72 |
"๐ ํผ์ค๋ฅด๋ (Fjord)": "fjord",
|
| 73 |
"๐ฅ ๋๋ผ๋ฆฐ (Drumlin)": "drumlin",
|
| 74 |
"๐ชจ ๋นํด์ (Moraine)": "moraine",
|
| 75 |
+
"๐ก๏ธ ์๋ ํธ (Arรชte)": "arete",
|
| 76 |
}
|
| 77 |
elif category == "๐ ํ์ฐ ์งํ":
|
| 78 |
landform_options = {
|
|
|
|
| 95 |
"๐ฐ ํก์ฌ๊ตฌ (Transverse Dune)": "transverse_dune",
|
| 96 |
"โญ ์ฑ์ฌ๊ตฌ (Star Dune)": "star_dune",
|
| 97 |
"๐ฟ ๋ฉ์ฌ/๋ทฐํธ (Mesa/Butte)": "mesa_butte",
|
| 98 |
+
"๐๏ธ ์๋ (Wadi)": "wadi",
|
| 99 |
+
"๐ชถ ํ๋ผ์ผ (Playa)": "playa",
|
| 100 |
+
"๐ ๋ฒ์ฏ๋ฐ์ (Pedestal Rock)": "pedestal_rock",
|
| 101 |
}
|
| 102 |
else: # ํด์ ์งํ
|
| 103 |
landform_options = {
|
engine/ideal_landforms.py
CHANGED
|
@@ -2063,7 +2063,281 @@ def create_star_dune(grid_size: int = 100, stage: float = 1.0,
|
|
| 2063 |
return elevation
|
| 2064 |
|
| 2065 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2066 |
# ์ ๋๋ฉ์ด์
์์ฑ๊ธฐ ๋งคํ
|
|
|
|
| 2067 |
ANIMATED_LANDFORM_GENERATORS = {
|
| 2068 |
'delta': create_delta_animated,
|
| 2069 |
'alluvial_fan': create_alluvial_fan_animated,
|
|
@@ -2104,6 +2378,13 @@ ANIMATED_LANDFORM_GENERATORS = {
|
|
| 2104 |
'karren': create_karren,
|
| 2105 |
'transverse_dune': create_transverse_dune,
|
| 2106 |
'star_dune': create_star_dune,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2107 |
}
|
| 2108 |
|
| 2109 |
# ์งํ ์์ฑ ํจ์ ๋งคํ
|
|
@@ -2147,5 +2428,12 @@ IDEAL_LANDFORM_GENERATORS = {
|
|
| 2147 |
'karren': lambda gs: create_karren(gs, 1.0),
|
| 2148 |
'transverse_dune': lambda gs: create_transverse_dune(gs, 1.0),
|
| 2149 |
'star_dune': lambda gs: create_star_dune(gs, 1.0),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2150 |
}
|
| 2151 |
|
|
|
|
| 2063 |
return elevation
|
| 2064 |
|
| 2065 |
|
| 2066 |
+
# ============================================
|
| 2067 |
+
# ์ถ๊ฐ ํ์ฅ ์งํ๋ค (Additional Expansion)
|
| 2068 |
+
# ============================================
|
| 2069 |
+
|
| 2070 |
+
def create_perched_river(grid_size: int = 100, stage: float = 1.0):
|
| 2071 |
+
"""์ฒ์ ์ฒ (Perched River) - ์์ฐ์ ๋ฐฉ ๋ฐ๋ฌ๋ก ํ์์ด ์ฃผ๋ณ๋ณด๋ค ๋์
|
| 2072 |
+
|
| 2073 |
+
Stage 0~0.5: ๋ฒ๋์ ํ์ฑ + ์์ฐ์ ๋ฐฉ ๋ฐ๋ฌ
|
| 2074 |
+
Stage 0.5~1.0: ํ์ ํด์ ์ผ๋ก ์ฃผ๋ณ๋ณด๋ค ๋์์ง (์ฒ์ ์ฒ)
|
| 2075 |
+
"""
|
| 2076 |
+
h, w = grid_size, grid_size
|
| 2077 |
+
elevation = np.zeros((h, w))
|
| 2078 |
+
|
| 2079 |
+
# ๋ฒ๋์ ๊ธฐ๋ณธ ๋์ด
|
| 2080 |
+
base_height = 10.0
|
| 2081 |
+
elevation[:] = base_height
|
| 2082 |
+
|
| 2083 |
+
# ํ์ฒ ์ค์ฌ์
|
| 2084 |
+
center = w // 2
|
| 2085 |
+
|
| 2086 |
+
# ์์ฐ์ ๋ฐฉ ๋ฐ๋ฌ (stage์ ๋ฐ๋ผ)
|
| 2087 |
+
levee_height = 8.0 * stage
|
| 2088 |
+
levee_width = int(w * 0.15)
|
| 2089 |
+
|
| 2090 |
+
for c in range(w):
|
| 2091 |
+
dist_from_center = abs(c - center)
|
| 2092 |
+
|
| 2093 |
+
if dist_from_center < levee_width:
|
| 2094 |
+
# ํ์ (ํ์ฒ ๋ฐ๋ฅ) - ์ฃผ๋ณ๋ณด๋ค ๋์์ง
|
| 2095 |
+
if dist_from_center < 5:
|
| 2096 |
+
river_bed_height = base_height + levee_height * 0.8 * stage
|
| 2097 |
+
elevation[:, c] = river_bed_height
|
| 2098 |
+
else:
|
| 2099 |
+
# ์์ฐ์ ๋ฐฉ (์ ๋ฐฉ)
|
| 2100 |
+
decay = 1 - (dist_from_center - 5) / (levee_width - 5)
|
| 2101 |
+
elevation[:, c] = base_height + levee_height * decay * stage
|
| 2102 |
+
else:
|
| 2103 |
+
# ๋ฐฐํ์ต์ง (๋ฎ์ ๊ณณ)
|
| 2104 |
+
backswamp_depth = 3.0 * stage
|
| 2105 |
+
elevation[:, c] = base_height - backswamp_depth
|
| 2106 |
+
|
| 2107 |
+
return elevation
|
| 2108 |
+
|
| 2109 |
+
|
| 2110 |
+
def create_arete(grid_size: int = 100, stage: float = 1.0):
|
| 2111 |
+
"""์๋ ํธ (Arรชte) - ๋นํ์ ์ํด ํ์ฑ๋ ๋ ์นด๋ก์ด ๋ฅ์
|
| 2112 |
+
|
| 2113 |
+
๋ ๊ถ๊ณก ์ฌ์ด์ ๋ ์นด๋ก์ด ๋ฅ์
|
| 2114 |
+
"""
|
| 2115 |
+
h, w = grid_size, grid_size
|
| 2116 |
+
elevation = np.zeros((h, w))
|
| 2117 |
+
|
| 2118 |
+
# ๊ธฐ๋ณธ ๊ณ ์ฐ ์งํ
|
| 2119 |
+
base_height = 100.0
|
| 2120 |
+
elevation[:] = base_height
|
| 2121 |
+
|
| 2122 |
+
center = w // 2
|
| 2123 |
+
|
| 2124 |
+
# ์์ชฝ์ ๊ถ๊ณก ํ์ฑ
|
| 2125 |
+
cirque_depth = 60.0 * stage
|
| 2126 |
+
cirque_radius = int(w * 0.35)
|
| 2127 |
+
|
| 2128 |
+
for r in range(h):
|
| 2129 |
+
for c in range(w):
|
| 2130 |
+
# ์ผ์ชฝ ๊ถ๊ณก
|
| 2131 |
+
left_cx = center - int(w * 0.25)
|
| 2132 |
+
left_cy = int(h * 0.5)
|
| 2133 |
+
dist_left = np.sqrt((r - left_cy)**2 + (c - left_cx)**2)
|
| 2134 |
+
|
| 2135 |
+
# ์ค๋ฅธ์ชฝ ๊ถ๊ณก
|
| 2136 |
+
right_cx = center + int(w * 0.25)
|
| 2137 |
+
right_cy = int(h * 0.5)
|
| 2138 |
+
dist_right = np.sqrt((r - right_cy)**2 + (c - right_cx)**2)
|
| 2139 |
+
|
| 2140 |
+
if dist_left < cirque_radius:
|
| 2141 |
+
bowl_depth = cirque_depth * (1 - (dist_left / cirque_radius)**2)
|
| 2142 |
+
elevation[r, c] = min(elevation[r, c], base_height - bowl_depth)
|
| 2143 |
+
|
| 2144 |
+
if dist_right < cirque_radius:
|
| 2145 |
+
bowl_depth = cirque_depth * (1 - (dist_right / cirque_radius)**2)
|
| 2146 |
+
elevation[r, c] = min(elevation[r, c], base_height - bowl_depth)
|
| 2147 |
+
|
| 2148 |
+
# ์ค์ ๋ฅ์ (์๋ ํธ) ๊ฐ์กฐ
|
| 2149 |
+
ridge_width = 5
|
| 2150 |
+
for c in range(center - ridge_width, center + ridge_width):
|
| 2151 |
+
if 0 <= c < w:
|
| 2152 |
+
sharpness = 1 - abs(c - center) / ridge_width
|
| 2153 |
+
elevation[:, c] = base_height + 10.0 * sharpness * stage
|
| 2154 |
+
|
| 2155 |
+
return elevation
|
| 2156 |
+
|
| 2157 |
+
|
| 2158 |
+
def create_wadi(grid_size: int = 100, stage: float = 1.0):
|
| 2159 |
+
"""์๋ (Wadi) - ๊ฑด์กฐ์ง์ญ ์ผ์์ ํ์ฒ ๊ณ๊ณก
|
| 2160 |
+
|
| 2161 |
+
ํ์์ ๊ฑด์กฐ, ์ฐ๊ธฐ์๋ง ๋ฌผ์ด ํ๋ฅด๋ ๊ณ๊ณก
|
| 2162 |
+
"""
|
| 2163 |
+
h, w = grid_size, grid_size
|
| 2164 |
+
elevation = np.zeros((h, w))
|
| 2165 |
+
|
| 2166 |
+
# ๊ฑด์กฐ ๊ณ ์
|
| 2167 |
+
base_height = 50.0
|
| 2168 |
+
elevation[:] = base_height
|
| 2169 |
+
|
| 2170 |
+
# ์๋ ๊ณ๊ณก ์์ฑ (๊ตฌ๋ถ๊ตฌ๋ถ)
|
| 2171 |
+
center = w // 2
|
| 2172 |
+
valley_depth = 25.0 * stage
|
| 2173 |
+
valley_width = int(w * 0.2)
|
| 2174 |
+
|
| 2175 |
+
for r in range(h):
|
| 2176 |
+
# ๊ตฌ๋ถ๊ตฌ๋ถํ ๊ณ๊ณก ์ค์ฌ
|
| 2177 |
+
offset = int(15 * np.sin(r * 0.08))
|
| 2178 |
+
valley_center = center + offset
|
| 2179 |
+
|
| 2180 |
+
for c in range(w):
|
| 2181 |
+
dist = abs(c - valley_center)
|
| 2182 |
+
if dist < valley_width:
|
| 2183 |
+
# V์ํ ๊ณ๊ณก
|
| 2184 |
+
depth = valley_depth * (1 - dist / valley_width)
|
| 2185 |
+
elevation[r, c] = base_height - depth
|
| 2186 |
+
|
| 2187 |
+
# ๋ชจ๋/์๊ฐ ๋ฐ๋ฅ (ํํ)
|
| 2188 |
+
for r in range(h):
|
| 2189 |
+
offset = int(15 * np.sin(r * 0.08))
|
| 2190 |
+
valley_center = center + offset
|
| 2191 |
+
for c in range(valley_center - 3, valley_center + 3):
|
| 2192 |
+
if 0 <= c < w:
|
| 2193 |
+
elevation[r, c] = base_height - valley_depth + 2 # ํํํ ๋ฐ๋ฅ
|
| 2194 |
+
|
| 2195 |
+
return elevation
|
| 2196 |
+
|
| 2197 |
+
|
| 2198 |
+
def create_playa(grid_size: int = 100, stage: float = 1.0):
|
| 2199 |
+
"""ํ๋ผ์ผ (Playa) - ๊ฑด์กฐ ํธ์ ๋ฐ๋ฅ
|
| 2200 |
+
|
| 2201 |
+
๊ฑด์กฐ์ง์ญ์์ ๋ฌผ์ด ์ฆ๋ฐํ๊ณ ๋จ์ ํํํ ํธ์ ๋ฐ๋ฅ
|
| 2202 |
+
"""
|
| 2203 |
+
h, w = grid_size, grid_size
|
| 2204 |
+
elevation = np.zeros((h, w))
|
| 2205 |
+
|
| 2206 |
+
# ๋ถ์ง ์งํ
|
| 2207 |
+
center_r, center_c = h // 2, w // 2
|
| 2208 |
+
basin_radius = int(min(h, w) * 0.4)
|
| 2209 |
+
|
| 2210 |
+
for r in range(h):
|
| 2211 |
+
for c in range(w):
|
| 2212 |
+
dist = np.sqrt((r - center_r)**2 + (c - center_c)**2)
|
| 2213 |
+
|
| 2214 |
+
if dist < basin_radius:
|
| 2215 |
+
# ๋ถ์ง ๋ด๋ถ (ํ๋ผ์ผ)
|
| 2216 |
+
# ๋งค์ฐ ํํํ ํธ์ ๋ฐ๋ฅ
|
| 2217 |
+
elevation[r, c] = 10.0 + np.random.uniform(0, 0.5) # ๊ฑฐ์ ํํ
|
| 2218 |
+
else:
|
| 2219 |
+
# ๋ถ์ง ์ธ๋ถ (์ฐ์ง)
|
| 2220 |
+
rim_height = 50.0 * (1 - basin_radius / (dist + 1))
|
| 2221 |
+
elevation[r, c] = 30.0 + rim_height * stage
|
| 2222 |
+
|
| 2223 |
+
# ์๊ธ ๊ฒฐ์ ํจํด (๋ค๊ฐํ)
|
| 2224 |
+
if stage > 0.7:
|
| 2225 |
+
for i in range(10):
|
| 2226 |
+
poly_r = center_r + np.random.randint(-basin_radius//2, basin_radius//2)
|
| 2227 |
+
poly_c = center_c + np.random.randint(-basin_radius//2, basin_radius//2)
|
| 2228 |
+
poly_size = np.random.randint(5, 15)
|
| 2229 |
+
for dr in range(-poly_size, poly_size):
|
| 2230 |
+
for dc in range(-poly_size, poly_size):
|
| 2231 |
+
if 0 <= poly_r+dr < h and 0 <= poly_c+dc < w:
|
| 2232 |
+
if abs(dr) + abs(dc) == poly_size - 1: # ํ
๋๋ฆฌ
|
| 2233 |
+
elevation[poly_r+dr, poly_c+dc] += 0.3
|
| 2234 |
+
|
| 2235 |
+
return elevation
|
| 2236 |
+
|
| 2237 |
+
|
| 2238 |
+
def create_pedestal_rock(grid_size: int = 100, stage: float = 1.0):
|
| 2239 |
+
"""๋ฒ์ฏ๋ฐ์ (Pedestal Rock) - ๋ฐ๋์ ์ํ ์ฐจ๋ณํํ ์งํ
|
| 2240 |
+
|
| 2241 |
+
Stage 0~0.3: ์๋ ์์ ๊ธฐ๋ฅ
|
| 2242 |
+
Stage 0.3~0.7: ๋ฐ๋์ ์ํ ํ๋ถ ์นจ์ (์ฐ๋ง์์ฉ)
|
| 2243 |
+
Stage 0.7~1.0: ๋ฒ์ฏ ๋ชจ์ ์์ฑ (์ค๊ธฐ๊ฐ ๋งค์ฐ ์์์ง)
|
| 2244 |
+
|
| 2245 |
+
๋ฐ๋์ ์ค๋ ค์จ ๋ชจ๋๊ฐ ํ๋ถ๋ฅผ ๊น์๋ (์งํ ๊ฐ๊น์ธ์๋ก ๋ชจ๋ ๋๋ ๋์)
|
| 2246 |
+
"""
|
| 2247 |
+
h, w = grid_size, grid_size
|
| 2248 |
+
elevation = np.zeros((h, w))
|
| 2249 |
+
|
| 2250 |
+
# ์ฌ๋ง ํ์
|
| 2251 |
+
base_height = 5.0
|
| 2252 |
+
elevation[:] = base_height
|
| 2253 |
+
|
| 2254 |
+
# ๋ฒ์ฏ๋ฐ์ ์ฌ๋ฌ ๊ฐ
|
| 2255 |
+
num_rocks = 3
|
| 2256 |
+
np.random.seed(42)
|
| 2257 |
+
|
| 2258 |
+
for i in range(num_rocks):
|
| 2259 |
+
# ์์น
|
| 2260 |
+
rock_r = np.random.randint(h // 4, 3 * h // 4)
|
| 2261 |
+
rock_c = np.random.randint(w // 4, 3 * w // 4)
|
| 2262 |
+
|
| 2263 |
+
# ์๋ ๋ฐ์ ํฌ๊ธฐ (stage 0์์์ ํฌ๊ธฐ)
|
| 2264 |
+
original_radius = np.random.randint(10, 16)
|
| 2265 |
+
rock_height = np.random.uniform(25, 40)
|
| 2266 |
+
|
| 2267 |
+
# stage์ ๋ฐ๋ฅธ ์นจ์ ์ ๋ (stage ๋์์๋ก ํ๋ถ ๋ ๊น์)
|
| 2268 |
+
erosion_factor = stage # 0~1
|
| 2269 |
+
|
| 2270 |
+
for r in range(h):
|
| 2271 |
+
for c in range(w):
|
| 2272 |
+
dist = np.sqrt((r - rock_r)**2 + (c - rock_c)**2)
|
| 2273 |
+
|
| 2274 |
+
if dist < original_radius:
|
| 2275 |
+
# ๋ฐ์ ๋ด๋ถ - ๋์ด์ ๋ฐ๋ผ ๋ฐ๊ฒฝ์ด ๋ค๋ฆ
|
| 2276 |
+
# ์๋ถ: ์๋ ๋ฐ๊ฒฝ ์ ์ง
|
| 2277 |
+
# ํ๋ถ: stage์ ๋ฐ๋ผ ๊น์
|
| 2278 |
+
|
| 2279 |
+
# ๊ฐ ๋์ด์์์ ์ ํจ ๋ฐ๊ฒฝ ๊ณ์ฐ
|
| 2280 |
+
for z_level in range(int(rock_height)):
|
| 2281 |
+
# ์งํ์์์ ๋์ด ๋น์จ (0=๋ฐ๋ฅ, 1=๊ผญ๋๊ธฐ)
|
| 2282 |
+
height_ratio = z_level / rock_height
|
| 2283 |
+
|
| 2284 |
+
# ํ๋ถ์ผ์๋ก ๋ฐ๋ ์นจ์ ์ฌํจ (์งํ ๊ฐ๊น์ธ์๋ก)
|
| 2285 |
+
if height_ratio < 0.5:
|
| 2286 |
+
# ํ๋ถ: ์นจ์์ผ๋ก ๋ฐ๊ฒฝ ๊ฐ์
|
| 2287 |
+
erosion_at_height = erosion_factor * (1 - height_ratio * 2) # ๋ฐ๋ฅ์์ ์ต๋
|
| 2288 |
+
current_radius = original_radius * (1 - erosion_at_height * 0.7)
|
| 2289 |
+
else:
|
| 2290 |
+
# ์๋ถ: ์๋ ๋ฐ๊ฒฝ ์ ์ง (๋ชจ์ ๋ถ๋ถ)
|
| 2291 |
+
current_radius = original_radius
|
| 2292 |
+
|
| 2293 |
+
if dist < current_radius:
|
| 2294 |
+
elevation[r, c] = max(elevation[r, c], base_height + z_level)
|
| 2295 |
+
|
| 2296 |
+
return elevation
|
| 2297 |
+
|
| 2298 |
+
|
| 2299 |
+
def create_estuary(grid_size: int = 100, stage: float = 1.0):
|
| 2300 |
+
"""์์ค์ถ์ด๋ฆฌ (Estuary) - ์ผ๊ฐ๊ฐ, ์กฐ์ ์ํฅ
|
| 2301 |
+
|
| 2302 |
+
์กฐ์์ ์ํฅ์ ๋ฐ๋ ๋์ ํ๊ตฌ
|
| 2303 |
+
"""
|
| 2304 |
+
h, w = grid_size, grid_size
|
| 2305 |
+
elevation = np.zeros((h, w))
|
| 2306 |
+
|
| 2307 |
+
# ์ก์ง ๊ธฐ๋ณธ
|
| 2308 |
+
land_height = 20.0
|
| 2309 |
+
elevation[:] = land_height
|
| 2310 |
+
|
| 2311 |
+
# ์์ค์ถ์ด๋ฆฌ (๊น๋๊ธฐ ๋ชจ์)
|
| 2312 |
+
apex_row = int(h * 0.1)
|
| 2313 |
+
center = w // 2
|
| 2314 |
+
|
| 2315 |
+
for r in range(h):
|
| 2316 |
+
# ํ๋ฅ๋ก ๊ฐ์๋ก ๋์ด์ง
|
| 2317 |
+
progress = (r - apex_row) / (h - apex_row) if r > apex_row else 0
|
| 2318 |
+
estuary_width = int(5 + 40 * progress * stage)
|
| 2319 |
+
|
| 2320 |
+
for c in range(w):
|
| 2321 |
+
dist = abs(c - center)
|
| 2322 |
+
|
| 2323 |
+
if r < apex_row:
|
| 2324 |
+
# ์๋ฅ ํ์ฒ (์ข์)
|
| 2325 |
+
if dist < 5:
|
| 2326 |
+
elevation[r, c] = -5.0
|
| 2327 |
+
elif dist < estuary_width:
|
| 2328 |
+
# ์์ค์ถ์ด๋ฆฌ ์์ญ
|
| 2329 |
+
depth = 10.0 * (1 - dist / estuary_width) * (0.5 + 0.5 * progress)
|
| 2330 |
+
elevation[r, c] = -depth
|
| 2331 |
+
|
| 2332 |
+
# ์กฐ๊ฐ๋ (tide flat)
|
| 2333 |
+
if dist >= estuary_width - 10 and dist < estuary_width and r > apex_row:
|
| 2334 |
+
elevation[r, c] = max(elevation[r, c], -1.0) # ์กฐ๊ฐ๋ (์์)
|
| 2335 |
+
|
| 2336 |
+
return elevation
|
| 2337 |
+
|
| 2338 |
+
|
| 2339 |
# ์ ๋๋ฉ์ด์
์์ฑ๊ธฐ ๋งคํ
|
| 2340 |
+
|
| 2341 |
ANIMATED_LANDFORM_GENERATORS = {
|
| 2342 |
'delta': create_delta_animated,
|
| 2343 |
'alluvial_fan': create_alluvial_fan_animated,
|
|
|
|
| 2378 |
'karren': create_karren,
|
| 2379 |
'transverse_dune': create_transverse_dune,
|
| 2380 |
'star_dune': create_star_dune,
|
| 2381 |
+
# ์ถ๊ฐ ํ์ฅ ์งํ
|
| 2382 |
+
'perched_river': create_perched_river,
|
| 2383 |
+
'arete': create_arete,
|
| 2384 |
+
'wadi': create_wadi,
|
| 2385 |
+
'playa': create_playa,
|
| 2386 |
+
'pedestal_rock': create_pedestal_rock,
|
| 2387 |
+
'estuary': create_estuary,
|
| 2388 |
}
|
| 2389 |
|
| 2390 |
# ์งํ ์์ฑ ํจ์ ๋งคํ
|
|
|
|
| 2428 |
'karren': lambda gs: create_karren(gs, 1.0),
|
| 2429 |
'transverse_dune': lambda gs: create_transverse_dune(gs, 1.0),
|
| 2430 |
'star_dune': lambda gs: create_star_dune(gs, 1.0),
|
| 2431 |
+
# ์ถ๊ฐ ํ์ฅ ์งํ
|
| 2432 |
+
'perched_river': lambda gs: create_perched_river(gs, 1.0),
|
| 2433 |
+
'arete': lambda gs: create_arete(gs, 1.0),
|
| 2434 |
+
'wadi': lambda gs: create_wadi(gs, 1.0),
|
| 2435 |
+
'playa': lambda gs: create_playa(gs, 1.0),
|
| 2436 |
+
'pedestal_rock': lambda gs: create_pedestal_rock(gs, 1.0),
|
| 2437 |
+
'estuary': lambda gs: create_estuary(gs, 1.0),
|
| 2438 |
}
|
| 2439 |
|
pages/1_๐_Gallery.py
CHANGED
|
@@ -8,25 +8,12 @@ import matplotlib.pyplot as plt
|
|
| 8 |
import sys
|
| 9 |
import os
|
| 10 |
|
| 11 |
-
# ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ๊ฒฝ๋ก์ ์ถ๊ฐ
|
| 12 |
-
|
| 13 |
-
sys.path.insert(0,
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
from renderer import render_terrain_plotly
|
| 18 |
-
IMPORT_OK = True
|
| 19 |
-
except Exception as e:
|
| 20 |
-
st.error(f"Import Error: {e}")
|
| 21 |
-
IMPORT_OK = False
|
| 22 |
-
IDEAL_LANDFORM_GENERATORS = {}
|
| 23 |
-
ANIMATED_LANDFORM_GENERATORS = {}
|
| 24 |
-
|
| 25 |
-
# ์ธ์
์ํ ์ด๊ธฐํ (auto_playing ์ํ ํ์ธ)
|
| 26 |
-
if 'auto_playing' not in st.session_state:
|
| 27 |
-
st.session_state['auto_playing'] = False
|
| 28 |
-
if 'auto_stage' not in st.session_state:
|
| 29 |
-
st.session_state['auto_stage'] = 0.0
|
| 30 |
|
| 31 |
st.header("๐ ์ด์์ ์งํ ๊ฐค๋ฌ๋ฆฌ")
|
| 32 |
st.markdown("_๊ต๊ณผ์์ ์ธ ์งํ ํํ๋ฅผ ๊ธฐํํ์ ๋ชจ๋ธ๋ก ์๊ฐํํฉ๋๋ค._")
|
|
@@ -67,6 +54,7 @@ if category == "๐ ํ์ฒ ์งํ":
|
|
| 67 |
"๐๏ธ V์๊ณก (V-Valley)": "v_valley",
|
| 68 |
"๐ ๋ง์ํ์ฒ (Braided River)": "braided_river",
|
| 69 |
"๐ง ํญํฌ (Waterfall)": "waterfall",
|
|
|
|
| 70 |
}
|
| 71 |
elif category == "๐บ ์ผ๊ฐ์ฃผ ์ ํ":
|
| 72 |
landform_options = {
|
|
@@ -74,6 +62,7 @@ elif category == "๐บ ์ผ๊ฐ์ฃผ ์ ํ":
|
|
| 74 |
"๐ฆถ ์กฐ์กฑ์ ์ผ๊ฐ์ฃผ (Bird-foot)": "bird_foot_delta",
|
| 75 |
"๐ ํธ์ ์ผ๊ฐ์ฃผ (Arcuate)": "arcuate_delta",
|
| 76 |
"๐ ์ฒจ๋์ ์ผ๊ฐ์ฃผ (Cuspate)": "cuspate_delta",
|
|
|
|
| 77 |
}
|
| 78 |
elif category == "โ๏ธ ๋นํ ์งํ":
|
| 79 |
landform_options = {
|
|
@@ -83,6 +72,7 @@ elif category == "โ๏ธ ๋นํ ์งํ":
|
|
| 83 |
"๐ ํผ์ค๋ฅด๋ (Fjord)": "fjord",
|
| 84 |
"๐ฅ ๋๋ผ๋ฆฐ (Drumlin)": "drumlin",
|
| 85 |
"๐ชจ ๋นํด์ (Moraine)": "moraine",
|
|
|
|
| 86 |
}
|
| 87 |
elif category == "๐ ํ์ฐ ์งํ":
|
| 88 |
landform_options = {
|
|
@@ -105,6 +95,9 @@ elif category == "๐๏ธ ๊ฑด์กฐ ์งํ":
|
|
| 105 |
"๐ฐ ํก์ฌ๊ตฌ (Transverse Dune)": "transverse_dune",
|
| 106 |
"โญ ์ฑ์ฌ๊ตฌ (Star Dune)": "star_dune",
|
| 107 |
"๐ฟ ๋ฉ์ฌ/๋ทฐํธ (Mesa/Butte)": "mesa_butte",
|
|
|
|
|
|
|
|
|
|
| 108 |
}
|
| 109 |
else: # ํด์ ์งํ
|
| 110 |
landform_options = {
|
|
@@ -220,14 +213,14 @@ if landform_key in ANIMATED_LANDFORM_GENERATORS:
|
|
| 220 |
stage_value = st.session_state.get('auto_stage', 0.0)
|
| 221 |
st.slider(
|
| 222 |
"ํ์ฑ ๋จ๊ณ (์๋ ์ฌ์ ์ค...)",
|
| 223 |
-
0.0, 1.0, stage_value, 0.
|
| 224 |
key="gallery_stage_slider",
|
| 225 |
disabled=True
|
| 226 |
)
|
| 227 |
else:
|
| 228 |
stage_value = st.slider(
|
| 229 |
"ํ์ฑ ๋จ๊ณ (0% = ์์, 100% = ์์ฑ)",
|
| 230 |
-
0.0, 1.0, 1.0, 0.
|
| 231 |
key="gallery_stage_slider"
|
| 232 |
)
|
| 233 |
|
|
@@ -249,50 +242,37 @@ if landform_key in ANIMATED_LANDFORM_GENERATORS:
|
|
| 249 |
stage_water[r, c] = 3.0
|
| 250 |
|
| 251 |
# 3D ๋ ๋๋ง
|
| 252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
)
|
| 264 |
-
st.write("โ
Debug: render_terrain_plotly ์ฑ๊ณต!")
|
| 265 |
-
st.plotly_chart(fig_stage, use_container_width=True, key="stage_view")
|
| 266 |
-
except Exception as e:
|
| 267 |
-
st.error(f"โ Render Error: {e}")
|
| 268 |
|
| 269 |
-
#
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
|
| 272 |
-
|
| 273 |
-
# ๋ก์ปฌ ํ๊ฒฝ: ์๋ ์ฌ์ ๊ธฐ๋ฅ ํ์ฑํ
|
| 274 |
-
col_play, col_step = st.columns(2)
|
| 275 |
-
with col_play:
|
| 276 |
-
if st.button("โถ๏ธ ์๋ ์ฌ์ ์์", key="auto_play"):
|
| 277 |
-
st.session_state['auto_playing'] = True
|
| 278 |
-
st.session_state['auto_stage'] = 0.0
|
| 279 |
-
with col_step:
|
| 280 |
-
if st.button("โน๏ธ ์ ์ง", key="stop_play"):
|
| 281 |
-
st.session_state['auto_playing'] = False
|
| 282 |
-
|
| 283 |
-
if st.session_state.get('auto_playing', False):
|
| 284 |
-
current_stage = st.session_state.get('auto_stage', 0.0)
|
| 285 |
-
if current_stage < 1.0:
|
| 286 |
-
st.session_state['auto_stage'] = current_stage + 0.1
|
| 287 |
-
import time
|
| 288 |
-
time.sleep(0.5)
|
| 289 |
-
st.rerun()
|
| 290 |
-
else:
|
| 291 |
-
st.session_state['auto_playing'] = False
|
| 292 |
-
st.success("โ
์๋ฃ!")
|
| 293 |
-
|
| 294 |
-
st.caption("๐ก **Tip:** ์นด๋ฉ๋ผ ๊ฐ๋๋ฅผ ๋จผ์ ์กฐ์ ํ ํ ์๋ ์ฌ์ํ๋ฉด ์ ์ง๋ฉ๋๋ค.")
|
| 295 |
-
else:
|
| 296 |
-
# HuggingFace: ์ฌ๋ผ์ด๋๋ง ์ฌ์ฉ
|
| 297 |
-
st.caption("๐ก **Tip:** ์ฌ๋ผ์ด๋๋ฅผ ๋๋๊ทธํด์ ํ์ฑ ๊ณผ์ ์ ํ์ธํ์ธ์. ๋ง์ฐ์ค๋ก 3D ํ์ ๊ฐ๋ฅ!")
|
| 298 |
-
|
|
|
|
| 8 |
import sys
|
| 9 |
import os
|
| 10 |
|
| 11 |
+
# ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ๊ฒฝ๋ก์ ์ถ๊ฐ
|
| 12 |
+
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("_๊ต๊ณผ์์ ์ธ ์งํ ํํ๋ฅผ ๊ธฐํํ์ ๋ชจ๋ธ๋ก ์๊ฐํํฉ๋๋ค._")
|
|
|
|
| 54 |
"๐๏ธ V์๊ณก (V-Valley)": "v_valley",
|
| 55 |
"๐ ๋ง์ํ์ฒ (Braided River)": "braided_river",
|
| 56 |
"๐ง ํญํฌ (Waterfall)": "waterfall",
|
| 57 |
+
"๐ง ์ฒ์ ์ฒ (Perched River)": "perched_river",
|
| 58 |
}
|
| 59 |
elif category == "๐บ ์ผ๊ฐ์ฃผ ์ ํ":
|
| 60 |
landform_options = {
|
|
|
|
| 62 |
"๐ฆถ ์กฐ์กฑ์ ์ผ๊ฐ์ฃผ (Bird-foot)": "bird_foot_delta",
|
| 63 |
"๐ ํธ์ ์ผ๊ฐ์ฃผ (Arcuate)": "arcuate_delta",
|
| 64 |
"๐ ์ฒจ๋์ ์ผ๊ฐ์ฃผ (Cuspate)": "cuspate_delta",
|
| 65 |
+
"๐ ์์ค์ถ์ด๋ฆฌ (Estuary)": "estuary",
|
| 66 |
}
|
| 67 |
elif category == "โ๏ธ ๋นํ ์งํ":
|
| 68 |
landform_options = {
|
|
|
|
| 72 |
"๐ ํผ์ค๋ฅด๋ (Fjord)": "fjord",
|
| 73 |
"๐ฅ ๋๋ผ๋ฆฐ (Drumlin)": "drumlin",
|
| 74 |
"๐ชจ ๋นํด์ (Moraine)": "moraine",
|
| 75 |
+
"๐ก๏ธ ์๋ ํธ (Arรชte)": "arete",
|
| 76 |
}
|
| 77 |
elif category == "๐ ํ์ฐ ์งํ":
|
| 78 |
landform_options = {
|
|
|
|
| 95 |
"๐ฐ ํก์ฌ๊ตฌ (Transverse Dune)": "transverse_dune",
|
| 96 |
"โญ ์ฑ์ฌ๊ตฌ (Star Dune)": "star_dune",
|
| 97 |
"๐ฟ ๋ฉ์ฌ/๋ทฐํธ (Mesa/Butte)": "mesa_butte",
|
| 98 |
+
"๐๏ธ ์๋ (Wadi)": "wadi",
|
| 99 |
+
"๐ชถ ํ๋ผ์ผ (Playa)": "playa",
|
| 100 |
+
"๐ ๋ฒ์ฏ๋ฐ์ (Pedestal Rock)": "pedestal_rock",
|
| 101 |
}
|
| 102 |
else: # ํด์ ์งํ
|
| 103 |
landform_options = {
|
|
|
|
| 213 |
stage_value = st.session_state.get('auto_stage', 0.0)
|
| 214 |
st.slider(
|
| 215 |
"ํ์ฑ ๋จ๊ณ (์๋ ์ฌ์ ์ค...)",
|
| 216 |
+
0.0, 1.0, stage_value, 0.02,
|
| 217 |
key="gallery_stage_slider",
|
| 218 |
disabled=True
|
| 219 |
)
|
| 220 |
else:
|
| 221 |
stage_value = st.slider(
|
| 222 |
"ํ์ฑ ๋จ๊ณ (0% = ์์, 100% = ์์ฑ)",
|
| 223 |
+
0.0, 1.0, 1.0, 0.02,
|
| 224 |
key="gallery_stage_slider"
|
| 225 |
)
|
| 226 |
|
|
|
|
| 242 |
stage_water[r, c] = 3.0
|
| 243 |
|
| 244 |
# 3D ๋ ๋๋ง
|
| 245 |
+
fig_stage = render_terrain_plotly(
|
| 246 |
+
stage_elev,
|
| 247 |
+
f"{selected_landform} - {int(stage_value*100)}%",
|
| 248 |
+
add_water=True,
|
| 249 |
+
water_depth_grid=stage_water,
|
| 250 |
+
water_level=-999,
|
| 251 |
+
force_camera=False, # ์นด๋ฉ๋ผ ์ด๋ ํ์ฉ
|
| 252 |
+
landform_type=landform_type
|
| 253 |
+
)
|
| 254 |
+
st.plotly_chart(fig_stage, use_container_width=True, key="stage_view")
|
| 255 |
|
| 256 |
+
# ์๋ ์ฌ์ (์ธ์
์ํ ํ์ฉ)
|
| 257 |
+
col_play, col_step = st.columns(2)
|
| 258 |
+
with col_play:
|
| 259 |
+
if st.button("โถ๏ธ ์๋ ์ฌ์ ์์", key="auto_play"):
|
| 260 |
+
st.session_state['auto_playing'] = True
|
| 261 |
+
st.session_state['auto_stage'] = 0.0
|
| 262 |
+
with col_step:
|
| 263 |
+
if st.button("โน๏ธ ์ ์ง", key="stop_play"):
|
| 264 |
+
st.session_state['auto_playing'] = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
|
| 266 |
+
# ์๋ ์ฌ์ ์ค์ด๋ฉด stage ์๋ ์ฆ๊ฐ
|
| 267 |
+
if st.session_state.get('auto_playing', False):
|
| 268 |
+
current_stage = st.session_state.get('auto_stage', 0.0)
|
| 269 |
+
if current_stage < 1.0:
|
| 270 |
+
st.session_state['auto_stage'] = current_stage + 0.04
|
| 271 |
+
import time
|
| 272 |
+
time.sleep(0.15)
|
| 273 |
+
st.rerun()
|
| 274 |
+
else:
|
| 275 |
+
st.session_state['auto_playing'] = False
|
| 276 |
+
st.success("โ
์๋ฃ!")
|
| 277 |
|
| 278 |
+
st.caption("๐ก **Tip:** ์นด๋ฉ๋ผ ๊ฐ๋๋ฅผ ๋จผ์ ์กฐ์ ํ ํ ์๋ ์ฌ์ํ๋ฉด ์ ์ง๋ฉ๋๋ค.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pages/2_๐บ๏ธ_Overview.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
๐บ๏ธ ์นดํ
๊ณ ๋ฆฌ ์ ์ฒด ๋ทฐ
|
| 3 |
+
๊ฐ ์นดํ
๊ณ ๋ฆฌ์ ๋ชจ๋ ์งํ์ ํ๋์ ๋น๊ตํฉ๋๋ค.
|
| 4 |
+
"""
|
| 5 |
+
import streamlit as st
|
| 6 |
+
import numpy as np
|
| 7 |
+
import matplotlib.pyplot as plt
|
| 8 |
+
import sys
|
| 9 |
+
import os
|
| 10 |
+
|
| 11 |
+
# ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ๊ฒฝ๋ก์ ์ถ๊ฐ
|
| 12 |
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 13 |
+
|
| 14 |
+
from engine.ideal_landforms import IDEAL_LANDFORM_GENERATORS
|
| 15 |
+
|
| 16 |
+
st.set_page_config(layout="wide")
|
| 17 |
+
st.header("๐บ๏ธ ์นดํ
๊ณ ๋ฆฌ ์ ์ฒด ๋ทฐ")
|
| 18 |
+
st.markdown("_๊ฐ ์นดํ
๊ณ ๋ฆฌ์ ๋ชจ๋ ์งํ์ ํ๋์ ๋น๊ตํฉ๋๋ค._")
|
| 19 |
+
|
| 20 |
+
# ์นดํ
๊ณ ๋ฆฌ ์ ์
|
| 21 |
+
CATEGORIES = {
|
| 22 |
+
"๐ ํ์ฒ ์งํ": {
|
| 23 |
+
"alluvial_fan": "์ ์์ง",
|
| 24 |
+
"free_meander": "์์ ๊ณก๋ฅ",
|
| 25 |
+
"incised_meander": "๊ฐ์
๊ณก๋ฅ",
|
| 26 |
+
"v_valley": "V์๊ณก",
|
| 27 |
+
"braided_river": "๋ง์ํ์ฒ",
|
| 28 |
+
"waterfall": "ํญํฌ",
|
| 29 |
+
"perched_river": "์ฒ์ ์ฒ",
|
| 30 |
+
},
|
| 31 |
+
"๐บ ์ผ๊ฐ์ฃผ ์ ํ": {
|
| 32 |
+
"delta": "์ผ๋ฐ ์ผ๊ฐ์ฃผ",
|
| 33 |
+
"bird_foot_delta": "์กฐ์กฑ์",
|
| 34 |
+
"arcuate_delta": "ํธ์",
|
| 35 |
+
"cuspate_delta": "์ฒจ๋์",
|
| 36 |
+
"estuary": "์์ค์ถ์ด๋ฆฌ",
|
| 37 |
+
},
|
| 38 |
+
"โ๏ธ ๋นํ ์งํ": {
|
| 39 |
+
"u_valley": "U์๊ณก",
|
| 40 |
+
"cirque": "๊ถ๊ณก",
|
| 41 |
+
"horn": "ํธ๋ฅธ",
|
| 42 |
+
"fjord": "ํผ์ค๋ฅด๋",
|
| 43 |
+
"drumlin": "๋๋ผ๋ฆฐ",
|
| 44 |
+
"moraine": "๋นํด์",
|
| 45 |
+
"arete": "์๋ ํธ",
|
| 46 |
+
},
|
| 47 |
+
"๐ ํ์ฐ ์งํ": {
|
| 48 |
+
"shield_volcano": "์์ํ์ฐ",
|
| 49 |
+
"stratovolcano": "์ฑ์ธตํ์ฐ",
|
| 50 |
+
"caldera": "์นผ๋ฐ๋ผ",
|
| 51 |
+
"crater_lake": "ํ๊ตฌํธ",
|
| 52 |
+
"lava_plateau": "์ฉ์๋์ง",
|
| 53 |
+
},
|
| 54 |
+
"๐ฆ ์นด๋ฅด์คํธ ์งํ": {
|
| 55 |
+
"karst_doline": "๋๋ฆฌ๋ค",
|
| 56 |
+
"uvala": "์ฐ๋ฐ๋ผ",
|
| 57 |
+
"tower_karst": "ํ์นด๋ฅด์คํธ",
|
| 58 |
+
"karren": "์นด๋ ",
|
| 59 |
+
},
|
| 60 |
+
"๐๏ธ ๊ฑด์กฐ ์งํ": {
|
| 61 |
+
"barchan": "๋ฐ๋ฅดํ",
|
| 62 |
+
"transverse_dune": "ํก์ฌ๊ตฌ",
|
| 63 |
+
"star_dune": "์ฑ์ฌ๊ตฌ",
|
| 64 |
+
"mesa_butte": "๋ฉ์ฌ/๋ทฐํธ",
|
| 65 |
+
"wadi": "์๋",
|
| 66 |
+
"playa": "ํ๋ผ์ผ",
|
| 67 |
+
"pedestal_rock": "๋ฒ์ฏ๋ฐ์",
|
| 68 |
+
},
|
| 69 |
+
"๐๏ธ ํด์ ์งํ": {
|
| 70 |
+
"coastal_cliff": "ํด์์ ๋ฒฝ",
|
| 71 |
+
"spit_lagoon": "์ฌ์ทจ+์ํธ",
|
| 72 |
+
"tombolo": "์ก๊ณ์ฌ์ฃผ",
|
| 73 |
+
"ria_coast": "๋ฆฌ์์คํด์",
|
| 74 |
+
"sea_arch": "ํด์์์น",
|
| 75 |
+
"coastal_dune": "ํด์์ฌ๊ตฌ",
|
| 76 |
+
},
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
# ์นดํ
๊ณ ๋ฆฌ ์ ํ
|
| 80 |
+
category = st.sidebar.selectbox("์นดํ
๊ณ ๋ฆฌ ์ ํ", list(CATEGORIES.keys()))
|
| 81 |
+
landforms = CATEGORIES[category]
|
| 82 |
+
|
| 83 |
+
# ๊ทธ๋ฆฌ๋ ํฌ๊ธฐ
|
| 84 |
+
grid_size = st.sidebar.slider("ํด์๋", 50, 120, 80)
|
| 85 |
+
|
| 86 |
+
st.subheader(f"{category} - {len(landforms)}์ข
")
|
| 87 |
+
|
| 88 |
+
# ์ปฌ๋ผ ์ ๊ณ์ฐ
|
| 89 |
+
num_landforms = len(landforms)
|
| 90 |
+
cols_per_row = min(4, num_landforms)
|
| 91 |
+
rows = (num_landforms + cols_per_row - 1) // cols_per_row
|
| 92 |
+
|
| 93 |
+
# ์งํ ์์ฑ ๋ฐ ํ์
|
| 94 |
+
landform_items = list(landforms.items())
|
| 95 |
+
|
| 96 |
+
for row_idx in range(rows):
|
| 97 |
+
cols = st.columns(cols_per_row)
|
| 98 |
+
for col_idx, col in enumerate(cols):
|
| 99 |
+
item_idx = row_idx * cols_per_row + col_idx
|
| 100 |
+
if item_idx < num_landforms:
|
| 101 |
+
key, name = landform_items[item_idx]
|
| 102 |
+
|
| 103 |
+
with col:
|
| 104 |
+
st.markdown(f"**{name}**")
|
| 105 |
+
|
| 106 |
+
if key in IDEAL_LANDFORM_GENERATORS:
|
| 107 |
+
try:
|
| 108 |
+
elevation = IDEAL_LANDFORM_GENERATORS[key](grid_size)
|
| 109 |
+
|
| 110 |
+
# 2D ํ๋ทฐ ์ด๋ฏธ์ง
|
| 111 |
+
fig, ax = plt.subplots(figsize=(4, 4))
|
| 112 |
+
im = ax.imshow(elevation, cmap='terrain', origin='lower')
|
| 113 |
+
ax.set_title(name, fontsize=10)
|
| 114 |
+
ax.axis('off')
|
| 115 |
+
plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
|
| 116 |
+
st.pyplot(fig)
|
| 117 |
+
plt.close(fig)
|
| 118 |
+
except Exception as e:
|
| 119 |
+
st.error(f"์ค๋ฅ: {e}")
|
| 120 |
+
else:
|
| 121 |
+
st.warning(f"{key} ๋ฏธ๊ตฌํ")
|
| 122 |
+
|
| 123 |
+
st.markdown("---")
|
| 124 |
+
st.caption("๐ก ๊ฐ ์งํ์ ํด๋ฆญํ๋ฉด Gallery ํ์ด์ง์์ 3D๋ก ์์ธํ๊ฒ ๋ณผ ์ ์์ต๋๋ค.")
|