Refactor generator `traylayout`

* Use generic argument `sx` and `sy` to generate text traylayout
* Add typing
* Fix code style
This commit is contained in:
Rotzbua 2023-02-27 21:58:53 +01:00 committed by Florian Festi
parent 0e4e373367
commit fa2b2fe466
2 changed files with 69 additions and 80 deletions

View File

@ -13,81 +13,86 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import boxes import boxes
from boxes import * from boxes import *
class TrayLayout(Boxes): class TrayLayout(Boxes):
"""Generate a typetray from a layout file""" """Generate a layout file for a typetray."""
# This class generates the skeleton text file that can then be edited # This class generates the skeleton text file that can then be edited
# to describe the actual box # to describe the actual box
description = """This is a two step process. The layout is based on a grid description = """This is a two step process. This is step 1.
of sizes in x and y direction. Choose how many distances you need in both directions. The actual sizes and all other settings can be entered in the second step.""" The layout is based on a grid of sizes in x and y direction.
Choose how many distances you need in both directions.
The actual sizes and all other settings can be entered in the second step."""
webinterface = True webinterface = True
ui_group = "Tray" ui_group = "Tray"
sx: list[float] = [] # arg input
sy: list[float] = [] # arg input
hwalls: list[list[bool]] = []
vwalls: list[list[bool]] = []
floors: list[list[bool]] = []
def __init__(self, input=None, webargs=False) -> None: def __init__(self, input=None, webargs=False) -> None:
Boxes.__init__(self) Boxes.__init__(self)
self.argparser = argparse.ArgumentParser() self.argparser = argparse.ArgumentParser()
self.argparser.add_argument( self.buildArgParser("sx", "sy")
"--x", action="store", type=int, default=2,
help="number of compartments side by side")
self.argparser.add_argument(
"--y", action="store", type=int, default=2,
help="number of compartments back to front")
self.argparser.add_argument( self.argparser.add_argument(
"--output", action="store", type=str, default="traylayout.txt", "--output", action="store", type=str, default="traylayout.txt",
help="name of the layout text file") help="Name of the layout text file.")
# Use empty open and close methods to avoid initializing the whole def open(self) -> None:
# drawing infrastructure # Use empty open and close methods to avoid initializing the whole drawing infrastructure.
def open(self):
pass pass
def close(self): def close(self) -> None:
# Use empty open and close methods to avoid initializing the whole drawing infrastructure.
pass pass
def fillDefault(self, x, y): def fillDefault(self, sx: list[float], sy: list[float]) -> None:
self.x = [0.0] * x self.sx = sx
self.y = [0.0] * y self.sy = sy
self.hwalls = [[True for i in range(x)] for j in range(y + 1)] x = len(sx)
self.vwalls = [[True for i in range(x + 1)] for j in range(y)] y = len(sy)
self.floors = [[True for i in range(x)] for j in range(y)] self.hwalls = [[True for _ in range(x)] for _ in range(y + 1)]
self.vwalls = [[True for _ in range(x + 1)] for _ in range(y)]
self.floors = [[True for _ in range(x)] for _ in range(y)]
def __str__(self) -> str: def __str__(self) -> str:
r = [] r = []
for i, x in enumerate(self.x): for i, x in enumerate(self.sx):
r.append(" |" * (i) + " ,> %.1fmm\n" % x) r.append(" |" * i + " ,> %.1fmm\n" % x)
for hwalls, vwalls, floors, y in zip( for hwalls, vwalls, floors, y in zip(self.hwalls, self.vwalls, self.floors, self.sy):
self.hwalls, self.vwalls, self.floors, self.y):
r.append("".join("+" + " -"[h] for h in hwalls) + "+\n") r.append("".join("+" + " -"[h] for h in hwalls) + "+\n")
r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors))) r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors))) + " |"[vwalls[-1]] + " %.1fmm\n" % y)
+ " |"[vwalls[-1]] + " %.1fmm\n" % y)
r.append("".join("+" + " -"[h] for h in self.hwalls[-1]) + "+\n") r.append("".join("+" + " -"[h] for h in self.hwalls[-1]) + "+\n")
return "".join(r) return "".join(r)
def render(self): def render(self) -> None:
self.fillDefault(self.x, self.y) self.fillDefault(self.sx, self.sy)
with open(self.output, 'w') as f: with open(self.output, 'w') as f:
f.write(str(self)) f.write(str(self))
class TrayLayout2(TrayLayout):
"""Generate a typetray from a layout file""" class TrayLayout2(Boxes):
"""Generate a typetray from a layout file."""
# This class reads in the layout either from a file (with --input) or # This class reads in the layout either from a file (with --input) or
# as string (with --layout) and turns it into a drawing for a box. # as string (with --layout) and turns it into a drawing for a box.
webinterface = True webinterface = True
description = """Edit the layout text graphics to adjust your tray. description = """This is a two step process. This is step 2.
Edit the layout text graphics to adjust your tray.
Put in the sizes for each column and row. You can replace the hyphens and Put in the sizes for each column and row. You can replace the hyphens and
vertical bars representing the walls with a space character to remove the walls. vertical bars representing the walls with a space character to remove the walls.
You can replace the space characters representing the floor by a "X" to remove the floor for this compartment. You can replace the space characters representing the floor by a "X" to remove the floor for this compartment.
@ -100,30 +105,24 @@ You can replace the space characters representing the floor by a "X" to remove t
if not webargs: if not webargs:
self.argparser.add_argument( self.argparser.add_argument(
"--input", action="store", type=argparse.FileType('r'), "--input", action="store", type=argparse.FileType('r'),
default='traylayout.txt', default="traylayout.txt",
help="layout file") help="layout file")
self.layout = None self.layout = None
else: else:
self.argparser.add_argument( self.argparser.add_argument(
"--layout", action="store", type=str, default="") "--layout", action="store", type=str, default="")
# Use normal open and close def vWalls(self, x: int, y: int) -> int:
open = Boxes.open """Number of vertical walls at a crossing."""
close = Boxes.close
def vWalls(self, x, y):
"""Number of vertical walls at a crossing"""
result = 0 result = 0
if y > 0 and self.vwalls[y - 1][x]: if y > 0 and self.vwalls[y - 1][x]:
result += 1 result += 1
if y < len(self.y) and self.vwalls[y][x]: if y < len(self.y) and self.vwalls[y][x]:
result += 1 result += 1
return result return result
def hWalls(self, x, y): def hWalls(self, x: int, y: int) -> int:
"""Number of horizontal walls at a crossing""" """Number of horizontal walls at a crossing."""
result = 0 result = 0
if x > 0 and self.hwalls[y][x - 1]: if x > 0 and self.hwalls[y][x - 1]:
result += 1 result += 1
@ -131,22 +130,18 @@ You can replace the space characters representing the floor by a "X" to remove t
result += 1 result += 1
return result return result
def vFloor(self, x, y): def vFloor(self, x: int, y: int) -> bool:
"""Is there floor under vertical wall""" """Is there floor under vertical wall."""
if y >= len(self.y): if y >= len(self.y):
return False return False
return ( return (x > 0 and self.floors[y][x - 1]) or (x < len(self.x) and self.floors[y][x])
(x > 0 and self.floors[y][x - 1]) or
(x < len(self.x) and self.floors[y][x]))
def hFloor(self, x, y): def hFloor(self, x: int, y: int) -> bool:
"""Is there foor under horizontal wall""" """Is there floor under horizontal wall."""
if x >= len(self.x): if x >= len(self.x):
return False return False
return ( return (y > 0 and self.floors[y - 1][x]) or (y < len(self.y) and self.floors[y][x])
(y > 0 and self.floors[y - 1][x]) or
(y < len(self.y) and self.floors[y][x]))
@restore @restore
def edgeAt(self, edge, x, y, length, angle=0): def edgeAt(self, edge, x, y, length, angle=0):
@ -168,7 +163,7 @@ You can replace the space characters representing the floor by a "X" to remove t
if self.hi: if self.hi:
self.hi = self.adjustSize(self.hi, e2=False) self.hi = self.adjustSize(self.hi, e2=False)
self.hi = hi = self.hi or self.h self.hi = self.hi or self.h
self.edges["s"] = boxes.edges.Slot(self, self.hi / 2.0) self.edges["s"] = boxes.edges.Slot(self, self.hi / 2.0)
self.edges["C"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi) self.edges["C"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi)
self.edges["D"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi, outset=self.thickness) self.edges["D"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi, outset=self.thickness)
@ -176,10 +171,9 @@ You can replace the space characters representing the floor by a "X" to remove t
def walls(self, move=None): def walls(self, move=None):
lx = len(self.x) lx = len(self.x)
ly = len(self.y) ly = len(self.y)
t = self.thickness # t = self.thickness
b = self.burn # b = self.burn
t2 = self.thickness / 2.0 # t2 = self.thickness / 2.0
self.ctx.save() self.ctx.save()
@ -212,8 +206,7 @@ You can replace the space characters representing the floor by a "X" to remove t
edges.append("E") edges.append("E")
lengths.append(self.x[end]) lengths.append(self.x[end])
if (self.hFloor(end, y) == 0 and if self.hFloor(end, y) == 0 and self.hFloor(end + 1, y) == 0:
self.hFloor(end+1, y) == 0):
edges.append("EDs"[self.vWalls(end + 1, y)]) edges.append("EDs"[self.vWalls(end + 1, y)])
else: else:
edges.append("eCs"[self.vWalls(end + 1, y)]) edges.append("eCs"[self.vWalls(end + 1, y)])
@ -235,7 +228,6 @@ You can replace the space characters representing the floor by a "X" to remove t
self.rectangularWall(10, h, "ffef", move="up only") self.rectangularWall(10, h, "ffef", move="up only")
self.ctx.save() self.ctx.save()
# Vertical Walls # Vertical Walls
for x in range(lx + 1): for x in range(lx + 1):
if x == 0 or x == lx: if x == 0 or x == lx:
@ -263,8 +255,7 @@ You can replace the space characters representing the floor by a "X" to remove t
edges.append("E") edges.append("E")
lengths.append(self.y[end]) lengths.append(self.y[end])
if (self.vFloor(x, end) == 0 and if self.vFloor(x, end) == 0 and self.vFloor(x, end + 1) == 0:
self.vFloor(x, end + 1) == 0):
edges.append("EDs"[self.hWalls(x, end + 1)]) edges.append("EDs"[self.hWalls(x, end + 1)])
else: else:
edges.append("eCs"[self.hWalls(x, end + 1)]) edges.append("eCs"[self.hWalls(x, end + 1)])
@ -274,13 +265,12 @@ You can replace the space characters representing the floor by a "X" to remove t
lengths.pop() lengths.pop()
edges.pop() edges.pop()
upper = [{ upper = [{"f": "e",
"f": "e", "s": "s",
"s": "s", "e": "e",
"e": "e", "E": "e",
"E": "e", "C": "e",
"C": "e", "D": "e"}[e] for e in reversed(edges)]
"D": "e"}[e] for e in reversed(edges)]
edges = ["e" if e == "s" else e for e in edges] edges = ["e" if e == "s" else e for e in edges]
self.rectangularWall(sum(lengths), h, [ self.rectangularWall(sum(lengths), h, [
boxes.edges.CompoundEdge(self, edges, lengths), boxes.edges.CompoundEdge(self, edges, lengths),
@ -300,7 +290,7 @@ You can replace the space characters representing the floor by a "X" to remove t
b = self.burn b = self.burn
t2 = self.thickness / 2.0 t2 = self.thickness / 2.0
tw, th = sum(self.x) + (lx+1) * t, sum(self.y) + (ly + 1) * t tw, th = sum(self.x) + (lx + 1) * t, sum(self.y) + (ly + 1) * t
if self.move(tw, th, move, True): if self.move(tw, th, move, True):
return return
@ -370,7 +360,7 @@ You can replace the space characters representing the floor by a "X" to remove t
if x == 0 or y == 0 or not self.floors[y - 1][x - 1]: if x == 0 or y == 0 or not self.floors[y - 1][x - 1]:
self.edgeAt("e", posx - b, posy + self.y[y] + t, t, -90) self.edgeAt("e", posx - b, posy + self.y[y] + t, t, -90)
if x == 0 or y == ly - 1 or not self.floors[y + 1][x - 1]: if x == 0 or y == ly - 1 or not self.floors[y + 1][x - 1]:
self.edgeAt("e", posx -b, posy, t, -90) self.edgeAt("e", posx - b, posy, t, -90)
posy += self.y[y] + self.thickness posy += self.y[y] + self.thickness
if x < lx: if x < lx:
posx += self.x[x] + self.thickness posx += self.x[x] + self.thickness
@ -392,7 +382,7 @@ You can replace the space characters representing the floor by a "X" to remove t
continue continue
if line[0] == '+': if line[0] == '+':
w = [] w = []
for n, c in enumerate(line[:len(x)*2 + 1]): for n, c in enumerate(line[:len(x) * 2 + 1]):
if n % 2: if n % 2:
if c == ' ': if c == ' ':
w.append(False) w.append(False)
@ -417,20 +407,20 @@ You can replace the space characters representing the floor by a "X" to remove t
elif c == ' ': elif c == ' ':
f.append(True) f.append(True)
else: else:
raise ValueError('''Can't parse line %i in layout: expected " ", "x" or "X" for char #%i''' % (nr+1, n+1)) raise ValueError("""Can't parse line %i in layout: expected " ", "x" or "X" for char #%i""" % (nr + 1, n + 1))
else: else:
if c == ' ': if c == ' ':
w.append(False) w.append(False)
elif c == '|': elif c == '|':
w.append(True) w.append(True)
else: else:
raise ValueError('''Can't parse line %i in layout: expected " ", or "|" for char #%i''' % (nr+1, n+1)) raise ValueError("""Can't parse line %i in layout: expected " ", or "|" for char #%i""" % (nr + 1, n + 1))
floors.append(f) floors.append(f)
vwalls.append(w) vwalls.append(w)
m = re.match(r"([ |][ xX])+[ |]\s*(\d*\.?\d+)\s*mm\s*", line) m = re.match(r"([ |][ xX])+[ |]\s*(\d*\.?\d+)\s*mm\s*", line)
if not m: if not m:
raise ValueError('''Can't parse line %i in layout: Can read height of the row''' % (nr+1)) raise ValueError("""Can't parse line %i in layout: Can read height of the row""" % (nr + 1))
else: else:
y.append(float(m.group(2))) y.append(float(m.group(2)))
@ -451,8 +441,7 @@ You can replace the space characters representing the floor by a "X" to remove t
raise ValueError("Wrong number of vertical wall lines: %i (%i expected)" % (len(vwalls), ly)) raise ValueError("Wrong number of vertical wall lines: %i (%i expected)" % (len(vwalls), ly))
for nr, walls in enumerate(vwalls): for nr, walls in enumerate(vwalls):
if len(walls) != lx + 1: if len(walls) != lx + 1:
raise ValueError( raise ValueError("Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx + 1))
"Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx + 1))
self.x = x self.x = x
self.y = y self.y = y
@ -460,7 +449,7 @@ You can replace the space characters representing the floor by a "X" to remove t
self.vwalls = vwalls self.vwalls = vwalls
self.floors = floors self.floors = floors
def render(self): def render(self) -> None:
self.prepare() self.prepare()
self.walls() self.walls()
self.base_plate() self.base_plate()

View File

@ -620,7 +620,7 @@ class BServer:
return self.genPageError(name, e, lang) return self.genPageError(name, e, lang)
if name == "TrayLayout": if name == "TrayLayout":
start_response(status, headers) start_response(status, headers)
box.fillDefault(box.x, box.y) box.fillDefault(box.sx, box.sy)
layout2 = boxes.generators.traylayout.TrayLayout2(self, webargs=True) layout2 = boxes.generators.traylayout.TrayLayout2(self, webargs=True)
layout2.argparser.set_defaults(layout=str(box)) layout2.argparser.set_defaults(layout=str(box))
return self.args2html(name, layout2, lang, action="TrayLayout2") return self.args2html(name, layout2, lang, action="TrayLayout2")