支持分层地图

This commit is contained in:
KimigaiiWuyi 2023-10-18 00:32:39 +08:00
parent 18a6380078
commit 6ded28d5bc
12 changed files with 58 additions and 18 deletions

1
.gitignore vendored
View File

@ -131,4 +131,5 @@ dmypy.json
# 地图资源 # 地图资源
fastapi_genshin_map/GetMapImage/map_data fastapi_genshin_map/GetMapImage/map_data
fastapi_genshin_map/GetMapImage/resource_data fastapi_genshin_map/GetMapImage/resource_data
fastapi_genshin_map/GetMapImage/icon_data
fastapi_genshin_map/GetMapImage/genshinmap.log fastapi_genshin_map/GetMapImage/genshinmap.log

View File

@ -43,4 +43,4 @@
+ [GPL-3.0 License](https://github.com/KimigaiiWuyi/GenshinUID/blob/main/LICENSE) ©[@KimigaiiWuyi](https://github.com/KimigaiiWuyi) + [GPL-3.0 License](https://github.com/KimigaiiWuyi/GenshinUID/blob/main/LICENSE) ©[@KimigaiiWuyi](https://github.com/KimigaiiWuyi)
## 丨返回图示例 ## 丨返回图示例
![测试.jpg](https://s2.loli.net/2022/10/17/D2cI5tQdgVk3Uuz.jpg) ![测试.jpg](https://s2.loli.net/2023/10/18/Khd5LRQF3HqrEVD.jpg)

View File

@ -6,7 +6,7 @@ import numpy as np
from sklearn.cluster import KMeans from sklearn.cluster import KMeans
from shapely.geometry import Point, Polygon from shapely.geometry import Point, Polygon
from .models import XYPoint from .models import XYPoint, XYZPoint
Pos = Tuple[float, float] Pos = Tuple[float, float]
Poses = List[XYPoint] Poses = List[XYPoint]
@ -14,8 +14,8 @@ Points = List[Point]
def k_means_points( def k_means_points(
points: List[XYPoint], length: int = 500, clusters: int = 3 points: List[XYZPoint], length: int = 500, clusters: int = 3
) -> List[Tuple[XYPoint, XYPoint, Poses]]: ) -> List[Tuple[XYZPoint, XYZPoint, Poses]]:
""" """
通过 K-Means 获取集群坐标列表 通过 K-Means 获取集群坐标列表

View File

@ -59,6 +59,10 @@ class Point(BaseModel):
author_name: str author_name: str
ctime: str ctime: str
display_state: int display_state: int
area_id: int
ext_attrs: str
z_level: int
icon_sign: int
class Slice(BaseModel): class Slice(BaseModel):
@ -100,6 +104,12 @@ class XYPoint(NamedTuple):
y: float y: float
class XYZPoint(NamedTuple):
x: float
y: float
z: int
class Kind(BaseModel): class Kind(BaseModel):
id: int id: int
name: str name: str

View File

@ -8,7 +8,7 @@ from asyncio import gather, create_task
from PIL import Image from PIL import Image
from httpx import AsyncClient from httpx import AsyncClient
from .models import Maps, Point, XYPoint from .models import Maps, Point, XYPoint, XYZPoint
CLIENT = AsyncClient() CLIENT = AsyncClient()
@ -76,7 +76,7 @@ async def get_map_by_pos(
return await get_img(map.slices[_pos_to_index(x, y)]) return await get_img(map.slices[_pos_to_index(x, y)])
def get_points_by_id(id_: int, points: List[Point]) -> List[XYPoint]: def get_points_by_id(id_: int, points: List[Point]) -> List[XYZPoint]:
""" """
根据 Label ID 获取坐标点 根据 Label ID 获取坐标点
@ -91,13 +91,13 @@ def get_points_by_id(id_: int, points: List[Point]) -> List[XYPoint]:
`list[XYPoint]` `list[XYPoint]`
""" """
return [ return [
XYPoint(point.x_pos, point.y_pos) XYZPoint(point.x_pos, point.y_pos, point.z_level)
for point in points for point in points
if point.label_id == id_ if point.label_id == id_
] ]
def convert_pos(points: List[XYPoint], origin: List[int]) -> List[XYPoint]: def convert_pos(points: List[XYZPoint], origin: List[int]) -> List[XYZPoint]:
""" """
将米游社资源坐标转换为以左上角为原点的坐标系的坐标 将米游社资源坐标转换为以左上角为原点的坐标系的坐标
@ -118,7 +118,7 @@ def convert_pos(points: List[XYPoint], origin: List[int]) -> List[XYPoint]:
>>> convert_pos(points, origin) >>> convert_pos(points, origin)
[XYPoint(x=6044, y=9335), XYPoint(x=644, y=6135)] [XYPoint(x=6044, y=9335), XYPoint(x=644, y=6135)]
""" """
return [XYPoint(x + origin[0], y + origin[1]) for x, y in points] return [XYZPoint(x + origin[0], y + origin[1], z) for x, y, z in points]
def convert_pos_crop( def convert_pos_crop(

View File

@ -0,0 +1,10 @@
import aiofiles
import aiohttp
async def download_file(url, save_path):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
if response.status == 200:
async with aiofiles.open(save_path, "wb") as f:
await f.write(await response.read())

View File

@ -9,6 +9,7 @@ from PIL import Image
from .GenshinMap.genshinmap import img, models, request, utils from .GenshinMap.genshinmap import img, models, request, utils
from .logger import logger from .logger import logger
from .download import download_file
Image.MAX_IMAGE_PIXELS = 333120000 Image.MAX_IMAGE_PIXELS = 333120000
router = APIRouter(prefix="/get_map") router = APIRouter(prefix="/get_map")
@ -16,6 +17,7 @@ TEXT_PATH = Path(__file__).parent / "texture2d"
mark_quest = Image.open(TEXT_PATH / "mark_quest.png").resize((32, 32)) mark_quest = Image.open(TEXT_PATH / "mark_quest.png").resize((32, 32))
MAP = Path(__file__).parent / "map_data" MAP = Path(__file__).parent / "map_data"
RESOURCE_PATH = Path(__file__).parent / "resource_data" RESOURCE_PATH = Path(__file__).parent / "resource_data"
ICON_PATH = Path(__file__).parent / "icon_data"
CHASM_PATH = MAP / "chasm.png" CHASM_PATH = MAP / "chasm.png"
ENKANOMIYA_PATH = MAP / "enkanomiya.png" ENKANOMIYA_PATH = MAP / "enkanomiya.png"
TEYVAT_PATH = MAP / "teyvat.png" TEYVAT_PATH = MAP / "teyvat.png"
@ -30,6 +32,9 @@ MAP_ID_DICT = {
# MapID.golden_apple_archipelago, # 金苹果群岛 # MapID.golden_apple_archipelago, # 金苹果群岛
} }
if not ICON_PATH.exists():
ICON_PATH.mkdir(exist_ok=True)
@router.on_event("startup") @router.on_event("startup")
async def create_genshin_map(): async def create_genshin_map():
@ -89,15 +94,16 @@ async def get_map_response(
return save_path return save_path
maps = await request.get_maps(map_id) maps = await request.get_maps(map_id)
labels = await request.get_labels(map_id) trees = await request.get_labels(map_id)
# 请求资源ID # 请求资源ID
resource_id = 0 resource_id = 0
for label in labels: for tree in trees:
for child in label.children: for label in tree.children:
if resource_name == child.name: if resource_name == label.name:
resource_id = child.id resource_id = label.id
resource_name = child.name resource_name = label.name
icon = label.icon
break break
if resource_id == 0: if resource_id == 0:
@ -109,6 +115,7 @@ async def get_map_response(
# 转换坐标 # 转换坐标
transmittable_converted = utils.convert_pos(transmittable, maps.detail.origin) transmittable_converted = utils.convert_pos(transmittable, maps.detail.origin)
print(transmittable_converted)
# 进行最密点获取 # 进行最密点获取
if is_cluster: if is_cluster:
@ -167,9 +174,20 @@ async def get_map_response(
int(point.x) - int(lt_point.x), int(point.x) - int(lt_point.x),
int(point.y) - int(lt_point.y), int(point.y) - int(lt_point.y),
) )
genshin_map.paste(
mark_quest, (point_trans[0] - 16, point_trans[1] - 16), mark_quest icon_path = ICON_PATH / f"{resource_name}.png"
) if not icon_path.exists():
await download_file(icon, icon_path)
icon_pic = Image.open(icon_path).resize((52, 52))
if point.z <= 3:
mark = Image.open(TEXT_PATH / f"mark_{point.z}.png")
else:
mark = Image.open(TEXT_PATH / f"mark_B.png")
mark.paste(icon_pic, (25, 17), icon_pic)
genshin_map.paste(mark, (point_trans[0] - 50, point_trans[1] - 100), mark)
# 转换RGB图 # 转换RGB图
genshin_map = genshin_map.convert("RGB") genshin_map = genshin_map.convert("RGB")
@ -199,6 +217,7 @@ async def get_map_by_point(
if resource_name == a or resource_name in resource_aliases[m][a]: if resource_name == a or resource_name in resource_aliases[m][a]:
return a return a
return resource_name return resource_name
# 判断别名 # 判断别名
resource_name = resource_aliases_to_name(resource_name) resource_name = resource_aliases_to_name(resource_name)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB