forked from bot/app
420 lines
12 KiB
Python
420 lines
12 KiB
Python
|
import json
|
|||
|
from typing import List, Any
|
|||
|
|
|||
|
from PIL import Image
|
|||
|
from arclet.alconna import Alconna
|
|||
|
from nb_cli import run_sync
|
|||
|
from nonebot import on_command
|
|||
|
from nonebot_plugin_alconna import on_alconna, Alconna, Subcommand, Args, MultiVar, Arparma, UniMessage
|
|||
|
from pydantic import BaseModel
|
|||
|
|
|||
|
from .canvas import *
|
|||
|
from ...utils.base.resource import get_path
|
|||
|
|
|||
|
resolution = 256
|
|||
|
|
|||
|
|
|||
|
class Entrance(BaseModel):
|
|||
|
identifier: str
|
|||
|
size: tuple[int, int]
|
|||
|
dest: List[str]
|
|||
|
|
|||
|
|
|||
|
class Station(BaseModel):
|
|||
|
identifier: str
|
|||
|
chineseName: str
|
|||
|
englishName: str
|
|||
|
position: tuple[int, int]
|
|||
|
|
|||
|
|
|||
|
class Line(BaseModel):
|
|||
|
identifier: str
|
|||
|
chineseName: str
|
|||
|
englishName: str
|
|||
|
color: Any
|
|||
|
stations: List["Station"]
|
|||
|
|
|||
|
|
|||
|
font_light = get_path("templates/fonts/MiSans/MiSans-Light.woff2")
|
|||
|
font_bold = get_path("templates/fonts/MiSans/MiSans-Bold.woff2")
|
|||
|
|
|||
|
@run_sync
|
|||
|
def generate_entrance_sign(name: str, aliases: List[str], lineInfo: List[Line], entranceIdentifier: str, ratio: tuple[int | float, int | float],
|
|||
|
reso: int = resolution):
|
|||
|
"""
|
|||
|
Generates an entrance sign for the ride.
|
|||
|
"""
|
|||
|
width, height = ratio[0] * reso, ratio[1] * reso
|
|||
|
baseCanvas = Canvas(Image.new("RGBA", (width, height), Color.WHITE))
|
|||
|
# 加黑色图框
|
|||
|
baseCanvas.outline = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0, 0),
|
|||
|
point=(0, 0),
|
|||
|
img=Shape.rectangle(
|
|||
|
size=(width, height),
|
|||
|
fillet=0,
|
|||
|
fill=(0, 0, 0, 0),
|
|||
|
width=15,
|
|||
|
outline=Color.BLACK
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
baseCanvas.contentPanel = Panel(
|
|||
|
uv_size=(width, height),
|
|||
|
box_size=(width - 28, height - 28),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
)
|
|||
|
|
|||
|
linePanelHeight = 0.7 * ratio[1]
|
|||
|
linePanelWidth = linePanelHeight * 1.3
|
|||
|
|
|||
|
# 画线路面板部分
|
|||
|
|
|||
|
for i, line in enumerate(lineInfo):
|
|||
|
linePanel = baseCanvas.contentPanel.__dict__[f"Line_{i}_Panel"] = Panel(
|
|||
|
uv_size=ratio,
|
|||
|
box_size=(linePanelWidth, linePanelHeight),
|
|||
|
parent_point=(i * linePanelWidth / ratio[0], 1),
|
|||
|
point=(0, 1),
|
|||
|
)
|
|||
|
|
|||
|
linePanel.colorCube = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(0.15, 1),
|
|||
|
parent_point=(0.125, 1),
|
|||
|
point=(0, 1),
|
|||
|
img=Shape.rectangle(
|
|||
|
size=(100, 100),
|
|||
|
fillet=0,
|
|||
|
fill=line.color,
|
|||
|
),
|
|||
|
keep_ratio=False
|
|||
|
)
|
|||
|
|
|||
|
textPanel = linePanel.TextPanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(0.625, 1),
|
|||
|
parent_point=(1, 1),
|
|||
|
point=(1, 1)
|
|||
|
)
|
|||
|
|
|||
|
# 中文线路名
|
|||
|
textPanel.namePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 2 / 3),
|
|||
|
parent_point=(0, 0),
|
|||
|
point=(0, 0),
|
|||
|
)
|
|||
|
nameSize = baseCanvas.get_actual_pixel_size("contentPanel.Line_{}_Panel.TextPanel.namePanel".format(i))
|
|||
|
textPanel.namePanel.text = Text(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
text=line.chineseName,
|
|||
|
color=Color.BLACK,
|
|||
|
font_size=int(nameSize[1] * 0.5),
|
|||
|
force_size=True,
|
|||
|
font=font_bold
|
|||
|
|
|||
|
)
|
|||
|
|
|||
|
# 英文线路名
|
|||
|
textPanel.englishNamePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1 / 3),
|
|||
|
parent_point=(0, 1),
|
|||
|
point=(0, 1),
|
|||
|
)
|
|||
|
englishNameSize = baseCanvas.get_actual_pixel_size("contentPanel.Line_{}_Panel.TextPanel.englishNamePanel".format(i))
|
|||
|
textPanel.englishNamePanel.text = Text(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
text=line.englishName,
|
|||
|
color=Color.BLACK,
|
|||
|
font_size=int(englishNameSize[1] * 0.6),
|
|||
|
force_size=True,
|
|||
|
font=font_light
|
|||
|
)
|
|||
|
|
|||
|
# 画名称部分
|
|||
|
namePanel = baseCanvas.contentPanel.namePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 0.4),
|
|||
|
parent_point=(0.5, 0),
|
|||
|
point=(0.5, 0),
|
|||
|
)
|
|||
|
|
|||
|
namePanel.text = Text(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
text=name,
|
|||
|
color=Color.BLACK,
|
|||
|
font_size=int(height * 0.3),
|
|||
|
force_size=True,
|
|||
|
font=font_bold
|
|||
|
)
|
|||
|
|
|||
|
aliasesPanel = baseCanvas.contentPanel.aliasesPanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 0.5),
|
|||
|
parent_point=(0.5, 1),
|
|||
|
point=(0.5, 1),
|
|||
|
|
|||
|
)
|
|||
|
for j, alias in enumerate(aliases):
|
|||
|
aliasesPanel.__dict__[alias] = Text(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(0.35, 0.5),
|
|||
|
parent_point=(0.5, 0.5 * j),
|
|||
|
point=(0.5, 0),
|
|||
|
text=alias,
|
|||
|
color=Color.BLACK,
|
|||
|
font_size=int(height * 0.15),
|
|||
|
font=font_light
|
|||
|
)
|
|||
|
|
|||
|
# 画入口标识
|
|||
|
entrancePanel = baseCanvas.contentPanel.entrancePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(0.2, 1),
|
|||
|
parent_point=(1, 0.5),
|
|||
|
point=(1, 0.5),
|
|||
|
)
|
|||
|
# 中文文本
|
|||
|
entrancePanel.namePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 0.5),
|
|||
|
parent_point=(1, 0),
|
|||
|
point=(1, 0),
|
|||
|
)
|
|||
|
entrancePanel.namePanel.text = Text(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0, 0.5),
|
|||
|
point=(0, 0.5),
|
|||
|
text=f"{entranceIdentifier}出入口",
|
|||
|
color=Color.BLACK,
|
|||
|
font_size=int(height * 0.2),
|
|||
|
force_size=True,
|
|||
|
font=font_bold
|
|||
|
)
|
|||
|
# 英文文本
|
|||
|
entrancePanel.englishNamePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 0.5),
|
|||
|
parent_point=(1, 1),
|
|||
|
point=(1, 1),
|
|||
|
)
|
|||
|
entrancePanel.englishNamePanel.text = Text(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0, 0.5),
|
|||
|
point=(0, 0.5),
|
|||
|
text=f"Entrance {entranceIdentifier}",
|
|||
|
color=Color.BLACK,
|
|||
|
font_size=int(height * 0.15),
|
|||
|
force_size=True,
|
|||
|
font=font_light
|
|||
|
)
|
|||
|
|
|||
|
return baseCanvas.base_img.tobytes()
|
|||
|
|
|||
|
|
|||
|
crt_alc = on_alconna(
|
|||
|
Alconna(
|
|||
|
"crt",
|
|||
|
Subcommand(
|
|||
|
"entrance",
|
|||
|
Args["name", str]["lines", str, ""]["entrance", int, 1], # /crt entrance 璧山&Bishan 1号线&Line1&#ff0000,27号线&Line1&#ff0000 1A
|
|||
|
)
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
@crt_alc.assign("entrance")
|
|||
|
async def _(result: Arparma):
|
|||
|
args = result.subcommands.get("entrance").args
|
|||
|
name = args["name"]
|
|||
|
lines = args["lines"]
|
|||
|
entrance = args["entrance"]
|
|||
|
line_info = []
|
|||
|
for line in lines.split(","):
|
|||
|
line_args = line.split("&")
|
|||
|
line_info.append(Line(
|
|||
|
identifier=1,
|
|||
|
chineseName=line_args[0],
|
|||
|
englishName=line_args[1],
|
|||
|
color=line_args[2],
|
|||
|
stations=[]
|
|||
|
))
|
|||
|
img_bytes = await generate_entrance_sign(
|
|||
|
name=name,
|
|||
|
aliases=name.split("&"),
|
|||
|
lineInfo=line_info,
|
|||
|
entranceIdentifier=entrance,
|
|||
|
ratio=(8, 1),
|
|||
|
reso=256,
|
|||
|
)
|
|||
|
await crt_alc.finish(
|
|||
|
UniMessage.image(raw=img_bytes)
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
def generate_platform_line_pic(line: Line, station: Station, ratio=None, reso: int = resolution):
|
|||
|
"""
|
|||
|
生成站台线路图
|
|||
|
:param line: 线路对象
|
|||
|
:param station: 本站点对象
|
|||
|
:param ratio: 比例
|
|||
|
:param reso: 分辨率,1:reso
|
|||
|
:return: 两个方向的站牌
|
|||
|
"""
|
|||
|
if ratio is None:
|
|||
|
ratio = [4, 1]
|
|||
|
width, height = ratio[0] * reso, ratio[1] * reso
|
|||
|
baseCanvas = Canvas(Image.new("RGBA", (width, height), Color.YELLOW))
|
|||
|
# 加黑色图框
|
|||
|
baseCanvas.linePanel = Panel(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(0.8, 0.15),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
)
|
|||
|
|
|||
|
# 直线块
|
|||
|
baseCanvas.linePanel.recLine = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=Shape.rectangle(
|
|||
|
size=(10, 10),
|
|||
|
fill=line.color,
|
|||
|
),
|
|||
|
keep_ratio=False
|
|||
|
)
|
|||
|
# 灰色直线块
|
|||
|
baseCanvas.linePanel.recLineGrey = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=Shape.rectangle(
|
|||
|
size=(10, 10),
|
|||
|
fill=Color.GREY,
|
|||
|
),
|
|||
|
keep_ratio=False
|
|||
|
)
|
|||
|
# 生成各站圆点
|
|||
|
outline_width = 40
|
|||
|
circleForward = Shape.circular(
|
|||
|
radius=200,
|
|||
|
fill=Color.WHITE,
|
|||
|
width=outline_width,
|
|||
|
outline=line.color,
|
|||
|
)
|
|||
|
|
|||
|
circleThisPanel = Canvas(Image.new("RGBA", (200, 200), (0, 0, 0, 0)))
|
|||
|
circleThisPanel.circleOuter = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1, 1),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=Shape.circular(
|
|||
|
radius=200,
|
|||
|
fill=Color.WHITE,
|
|||
|
width=outline_width,
|
|||
|
outline=line.color,
|
|||
|
),
|
|||
|
)
|
|||
|
circleThisPanel.circleOuter.circleInner = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(0.7, 0.7),
|
|||
|
parent_point=(0.5, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=Shape.circular(
|
|||
|
radius=200,
|
|||
|
fill=line.color,
|
|||
|
width=0,
|
|||
|
outline=line.color,
|
|||
|
),
|
|||
|
)
|
|||
|
|
|||
|
circleThisPanel.export("a.png", alpha=True)
|
|||
|
circleThis = circleThisPanel.base_img
|
|||
|
|
|||
|
circlePassed = Shape.circular(
|
|||
|
radius=200,
|
|||
|
fill=Color.WHITE,
|
|||
|
width=outline_width,
|
|||
|
outline=Color.GREY,
|
|||
|
)
|
|||
|
|
|||
|
arrival = False
|
|||
|
distance = 1 / (len(line.stations) - 1)
|
|||
|
for i, sta in enumerate(line.stations):
|
|||
|
box_size = (1.618, 1.618)
|
|||
|
if sta.identifier == station.identifier:
|
|||
|
arrival = True
|
|||
|
baseCanvas.linePanel.recLine.__dict__["station_{}".format(sta.identifier)] = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=(1.8, 1.8),
|
|||
|
parent_point=(distance * i, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=circleThis,
|
|||
|
keep_ratio=True
|
|||
|
)
|
|||
|
continue
|
|||
|
if arrival:
|
|||
|
# 后方站绘制
|
|||
|
baseCanvas.linePanel.recLine.__dict__["station_{}".format(sta.identifier)] = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=box_size,
|
|||
|
parent_point=(distance * i, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=circleForward,
|
|||
|
keep_ratio=True
|
|||
|
)
|
|||
|
else:
|
|||
|
# 前方站绘制
|
|||
|
baseCanvas.linePanel.recLine.__dict__["station_{}".format(sta.identifier)] = Img(
|
|||
|
uv_size=(1, 1),
|
|||
|
box_size=box_size,
|
|||
|
parent_point=(distance * i, 0.5),
|
|||
|
point=(0.5, 0.5),
|
|||
|
img=circlePassed,
|
|||
|
keep_ratio=True
|
|||
|
)
|
|||
|
return baseCanvas
|
|||
|
|
|||
|
|
|||
|
def generate_platform_sign(name: str, aliases: List[str], lineInfo: List[Line], entranceIdentifier: str, ratio: tuple[int | float, int | float],
|
|||
|
reso: int = resolution
|
|||
|
):
|
|||
|
pass
|
|||
|
|
|||
|
# def main():
|
|||
|
# generate_entrance_sign(
|
|||
|
# "璧山",
|
|||
|
# aliases=["Bishan"],
|
|||
|
# lineInfo=[
|
|||
|
#
|
|||
|
# Line(identifier="2", chineseName="1号线", englishName="Line 1", color=Color.RED, stations=[]),
|
|||
|
# Line(identifier="3", chineseName="27号线", englishName="Line 27", color="#685bc7", stations=[]),
|
|||
|
# Line(identifier="1", chineseName="璧铜线", englishName="BT Line", color="#685BC7", stations=[]),
|
|||
|
# ],
|
|||
|
# entranceIdentifier="1",
|
|||
|
# ratio=(8, 1)
|
|||
|
# )
|
|||
|
#
|
|||
|
#
|
|||
|
# main()
|