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
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import boxes
from boxes import *
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
# to describe the actual box
description = """This is a two step process. 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."""
description = """This is a two step process. This is step 1.
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
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:
Boxes.__init__(self)
self.argparser = argparse.ArgumentParser()
self.argparser.add_argument(
"--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.buildArgParser("sx", "sy")
self.argparser.add_argument(
"--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
# drawing infrastructure
def open(self):
def open(self) -> None:
# Use empty open and close methods to avoid initializing the whole drawing infrastructure.
pass
def close(self):
def close(self) -> None:
# Use empty open and close methods to avoid initializing the whole drawing infrastructure.
pass
def fillDefault(self, x, y):
self.x = [0.0] * x
self.y = [0.0] * y
self.hwalls = [[True for i in range(x)] for j in range(y + 1)]
self.vwalls = [[True for i in range(x + 1)] for j in range(y)]
self.floors = [[True for i in range(x)] for j in range(y)]
def fillDefault(self, sx: list[float], sy: list[float]) -> None:
self.sx = sx
self.sy = sy
x = len(sx)
y = len(sy)
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:
r = []
for i, x in enumerate(self.x):
r.append(" |" * (i) + " ,> %.1fmm\n" % x)
for i, x in enumerate(self.sx):
r.append(" |" * i + " ,> %.1fmm\n" % x)
for hwalls, vwalls, floors, y in zip(
self.hwalls, self.vwalls, self.floors, self.y):
for hwalls, vwalls, floors, y in zip(self.hwalls, self.vwalls, self.floors, self.sy):
r.append("".join("+" + " -"[h] for h in hwalls) + "+\n")
r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors)))
+ " |"[vwalls[-1]] + " %.1fmm\n" % y)
r.append("".join((" |"[v] + "X "[f] for v, f in zip(vwalls, floors))) + " |"[vwalls[-1]] + " %.1fmm\n" % y)
r.append("".join("+" + " -"[h] for h in self.hwalls[-1]) + "+\n")
return "".join(r)
def render(self):
self.fillDefault(self.x, self.y)
def render(self) -> None:
self.fillDefault(self.sx, self.sy)
with open(self.output, 'w') as f:
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
# as string (with --layout) and turns it into a drawing for a box.
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
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.
@ -100,30 +105,24 @@ You can replace the space characters representing the floor by a "X" to remove t
if not webargs:
self.argparser.add_argument(
"--input", action="store", type=argparse.FileType('r'),
default='traylayout.txt',
default="traylayout.txt",
help="layout file")
self.layout = None
else:
self.argparser.add_argument(
"--layout", action="store", type=str, default="")
# Use normal open and close
open = Boxes.open
close = Boxes.close
def vWalls(self, x, y):
"""Number of vertical walls at a crossing"""
def vWalls(self, x: int, y: int) -> int:
"""Number of vertical walls at a crossing."""
result = 0
if y > 0 and self.vwalls[y - 1][x]:
result += 1
if y < len(self.y) and self.vwalls[y][x]:
result += 1
return result
def hWalls(self, x, y):
"""Number of horizontal walls at a crossing"""
def hWalls(self, x: int, y: int) -> int:
"""Number of horizontal walls at a crossing."""
result = 0
if x > 0 and self.hwalls[y][x - 1]:
result += 1
@ -131,22 +130,18 @@ You can replace the space characters representing the floor by a "X" to remove t
result += 1
return result
def vFloor(self, x, y):
"""Is there floor under vertical wall"""
def vFloor(self, x: int, y: int) -> bool:
"""Is there floor under vertical wall."""
if y >= len(self.y):
return False
return (
(x > 0 and self.floors[y][x - 1]) or
(x < len(self.x) and self.floors[y][x]))
return (x > 0 and self.floors[y][x - 1]) or (x < len(self.x) and self.floors[y][x])
def hFloor(self, x, y):
"""Is there foor under horizontal wall"""
def hFloor(self, x: int, y: int) -> bool:
"""Is there floor under horizontal wall."""
if x >= len(self.x):
return False
return (
(y > 0 and self.floors[y - 1][x]) or
(y < len(self.y) and self.floors[y][x]))
return (y > 0 and self.floors[y - 1][x]) or (y < len(self.y) and self.floors[y][x])
@restore
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:
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["C"] = boxes.edges.CrossingFingerHoleEdge(self, self.hi)
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):
lx = len(self.x)
ly = len(self.y)
t = self.thickness
b = self.burn
t2 = self.thickness / 2.0
# t = self.thickness
# b = self.burn
# t2 = self.thickness / 2.0
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")
lengths.append(self.x[end])
if (self.hFloor(end, y) == 0 and
self.hFloor(end+1, y) == 0):
if self.hFloor(end, y) == 0 and self.hFloor(end + 1, y) == 0:
edges.append("EDs"[self.vWalls(end + 1, y)])
else:
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.ctx.save()
# Vertical Walls
for x in range(lx + 1):
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")
lengths.append(self.y[end])
if (self.vFloor(x, end) == 0 and
self.vFloor(x, end + 1) == 0):
if self.vFloor(x, end) == 0 and self.vFloor(x, end + 1) == 0:
edges.append("EDs"[self.hWalls(x, end + 1)])
else:
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()
edges.pop()
upper = [{
"f": "e",
"s": "s",
"e": "e",
"E": "e",
"C": "e",
"D": "e"}[e] for e in reversed(edges)]
upper = [{"f": "e",
"s": "s",
"e": "e",
"E": "e",
"C": "e",
"D": "e"}[e] for e in reversed(edges)]
edges = ["e" if e == "s" else e for e in edges]
self.rectangularWall(sum(lengths), h, [
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
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):
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]:
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]:
self.edgeAt("e", posx -b, posy, t, -90)
self.edgeAt("e", posx - b, posy, t, -90)
posy += self.y[y] + self.thickness
if x < lx:
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
if line[0] == '+':
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 c == ' ':
w.append(False)
@ -417,20 +407,20 @@ You can replace the space characters representing the floor by a "X" to remove t
elif c == ' ':
f.append(True)
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:
if c == ' ':
w.append(False)
elif c == '|':
w.append(True)
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)
vwalls.append(w)
m = re.match(r"([ |][ xX])+[ |]\s*(\d*\.?\d+)\s*mm\s*", line)
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:
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))
for nr, walls in enumerate(vwalls):
if len(walls) != lx + 1:
raise ValueError(
"Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx + 1))
raise ValueError("Wrong number of vertical walls in line %i: %i (%i expected)" % (nr, len(walls), lx + 1))
self.x = x
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.floors = floors
def render(self):
def render(self) -> None:
self.prepare()
self.walls()
self.base_plate()

View File

@ -620,7 +620,7 @@ class BServer:
return self.genPageError(name, e, lang)
if name == "TrayLayout":
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.argparser.set_defaults(layout=str(box))
return self.args2html(name, layout2, lang, action="TrayLayout2")