cylindertransport.py

changeset 4
f62562506053
parent 3
d8745f771267
child 5
c2158ae1dc05
--- a/cylindertransport.py	Mon Apr 03 03:15:12 2017 +0200
+++ b/cylindertransport.py	Mon Apr 03 04:19:45 2017 +0200
@@ -1,134 +1,161 @@
+"""
+Calculation of spacer pipes for Scuba cylinder transportation
+2017 by NeoSoft, mdd
+Input: see commandline help
+Output: 2D schematic & 3D OpenSCAD script
+"""
 from math import sqrt
 from PIL import Image, ImageDraw, ImageFont
 import argparse, sys
 from data import CYLINDER, PIPES
 from config import FONTBASE
 
-def offset(r1, r2):
-	return (2*sqrt(r1*r2))
+def offset(r_1, r_2):
+    """
+    Calculate horizontal center offset of two circles
+    so they tangent each other
+    """
+    return 2 * sqrt(r_1 * r_2)
 
-class CylinderSpacerCalculator:
-	def __init__(self, cylinders = ["10", "10"], space_min = 10):
-		self.cylinders = cylinders
-		self.space_min = space_min
-		self.font = FONTBASE + "arial.ttf"
-		self.scad = "// Color support only in compile mode (F5)\n" +\
-			"include <cylindertransport.scad>\n"
-		self.circles = []
-		self.spacings = []
-		self.margin = 20
+class CylinderSpacerCalculator():
+    """
+    Class to calculate transport spacer pipes between
+    Scuba cylinders
+    """
+    def __init__(self, cylinders, space_min=10):
+        self.cylinders = cylinders
+        self.space_min = space_min
+        self.font = FONTBASE + "arial.ttf"
+        self.scad = "// Color support only in compile mode (F5)\n" +\
+            "include <cylindertransport.scad>\n"
+        self.circles = []
+        self.spacings = []
+        self.margin = 20
 
-	def calc_min(self, r1, r2):
-		# stupider annaehreungsversuch, bis sich die beiden Tauchflaschen r1 und r2 nicht mehr beruehren
-		for p in PIPES:
-			i = p[1] / 2
-			if i>r1 or i>r2:
-				return None
-			x1 = offset(r1, i)
-			x2 = offset(r2, i)
-			x = (x1 + x2) - (r1+r2) 
-			if x >= self.space_min:
-				print "%s Pipe (%.1fmm), Cylinder spacing: %imm" % (p[0], p[1], x)
-				return [r1, i, r2, p[0]]
-		return None
+    def calc_min(self, r_1, r_2):
+        """
+        stupider annaehreungsversuch, bis sich die beiden
+        Tauchflaschen r_1 und r_2 nicht mehr beruehren
+        Rueckgabe: 3 Zylinderradien und das label der verwendeten Roehre
+        """
+        for p in PIPES:
+            i = p[1] / 2
+            x_1 = offset(r_1, i)
+            x_2 = offset(r_2, i)
+            x = (x_1 + x_2) - (r_1 + r_2)
+            if x >= self.space_min:
+                print "%s Pipe (%.1fmm), Cylinder spacing: %imm" % (
+                    p[0], p[1], x)
+                return [r_1, i, r_2, p[0]]
+        print "Abort: no suitable pipe found"
+        sys.exit(1)
 
-	def _circle(self, x, r, txt = "", size = 1.0):
-		self.circles.append([
-			x, r, txt, size
-			])
+    def _circle(self, x, r, txt="", size=1.0):
+        """
+        Push the circle definition for later rendering
+        """
+        self.circles.append([
+            x, r, txt, size
+            ])
 
-	def _calculate(self):
-		# first bottle spacer
-		r1 = CYLINDER[self.cylinders[0]][0] / 2
-		r2 = CYLINDER[self.cylinders[1]][0] / 2
-		r1, r2, r3, dn  = self.calc_min(r1, r2)
-		x = self.margin + r2 # start offset x
-		self._circle(x, r2, dn, 0.5)
-		self.scad += "spacer(%i, %i, %i, %i);\n" % (
-			x, r2, r3, CYLINDER[self.cylinders[0]][1])
-		x = x + offset(r2, r3)
+    def _calculate(self):
+        """
+        Calculate all cylinder and spacer circles
+        """
+        # first bottle spacer
+        r_1 = CYLINDER[self.cylinders[0]][0] / 2
+        r_2 = CYLINDER[self.cylinders[1]][0] / 2
+        r_1, r_2, r_3, dn = self.calc_min(r_1, r_2)
+        x = self.margin + r_2 # start offset x
+        self._circle(x, r_2, dn, 0.5)
+        self.scad += "spacer(%i, %i, %i, %i);\n" % (
+            x, r_2, r_3, CYLINDER[self.cylinders[0]][1])
+        x = x + offset(r_2, r_3)
 
-		for i in range(0, len(self.cylinders)-1):
-			r1 = CYLINDER[self.cylinders[i]][0] / 2
-			r2 = CYLINDER[self.cylinders[i+1]][0] / 2
-			r1, r2, r3, dn  = self.calc_min(r1, r2)
-			# draw cylinder
-			self._circle(x, r1, "Tank " + self.cylinders[i])
-			self.scad += "tank(%i, %i, %i);\n" % (
-				x, r1, CYLINDER[self.cylinders[i]][1])
-			sx1 = x+r1
-			x = x + offset(r1, r2)
-			# draw right spacer
-			self._circle(x, r2, dn, 0.5)
-			self.scad += "spacer(%i, %i, %i, %i);\n" % (
-				x, r2, r1, CYLINDER[self.cylinders[i]][1])
-			x = x + offset(r2, r3)
-			sx2 = x-r3
-			if i == (len(self.cylinders) - 2):
-				# draw last bottle
-				self._circle(x, r3, "Tank " + self.cylinders[i+1])
-				self.scad += "tank(%i, %i, %i);\n" % (
-					x, r3, CYLINDER[self.cylinders[i+1]][1])
-				x = x + offset(r2, r3)
+        for i in range(0, len(self.cylinders)-1):
+            r_1 = CYLINDER[self.cylinders[i]][0] / 2
+            r_2 = CYLINDER[self.cylinders[i+1]][0] / 2
+            r_1, r_2, r_3, dn = self.calc_min(r_1, r_2)
+            # draw cylinder
+            self._circle(x, r_1, "Tank " + self.cylinders[i])
+            self.scad += "tank(%i, %i, %i);\n" % (
+                x, r_1, CYLINDER[self.cylinders[i]][1])
+            sx1 = x + r_1
+            x = x + offset(r_1, r_2)
+            # draw right spacer
+            self._circle(x, r_2, dn, 0.5)
+            self.scad += "spacer(%i, %i, %i, %i);\n" % (
+                x, r_2, r_1, CYLINDER[self.cylinders[i]][1])
+            x = x + offset(r_2, r_3)
+            sx2 = x - r_3
+            if i == (len(self.cylinders) - 2):
+                # draw last bottle
+                self._circle(x, r_3, "Tank " + self.cylinders[i + 1])
+                self.scad += "tank(%i, %i, %i);\n" % (
+                    x, r_3, CYLINDER[self.cylinders[i + 1]][1])
+                x = x + offset(r_2, r_3)
 
-			self.spacings.append([sx1, sx2])
+            self.spacings.append([sx1, sx2])
+
+        # last bottle spacer pipe
+        self._circle(x, r_2, dn, 0.5)
+        self.scad += "spacer(%i, %i, %i, %i);\n" % (
+            x, r_2, r_3, CYLINDER[self.cylinders[len(self.cylinders)]][1])
+        return int(x + r_2 + self.margin)
 
-		# last bottle spacer pipe
-		self._circle(x, r2, dn, 0.5)
-		self.scad += "spacer(%i, %i, %i, %i);\n" % (
-			x, r2, r3, CYLINDER[self.cylinders[i+1]][1])
-		return int(x + r2 + self.margin)
+    def centertext(self, draw, x, y, txt, size):
+        font = ImageFont.truetype(self.font, int(24 * size))
+        tox, toy = draw.textsize(txt, font=font)
+        draw.text((x - tox / 2, y - toy / 2), \
+            txt, font=font, fill='#ffffff')
 
-	def render_image(self):
-		width = self._calculate()
-		image = Image.new('1', (width, 250)) # create new image
-		draw = ImageDraw.Draw(image)
-		# draw calculated circles
-		for circle in self.circles:
-			x, r, txt, size = circle
-			draw.arc([x - r, 0, x + r, 2 * r], 0, 360, 'white')
-			if txt != "":
-				font = ImageFont.truetype(self.font, int(24 * size))
-				tox, toy = draw.textsize(txt, font=font)
-				draw.text((x - tox / 2, r - toy / 2), txt, font=font, fill='#ffffff')
+    def render_image(self):
+        """
+        Start the calculation and return rendered PIL image object
+        """
+        width = self._calculate()
+        image = Image.new('1', (width, 250)) # create new image
+        draw = ImageDraw.Draw(image)
+        # draw calculated circles
+        for circle in self.circles:
+            x, r, txt, size = circle
+            draw.arc([x - r, 0, x + r, 2 * r], 0, 360, 'white')
+            if txt != "":
+                self.centertext(draw, x, r, txt, size)
 
-		# draw the spacing between cylinders
-		spacerY1 = 200
-		spacerY2 = 220
-		for spacing in self.spacings:
-			sx1, sx2 = spacing
-			draw.line((sx1, spacerY1, sx1, spacerY2), fill='#ffffff')
-			draw.line((sx2, spacerY1, sx2, spacerY2), fill='#ffffff')
-			txt = "%imm" % (sx2 - sx1)
-			font = ImageFont.truetype(FONTBASE+"arial.ttf", 12)
-			tox, toy = draw.textsize(txt, font=font)
-			draw.text((sx1 + (sx2 - sx1) / 2 - tox / 2,
-				spacerY2 + toy / 2), txt, font=font, fill='#ffffff')
+        # draw the spacing between cylinders
+        spacer_y1 = 200
+        spacer_y2 = 220
+        for sx1, sx2 in self.spacings:
+            draw.line((sx1, spacer_y1, sx1, spacer_y2), fill='#ffffff')
+            draw.line((sx2, spacer_y1, sx2, spacer_y2), fill='#ffffff')
+            self.centertext(draw, sx1 + (sx2 - sx1) / 2, \
+                spacer_y2 + 10, "%imm" % (sx2 - sx1), 0.5)
 
-		return image
+        return image
 
 if __name__ == "__main__":
-	parser = argparse.ArgumentParser(description = \
-		"Calculate spacer pipes for pressure cylinder transport\n" +\
-		"Known cylinder types:\n" + ", ".join(sorted(CYLINDER.keys())) )
-	parser.add_argument('cylinders', metavar = 'cylinder',
-		type = str, nargs = '+', help = 'cylinder types')
-	parser.add_argument('--space', dest='space_min',
-		type = int, default=10,
+    parser = argparse.ArgumentParser(description=\
+        "Calculate spacer pipes for pressure cylinder transport\n" +\
+        "Known cylinder types:\n" + ", ".join(sorted(CYLINDER.keys())))
+    parser.add_argument('cylinders', metavar='cylinder', \
+        type=str, nargs='+', help='cylinder types')
+    parser.add_argument('--space', dest='space_min', \
+        type=int, default=10, \
         help='minimum space between cylinders (mm)')
 
-	args = parser.parse_args()
+    options = parser.parse_args()
 
-	for test in args.cylinders:
-		if not test in CYLINDER.keys():
-			print "Cylinder type '%s' is unknown" % test
-			sys.exit(1)
+    for test in options.cylinders:
+        if not test in CYLINDER.keys():
+            print "Cylinder type '%s' is unknown" % test
+            sys.exit(1)
 
-	obj = CylinderSpacerCalculator(
-		args.cylinders, args.space_min)
+    worker = CylinderSpacerCalculator(
+        options.cylinders, options.space_min)
 
-	image = obj.render_image()
-	image.show()
+    image = worker.render_image()
+    image.show()
 
-	print "\n------------ START SCAD SCRIPT ------------"
-	print obj.scad + "------------ END SCAD SCRIPT ------------"
+    print "\n------------ START SCAD SCRIPT ------------"
+    print worker.scad + "------------ END SCAD SCRIPT ------------"

mercurial