Add mozc-dial nine dial edition.

Co-authored-by: Takashi Toyoshima <toyoshim@google.com>
Co-authored-by: Shun Ikejima <ikejima@google.com>
This commit is contained in:
Shun Ikejima
2025-10-28 18:19:10 +09:00
parent 1775d344f1
commit 994d22bb71
76 changed files with 810960 additions and 7327 deletions

View File

@@ -68,6 +68,12 @@ class SVGGenerator:
f'<polygon points="{p1[0]},{p1[1]} {p2[0]},{p2[1]} {p3[0]},{p3[1]}" fill="black" />'
)
def label(self, text):
"""左上にラベルを書く"""
self.elements.append(
f'<text x="40" y="8" font-size="8" fill="black">{text}</text>'
)
def export_to_svg(self):
"""描いたデータをsvgにして出力する。"""
svg_elements = "\n".join(self.elements)
@@ -79,34 +85,222 @@ class SVGGenerator:
encoders = [
{
"page": "one_dial",
"x": 10,
"y": 10,
"name": "one_dial",
"bits": 6,
# ダイヤルでは最初の穴の中心が0度の位置、そこから23/3度おきに35個の穴がある。
# コードでは最初の穴位置が20度から(20+23/2)度になってる。
"degrees": [
0, # 最初の遊び
]+[
(i * 23 / 3 + 20) for i in range(33+2)
] + [320],
"indicator": 23/3*.5+20 + 23/3+5,
}
# 最初の穴の中央位置 = 23/3*.5+20
# センサとエンドの位置のズレ = 23/3+5
"indicator": 23/3*0.5+20 + 23/3+5,
},
{
"page": "nine_dial",
"x": 0,
"y": 10,
"name": "dial_a",
"bits": 6,
# あそびあり35穴
"degrees": [
0, # 最初の遊び
]+[
(i * 23 / 3 + 20) for i in range(33+2)
] + [320],
"indicator": 23/3*0.5+20 + 23/3+5 + 85,
},
{
"page": "nine_dial",
"x": 70,
"y": 10,
"name": "dial_b",
"bits": 2,
# あそびなし3穴
"degrees": [
270/3*0, # 穴1
270/3*1, # 穴2
270/3*2, # 穴3
270/3*3, # 最後
],
"indicator": 75,
},
{
"page": "nine_dial",
"x": 120,
"y": 10,
"name": "dial_c",
"bits": 3,
# あそびなし4穴
"degrees": [
270/4*0, # 穴1
270/4*1, # 穴2
270/4*2, # 穴3
270/4*3, # 穴4
270/4*4, # 最後
],
"indicator": 75-90,
},
{
"page": "nine_dial",
"x": 0,
"y": 110,
"name": "dial_d",
"bits": 3,
# あそびあり1穴
"degrees": [
0, # あそび
20, # 1オンになる所
300, # 最後
],
"indicator": 20+75+90-90,
},
{
"page": "nine_dial",
"x": 60,
"y": 110,
"name": "dial_e",
"bits": 3,
# あそびあり6穴
"degrees": [
0, # あそび
20 + 270/6*0, # 穴1
20 + 270/6*1, # 穴2
20 + 270/6*2, # 穴3
20 + 270/6*3, # 穴4
20 + 270/6*4, # 穴5
20 + 270/6*5, # 穴6
20 + 270/6*6, # 最後
],
"indicator": 20+75+45,
},
{
"page": "nine_dial",
"x": 120,
"y": 110,
"name": "dial_f",
"bits": 3,
# あそびあり4穴
# 十字キーなので値がすごい変則
"degrees": [
0, # あそび
10+360/4*0, # 穴1
10+360/4*1, # 穴2
10+360/4*2, # 穴3
10+360/4*3, # 穴4
10+360/4*4-45, # 最後
],
"indicator": 75+90-15,
},
{
"page": "nine_dial",
"x": 0,
"y": 210,
"name": "dial_g",
"bits": 2,
# あそびなし3穴
"degrees": [ # degrees dial_bと同じ
270/3*0, # 穴1
270/3*1, # 穴2
270/3*2, # 穴3
270/3*3, # 最後
],
"indicator": 75+80,
},
{
"page": "nine_dial",
"x": 50,
"y": 210,
"name": "dial_h",
"bits": 2,
# あそびなし3穴
"degrees": [ # degrees dial_bと同じ
270/3*0, # 穴1
270/3*1, # 穴2
270/3*2, # 穴3
270/3*3, # 最後
],
"indicator": 75+90,
},
{
"page": "nine_dial",
"x": 110,
"y": 210,
"name": "dial_i",
"bits": 4,
# あそびあり10穴
"degrees": [
0, # あそび
20 + 270/10*0, # 穴1
20 + 270/10*1, # 穴2
20 + 270/10*2, # 穴3
20 + 270/10*3, # 穴4
20 + 270/10*4, # 穴5
20 + 270/10*5, # 穴6
20 + 270/10*6, # 穴7
20 + 270/10*7, # 穴8
20 + 270/10*8, # 穴9
20 + 270/10*9, # 穴10
20 + 270/10*10, # 最後
],
"indicator": 20+75+315-30,
},
]
from collections import defaultdict
# Group encoders by page
pages = defaultdict(list)
for encoder in encoders:
gen = SVGGenerator()
bits = encoder["bits"]
templ = encoder["degrees"]
gen.circle(8)
gen.circle(8+5*bits)
gen.indicator(8+5*bits, encoder["indicator"])
pages[encoder["page"]].append(encoder)
for i in range(len(templ)-1):
num = i+1
gray = num ^ (num>>1)
s = f'{gray:0{bits}b}'
# print(s)
for j in range(bits):
if (s[bits-j-1] == "1"):
gen.sector_ring(8+5+5*j, 8+5*j, templ[i], templ[i+1])
# A4 size in mm
A4_WIDTH_MM = 210
A4_HEIGHT_MM = 297
with open(f"{encoder["name"]}.svg", "w") as f:
f.write(gen.export_to_svg())
# Process each page
for page_name, page_encoders in pages.items():
page_svg_elements = []
for encoder in page_encoders:
# SVGGeneratorは内部でwidth/height=100を想定して中心座標を計算している
gen = SVGGenerator(width_mm=100, height_mm=100)
bits = encoder["bits"]
templ = encoder["degrees"]
gen.circle(8)
gen.circle(8 + 5 * bits)
gen.indicator(8 + 5 * bits, encoder["indicator"])
for i in range(len(templ)-1):
gen.label(encoder["name"])
num = i+1
gray = num ^ (num>>1)
s = f'{gray:0{bits}b}'
# print(s)
for j in range(bits):
if (s[bits-j-1] == "1"):
gen.sector_ring(8+5+5*j, 8+5*j, templ[i], templ[i+1])
# Get the SVG elements from the public member
encoder_elements = "\n".join(gen.elements)
transform_x = encoder["x"]
transform_y = encoder["y"]
page_svg_elements.append(
f'<g transform="translate({transform_x}, {transform_y})">\n{encoder_elements}\n</g>'
)
# Combine all elements for the page into a single A4 SVG
final_svg_content = (
f'<svg width="{A4_WIDTH_MM}mm" height="{A4_HEIGHT_MM}mm" viewBox="0 0 {A4_WIDTH_MM} {A4_HEIGHT_MM}" xmlns="http://www.w3.org/2000/svg">\n'
+ "\n".join(page_svg_elements)
+ "\n</svg>"
)
# Write to the page file
with open(f"{page_name}.svg", "w") as f:
f.write(final_svg_content)