diff --git a/AutoKey.py b/AutoKey.py index 5c3b0b5..2b0a6af 100755 --- a/AutoKey.py +++ b/AutoKey.py @@ -221,14 +221,15 @@ def empty(): fgdmodel = np.zeros((1,65),np.float64) cv2.grabCut(img2,mask,rect,bgdmodel,fgdmodel,5,cv2.GC_INIT_WITH_MASK) elif k == ord('m'): - cv2.imwrite('tmp.pbm',bwimg) + # Write 1 channel + cv2.imwrite('tmp.pbm',bwimg[:, :, 1]) subprocess.check_call([ "potrace", "tmp.pbm", "--tight", "-s", "-o", "tmp.svg" ]) - subprocess.check_call(["inkscape", "-h", str(img.shape[0]), "-b", "white", "-e", "tmp.png", "tmp.svg"]) + subprocess.check_call(["inkscape", "-h", str(img.shape[0]), "-b", "white", "--export-type", "png", "--export-filename", "tmp.png", "tmp.svg"]) svg = cv2.imread("tmp.png") mh = img.shape[0] - svg.shape[0] @@ -241,7 +242,7 @@ def empty(): if mw <= 0: mw = 0 - svg = cv2.copyMakeBorder(svg, mh/2, mh/2 + mh % 2, mw/2, mw/2 + mw % 2, cv2.BORDER_CONSTANT, value=(255, 255, 255, 255)) + svg = cv2.copyMakeBorder(svg, int(mh/2), int(mh/2 + mh % 2), int(mw/2), int(mw/2 + mw % 2), cv2.BORDER_CONSTANT, value=(255, 255, 255, 255)) mask2 = np.where((mask==1) + (mask==3),255,0).astype('uint8') output = cv2.bitwise_and(img2,img2,mask=mask2) @@ -261,6 +262,15 @@ def empty(): cv2.destroyAllWindows() + # Remove tmp file, that should be moved in another location... + try: + os.remove("tmp.pbm") + os.remove("tmp.png") + os.remove("tmp.svg") + os.remove("grabcut_output.png") + os.remove("grabcut_summary.png") + except OSError: + pass return def main(argv=None): @@ -293,6 +303,10 @@ def main(argv=None): parser.add_argument("--thin-handle", dest="thin_handle", action='store_true', required=False, help="Use a thin handle suitable for impressioning grips") parser.add_argument("--match-handle-connector", dest="match_handle_connector", action='store_true', required=False, help="Make the handle same thickness as the connector") + # Outname + parser.add_argument("--refinname", dest="refinname", action='store_true', required=False, help="Add the profile/description/keys in filename like key-AB95-E20-12345.stl") + parser.add_argument("--output", dest="output", required=False, help="Set the output name", metavar="FILE") + parser.add_argument('args', nargs=argparse.REMAINDER) if len(argv) == 0: @@ -359,14 +373,14 @@ def main(argv=None): # Look for length in system definition for branding for line in definition.splitlines(): - m = re.match("\s*kl\s*=\s*([\d\.]+)\s*;", line) + m = re.match(r"\s*kl\s*=\s*([\d\.]+)\s*;", line) if m: def_kl = m.group(1) next # Look for tolerance in profile definition for branding for idx,line in enumerate(profile_definition.splitlines()): - m = re.match("\s*tol\s*=\s*([\d\.]+)\s*;", line) + m = re.match(r"\s*tol\s*=\s*([\d\.]+)\s*;", line) if m: def_tol = m.group(1) def_tol_idx = idx @@ -389,13 +403,22 @@ def main(argv=None): branding = branding.replace("%model%", model) branding = branding.replace("%length%", "%s" % def_kl) branding = branding.replace("%tol%", "%s" % def_tol) + if opts.bumpkey: + branding = branding.replace("%code%", "%s" % "bumpkey") + elif opts.blank: + branding = branding.replace("%code%", "%s" % "blank") + elif opts.key: + branding = branding.replace("%code%", "%s" % (opts.key if opts.key else "NA")) + else: + branding = branding.replace("%code%", "%s" % "NA") + with open(os.path.join(BRAND_DIR, "branding.svg"), 'w') as f: f.write(branding) DEVNULL = open(os.devnull, 'w') - subprocess.check_call(["inkscape", "--export-eps", os.path.join(BRAND_DIR, "branding.eps"), os.path.join(BRAND_DIR, "branding.svg"),]) - subprocess.check_call(["pstoedit", "-nb", "-dt", "-f", "dxf:-polyaslines", os.path.join(BRAND_DIR, "branding.eps"), os.path.join(BRAND_DIR, "branding.dxf")], stderr=DEVNULL) + subprocess.check_call(["inkscape", "--export-type", "eps","--export-filename", os.path.join(BRAND_DIR, "branding.eps"), os.path.join(BRAND_DIR, "branding.svg"),]) + subprocess.check_call(["pstoedit", "-nb", "-dt", "-f", "dxf:-polyaslines", os.path.join(BRAND_DIR, "branding.eps"), os.path.join(BRAND_DIR, "branding.dxf")], stderr=subprocess.DEVNULL) # Read base settings with open(os.path.join(BASE_DIR, "base-settings.scad"), 'r') as f: @@ -434,7 +457,7 @@ def main(argv=None): combination = opts.key.split(",") for idx in range(0, len(combination)): try: - int(combination[idx]) + float(combination[idx]) except ValueError: combination[idx] = '"%s"' % combination[idx] f.write("combination = [%s];\n" % ",".join(combination)) @@ -462,10 +485,22 @@ def main(argv=None): f.write("include ;") f.write("\n") - subprocess.check_call(["inkscape", "--export-eps", os.path.join(BASE_DIR, "profile.eps"), opts.profile]) - subprocess.check_call(["pstoedit", "-nb", "-dt", "-f", "dxf:-polyaslines", os.path.join(BASE_DIR, "profile.eps"), os.path.join(BASE_DIR, "profile.dxf")], stderr=DEVNULL) - subprocess.check_call(["openscad", os.path.join(BASE_DIR, "key.scad") ]) - + outputname = "key.stl" + if opts.refinname: + # result + code = "NA" + if opts.bumpkey: + code = "bumbkey" + if opts.blank: + code = "blank" + if opts.key: + code = "".join(opts.key.split(",")) + outputname = "key_{}_{}_{}_{}_{}.stl".format(os.path.basename(opts.profile).replace(".svg", ""), model, code, def_kl, def_tol) + elif opts.output: + outputname = opts.output + subprocess.check_call(["inkscape", "--export-type", "eps","--export-filename", os.path.join(BASE_DIR, "profile.eps"), opts.profile]) + subprocess.check_call(["pstoedit", "-nb", "-dt", "-f", "dxf:-polyaslines", os.path.join(BASE_DIR, "profile.eps"), os.path.join(BASE_DIR, "profile.dxf")], stderr=subprocess.DEVNULL) + subprocess.check_call(["/usr/bin/openscad", os.path.join(BASE_DIR, "key.scad") ]) if __name__ == "__main__": sys.exit(main()) diff --git a/README.md b/README.md index 7ce281c..3f0447d 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,17 @@ AutoKey3D (formerly known as PhotoBump) is a software to create 3D models for key blanks, bumpkeys and regular keys. +This is an updated fork with the addition of metric measures. + For that, some things should be updated on files before the key generation. +1. You should have the distance between the shoulder and the first PIN for the **aspace** variable on the metric.scad file +2. You shoud have the key length for the **kl** variable on the metric.scad file +3. You should have the space between each pin for the variable **pinspace** on the metric.scad file +3. You should have the height of each PIN from the key base +4. You can now generate the key by using the command like this `python3 AutoKey.py --key 6.7,6.3,7.8,6.6,6.7 --profile profiles/metric.svg --definition definitions/metric.scad` +5. You should to update the metric.scg file by te profile that you ant to use. + +Note: The original author of the tool created a web site with that tool but the metric is not still implemented. A [pull request](https://github.com/choller/autokey3d/pull/7) is open to add that feature to avoid having all the dependencies installed on a computer (https://autokey.own-hero.net) + ## License Please note that AutoKey3D is released under a *non-commercial* license (CC BY-NC-SA 4.0). diff --git a/branding/branding-template.svg b/branding/branding-template.svg index 29f44a2..ca816ac 100644 --- a/branding/branding-template.svg +++ b/branding/branding-template.svg @@ -53,7 +53,7 @@ id="layer1"> by AutoKey3Dl=%length% t=%tol%l=%length% t=%tol% + id="tspan2985">c=%code%by AutoKey3D diff --git a/definitions/metric.scad b/definitions/metric.scad new file mode 100644 index 0000000..722e961 --- /dev/null +++ b/definitions/metric.scad @@ -0,0 +1,29 @@ +// This definition is also valid for: AB A90 + +// Key length +kl=27.7; + +// Combination cuts + +// Shoulder +aspace = 4.7; + +// Pin distance +pinspace = 4.05; + + +// not used +// Highest cut +hcut = ph - 2*tol - 4.45; + + // Cut spacing +cutspace = 1; // Actually alternating between 0.43/0.44 + +// Cut angle +cutangle = 112; + +// Plateau spacing of the cut +platspace = 0.0; + +// cur the key from the bottom by giving the size in milimeter. +realdim = true; diff --git a/includes/default-keycombcuts.scad b/includes/default-keycombcuts.scad index 4266586..23fdece 100644 --- a/includes/default-keycombcuts.scad +++ b/includes/default-keycombcuts.scad @@ -1,26 +1,26 @@ include ; -module keycombcuts(laser=false) { +module keycombcuts(laser=false, realdim=false) { for (i = [0:len(keycomb)-1]) { - keycombcut(i, keycomb[i], aspace, laser); + keycombcut(i, keycomb[i], aspace, laser, realdim=realdim); } if (laser) { - keycombcuts_laser(); + keycombcuts_laser(realdim=realdim); } } -module keycombcuts_laser() { +module keycombcuts_laser(realdim=false) { for (i = [0:len(keycomb)-1]) { if (i < len(keycomb)-1) { hull() { - keycombcut(i, keycomb[i], aspace, true, false, true); - keycombcut(i+1, keycomb[i+1], aspace, true, true, false); + keycombcut(i, keycomb[i], aspace, true, false, true, realdim=realdim); + keycombcut(i+1, keycomb[i+1], aspace, true, true, false, realdim=realdim); } } } hull() { - keycombcut(len(keycomb)-1, keycomb[len(keycomb)-1], aspace, true, false, true); + keycombcut(len(keycomb)-1, keycomb[len(keycomb)-1], aspace, true, false, true, realdim=realdim); translate([0,0,-kl]) - keycombcut(len(keycomb)-1, keycomb[len(keycomb)-1], aspace, true, false, true); + keycombcut(len(keycomb)-1, keycomb[len(keycomb)-1], aspace, true, false, true, realdim=realdim); } } diff --git a/includes/regularcut.scad b/includes/regularcut.scad index a5d1ade..3bec0f7 100644 --- a/includes/regularcut.scad +++ b/includes/regularcut.scad @@ -1,4 +1,5 @@ -module keycombcut(cutnum, cutlevel, loc_aspace, lcut_mode=false, lcut1=false, lcut2=false, rot=0, xcorr=0) { +module keycombcut(cutnum, cutlevel, loc_aspace, lcut_mode=false, lcut1=false, lcut2=false, rot=0, xcorr=0, realdim=false) { + // echo(cutnum, cutlevel, loc_aspace, lcut_mode, lcut1, lcut2, rot, xcorr); lcut = lcut1 || lcut2; cutdim = 10; d = cutdim / sqrt(2); // Diagonal of the cutting rect @@ -19,7 +20,9 @@ module keycombcut(cutnum, cutlevel, loc_aspace, lcut_mode=false, lcut1=false, lc ycorrect = d * sin(rotangle2) / cos(rotangle2/2) * sin(45+rotangle2/2); zcorrect = d * sin(-rotangle2) / cos(-rotangle2/2) * sin(45-rotangle2/2); - translate([0, addcutdepth + hcut-(cutlevel*cutspace + cutcorr + lcutcorr), 0]) + cutsize = realdim ? (ph - cutlevel) : (addcutdepth + hcut-(cutlevel*cutspace + cutcorr + lcutcorr)); + + translate([0, cutsize, 0]) translate([0,0,(loc_aspace + addaspace + cutnum*pinspace)*-1]) // Pin position translate([0,-cutdim/2 + tol, -cutdim/2 + kl/2]) // Center the cutter at 0. We need to add the tolerance to reach the lower end of the thinned key. //translate([0,-cutdim/2, -cutdim/2 + kl/2]) // Center the cutter at 0. We need to add the tolerance to reach the lower end of the thinned key. diff --git a/key.scad b/key.scad index f64750b..39c1bf5 100644 --- a/key.scad +++ b/key.scad @@ -94,7 +94,7 @@ union() { keytipcuts(); if (!blank) { - keycombcuts(lasercut); + keycombcuts(lasercut, realdim); } } khcyo = -(khcy-ph)/2; diff --git a/profiles/metric.scad b/profiles/metric.scad new file mode 100644 index 0000000..5d1d7c8 --- /dev/null +++ b/profiles/metric.scad @@ -0,0 +1,6 @@ +// The tolerance to use when removing material from the profile +tol = 0.2; + +// Key profile height (including tolerance, i.e. measured on the lock, not the blank) +// If you have information on the key blank height, add 2*tol. +ph=8.8 + 2*tol; diff --git a/profiles/metric.svg b/profiles/metric.svg new file mode 100644 index 0000000..ce4958b --- /dev/null +++ b/profiles/metric.svg @@ -0,0 +1,61 @@ + + + + + + + + image/svg+xml + + + + + + + + +