forked from OPSnet/Gazelle
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
script to generate trump precedence chart
- Loading branch information
Spine
committed
Apr 7, 2024
1 parent
9c139f2
commit 9ff5b7a
Showing
2 changed files
with
329 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
#! /usr/bin/python3 | ||
# | ||
# This generates the trump precedence chart | ||
# It is a bit of an awful hack but it gets the job done. | ||
# The arrows are particularly fragile: change some of the | ||
# chart settings and they will likely break. | ||
|
||
class Chart: | ||
def __init__( | ||
self, | ||
chart_width: int, | ||
chart_height: int, | ||
box_width: int, | ||
box_height: int, | ||
gutter: int, | ||
x: int, | ||
y: int, | ||
y_offset: int, | ||
radius: int | ||
): | ||
self.chart_width = chart_width | ||
self.chart_height = chart_height | ||
self.box_width = box_width | ||
self.box_height = box_height | ||
self.gutter = gutter | ||
self.x = x | ||
self.y = y | ||
self.y_offset = y_offset | ||
self.radius = radius | ||
self.column_count = 0 | ||
self.dist = 10 # spline distance for arcs | ||
self.gradient = [ | ||
"#3dda07", | ||
"#46c819", | ||
"#43b72a", | ||
"#56a63b", | ||
"#5f944d", | ||
] | ||
self.head_css = "font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bolder\" dominant-baseline=\"middle\" text-anchor=\"middle\"" | ||
self.text_css = "font-family=\"sans-serif\" font-size=\"12\" font-weight=\"bold\" dominant-baseline=\"middle\" text-anchor=\"middle\"" | ||
self.path_color = "#dffcd7" | ||
self.box_color = "#ebf9e7" | ||
|
||
def head_box(self, x: int, y: int, height: int, text: str, bg_color: str) -> str: | ||
para = text.split('/') | ||
box = f"<rect x=\"{x}\" y=\"{y}\" width=\"{self.box_width}\" height=\"{height}\" rx=\"3\" ry=\"3\" fill=\"{bg_color}\" stroke=\"{self.box_color}\" stroke-width=\"2\" />\n" | ||
x_mid = x + int(self.box_width / 2) | ||
y_begin = y + int(height / (len(para) + 1)) + 3 | ||
for line in para: | ||
box += f"<text x=\"{x_mid}\" y=\"{y_begin}\" {self.head_css}>{line}</text>\n" | ||
y_begin += 18 | ||
return box + "\n" | ||
|
||
def box(self, x: int, y: int, height: int, text: str, bg_color: str) -> str: | ||
para = text.split('/') | ||
box = f"<rect x=\"{x}\" y=\"{y}\" width=\"{self.box_width}\" height=\"{height}\" rx=\"3\" ry=\"3\" fill=\"{bg_color}\" stroke=\"{self.box_color}\" stroke-width=\"1\" />\n" | ||
x_mid = x + int(self.box_width / 2) | ||
y_begin = y + int(height / (len(para) + 1)) + 2 | ||
for line in para: | ||
box += f"<text x=\"{x_mid}\" y=\"{y_begin}\" {self.text_css}>{line}</text>\n" | ||
y_begin += 16 | ||
return box | ||
|
||
def line(self, x1: int, y1: int, x2: int, y2: int) -> str: | ||
return f"<line x1=\"{x1}\" y1=\"{y1}\" x2=\"{x2}\" y2=\"{y2}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n" | ||
|
||
def arc_ne(self, x: int, y: int) -> str: | ||
return f"<path d=\"M {x} {y} C {x} {y-self.dist}, {x+self.dist} {y-self.radius}, {x+self.radius} {y-self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n" | ||
|
||
def arc_nw(self, x: int, y: int) -> str: | ||
return f"<path d=\"M {x} {y} C {x} {y-self.dist}, {x-self.dist} {y-self.radius}, {x-self.radius} {y-self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n" | ||
|
||
def arc_se(self, x: int, y: int) -> str: | ||
return f"<path d=\"M {x} {y} C {x} {y+self.dist}, {x+self.dist} {y+self.radius}, {x+self.radius} {y+self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n" | ||
|
||
def arc_sw(self, x: int, y: int) -> str: | ||
return f"<path d=\"M {x} {y} C {x} {y+self.dist}, {x-self.dist} {y+self.radius}, {x-self.radius} {y+self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n" | ||
|
||
def side_arrow_head(self, x: int, y: int, direction: int) -> str: | ||
return f"<polygon points=\"{x},{y} {x - 6 * direction},{y - 3} {x - 6 * direction},{y + 3}\" fill=\"{self.path_color}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n" | ||
|
||
def up_arrow_head(self, x: int, y: int) -> str: | ||
return f"<polygon points=\"{x},{y - 8} {x - 4},{y} {x + 4},{y}\" fill=\"{self.path_color}\" stroke=\"{self.path_color}\" />\n" | ||
|
||
def up_arrow(self, x: int, y: int) -> str: | ||
x_mid = x + int(self.box_width/2) | ||
return f"<line x1=\"{x_mid}\" y1=\"{y}\" x2=\"{x_mid}\" y2=\"{y - 10}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n" + self.up_arrow_head(x_mid, y - 10) + "\n" | ||
|
||
def column(self, name: str, dependent: list[str]): | ||
x = self.x + self.column_count * (self.box_width + self.gutter) | ||
self.column_count += 1 | ||
y = self.box_height | ||
out = self.head_box(x, y - 20, self.box_height + 20, name, "#abe797") | ||
|
||
n = 0 | ||
for item in dependent: | ||
y += self.y_offset | ||
out += self.box(x, y, self.box_height, item, self.gradient[n]) + self.up_arrow(x, y) | ||
n += 1 | ||
|
||
return out | ||
|
||
def dependent_column(self, right: bool, dependent: dict) -> str: | ||
x = self.x + self.column_count * (self.box_width + self.gutter) | ||
y = self.box_height | ||
|
||
# curving arrow to each adjacent columns | ||
out = "" | ||
for direction in [-1, 1]: | ||
if direction == 1 and not right: | ||
continue | ||
x_mid = int(self.box_width / 2) | ||
x_begin = x + x_mid | ||
x_end = x_begin + (x_mid + self.gutter - 3) * direction | ||
y_begin = y + self.y_offset | ||
y_end = y_begin - self.box_height - 10 | ||
out += f"\n<path d=\"M {x_begin} {y_begin} C {x_begin} {y_begin-self.box_height+5}, {x_end-40 * direction} {y_end}, {x_end} {y_end}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n" | ||
out += self.side_arrow_head(x_end, y_end, direction) + "\n" | ||
|
||
n = 0 | ||
for item in dependent: | ||
y += self.y_offset | ||
out += self.box(x, y, self.box_height, item, self.gradient[n]) | ||
if n: | ||
out += self.up_arrow(x, y) | ||
n += 1 | ||
|
||
self.column_count += 1 | ||
return out | ||
|
||
def horizontal(self, top: int, color: str, dependent: list[str]) -> str: | ||
x = self.gutter | ||
y = top | ||
x_offset = self.box_width + self.gutter | ||
out = "" | ||
n = 0 | ||
for item in dependent: | ||
y_mid = y + int(self.box_height / 2) | ||
out += self.box(x, y, self.box_height, item, color) | ||
if n: | ||
out +=f"<line x1=\"{x - self.gutter}\" y1=\"{y_mid}\" x2=\"{x - 2}\" y2=\"{y_mid}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n" + self.side_arrow_head(x - 2, y_mid, 1) | ||
n += 1 | ||
x += x_offset | ||
return out | ||
|
||
def svg(self) -> str: | ||
out = (f""" | ||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="{self.chart_height}" width="{self.chart_width}"> | ||
<rect width="{self.chart_width}" height="{self.chart_height}" rx="8" ry="8" fill="#112709" stroke="#000" stroke-width="2" /> | ||
""").strip() | ||
|
||
out += self.column("MP3 V0", [ | ||
"V2", | ||
"any VBR", | ||
]) | ||
|
||
self.column_count += 1 | ||
cbr = [ | ||
"256 CBR", | ||
"224 CBR", | ||
"192 CBR", | ||
"< 192 CBR", | ||
] | ||
|
||
out += self.column("MP3 320", cbr) | ||
|
||
# draw the arrows from the CBR boxes to V0 | ||
x = self.x + 2 * (self.box_width + self.gutter) | ||
x_end = x - 59 | ||
y = 3 * (self.box_height) | ||
for n in range(0, len(cbr)): | ||
out += self.line(x, y, x_end, y) | ||
out += self.arc_se(x_end - self.radius, y - self.radius) | ||
y += self.y_offset | ||
|
||
y_top = self.chart_height - self.box_height - 20 | ||
out += self.horizontal(y_top, self.gradient[4], [ | ||
"192 AAC", | ||
"256 AAC", | ||
"320 AAC", | ||
]) | ||
|
||
# line from first horizontal box | ||
x = self.gutter + int(self.box_width / 2) | ||
out += self.arc_ne(x, y_top) | ||
out += self.arc_sw(x + self.box_width + self.gutter, y_top - self.radius * 2) | ||
x += self.radius - 1 | ||
x_end = x + int((self.box_width + self.gutter) / 2) + 20 | ||
y = y_top - self.radius | ||
out += self.line(x, y, x_end, y) | ||
|
||
# line from middle horizontal box | ||
x_end += self.radius | ||
y_end = self.chart_height - self.box_height - 80 | ||
out += self.line(x_end, y_end + self.radius * 2, x_end, y_end) | ||
|
||
# line from third horizontal box | ||
out += self.arc_se(x_end, y_end) | ||
x = int(self.gutter) / 2 + self.box_width * 2 - 10 | ||
x_end = x + self.box_width - self.gutter + 10 | ||
out += self.arc_nw(x_end, y_top) | ||
|
||
y = y_top - self.radius | ||
out += self.line(x, y, x_end - self.radius, y) | ||
|
||
# line to top | ||
x = self.x + int(self.gutter + 3/2 * self.box_width) | ||
y_begin = self.y + int(self.box_height * 2 - 20) | ||
out += self.line(x, y_begin, x, y_end) | ||
out += self.arc_nw(x, y_begin) | ||
y = y_begin - self.radius | ||
x_end = x - int(self.box_width / 2) - self.gutter + 2 | ||
out += self.line(x - self.radius, y, x_end, y) | ||
out += self.side_arrow_head(x_end, y, -1) | ||
|
||
out += self.column("FLAC 100% Log/+ Cue + Checksum", [ | ||
"FLAC 100% Log + Cue/No Checksum", | ||
"FLAC 100% Log/No Checksum", | ||
]) | ||
|
||
out += self.dependent_column(False, [ | ||
"FLAC < 100% Log/or No log", | ||
]) | ||
|
||
return out + "</svg>" | ||
|
||
c = Chart( | ||
810, | ||
450, | ||
138, # box width | ||
40, # box height | ||
20, # gutter | ||
20, # x | ||
20, # y | ||
60, # y_offset, how far below the next box is placed | ||
30, # radius of arcs | ||
) | ||
|
||
print(c.svg()) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.