Added usage messages to all the scripts and documented multiple configuration

projects.
This commit is contained in:
Chris Palmer 2020-03-11 23:09:03 +00:00
parent a8422a6aa6
commit 23a64f238d
14 changed files with 124 additions and 23 deletions

View File

@ -233,3 +233,13 @@ Vitamins are only ever previewed, so they are optimised to draw quickly in F5 an
In OpenCSG 3D difference and intersection are relatively slow and the negative volumes interfere with nearby objects when they are composed into assemblies. For this reason as much In OpenCSG 3D difference and intersection are relatively slow and the negative volumes interfere with nearby objects when they are composed into assemblies. For this reason as much
as possible is done by unioning primitives and extruded 2D shapes. Any 3D differences or intersections are wrapped in ```render()``` so that CGAL will compute a polyhedron as possible is done by unioning primitives and extruded 2D shapes. Any 3D differences or intersections are wrapped in ```render()``` so that CGAL will compute a polyhedron
that is cached and reused. This will be very slow the first time it renders but very fast afterwards. that is cached and reused. This will be very slow the first time it renders but very fast afterwards.
### Multiple configurations
Some parametric designs might have several configurations, for example a 3D printer with different size options. If several configurations need to be supported at the
same time multiple sets of BOMS, STLS and DXFs need to be generated in separate diectories. NopSCADlib supports this by having multiple configuration files named
```config_<target_name>.scad```. All the scripts take an optional first parameter that selects one of these config files by specifying ```target_name```.
The target config file is selected by generating ```target.scad``` that includes ```config_<target_name>.scad```.
The rest of the project includes ```target.scad``` to use the configuration.
Additionally all the generated file directories (assemblies, bom, stls, dxfs, etc. are placed in a sub-directory called ```<target_name>```.

View File

@ -189,8 +189,12 @@ def parse_bom(file = "openscad.log", name = None):
print(line[:-1]) print(line[:-1])
return main return main
def usage():
print("\nusage:\n\tbom [target_config] [<accessory_name>_assembly] - Generate BOMs for a project or an accessory to a project.")
sys.exit(1)
def boms(target = None, assembly = None): def boms(target = None, assembly = None):
bom_dir = set_config(target) + "bom" bom_dir = set_config(target, usage) + "bom"
if assembly: if assembly:
bom_dir += "/accessories" bom_dir += "/accessories"
if not os.path.isdir(bom_dir): if not os.path.isdir(bom_dir):
@ -239,11 +243,24 @@ def boms(target = None, assembly = None):
print("done") print("done")
if __name__ == '__main__': if __name__ == '__main__':
args = len(sys.argv) if len(sys.argv) > 3: usage()
if args > 1:
if args > 2: if len(sys.argv) == 3:
boms(sys.argv[1], sys.argv[2]) target, assembly = sys.argv[1], sys.argv[2]
else:
boms(sys.argv[1])
else: else:
boms(); if len(sys.argv) == 2:
if sys.argv[1][-9:] == "_assembly":
target, assembly = None, sys.argv[1]
else:
target, assembly = sys.argv[1], None
else:
target, assembly = None, None
if assembly:
if assembly[-9:] != "_assembly": usage()
try:
boms(target, assembly)
except Exception as e:
print(str(e))
sys.exit(1)

View File

@ -113,5 +113,5 @@ if __name__ == '__main__':
if len(sys.argv) == 2: if len(sys.argv) == 2:
canonicalise(sys.argv[1]) canonicalise(sys.argv[1])
else: else:
print("usage: c14n_stl file") print("\nusage:\n\t c14n_stl file - Canonicalise an STL file created by OpenSCAD.")
sys.exit(1) sys.exit(1)

View File

@ -26,6 +26,7 @@ from __future__ import print_function
import os import os
from tests import do_cmd from tests import do_cmd
import argparse
dir = 'scripts' dir = 'scripts'
@ -74,4 +75,5 @@ They should work with both Python 2 and Python 3.
if __name__ == '__main__': if __name__ == '__main__':
argparse.ArgumentParser().parse_args()
doc_scripts() doc_scripts()

View File

@ -46,11 +46,21 @@ def bom_to_parts(target_dir, part_type, assembly = None):
part_files.append(last_word[:-4] + '.' + part_type) part_files.append(last_word[:-4] + '.' + part_type)
return part_files return part_files
def usage(t):
print("\nusage:\n\t%ss [target_config] [<name1>.%s] ... [<nameN>.%s] - Generate specified %s files or all if none specified." % ( t, t, t, t.upper()))
sys.exit(1)
def make_parts(target, part_type, parts = None): def make_parts(target, part_type, parts = None):
# #
# Check list of parts is the correct type
#
if parts:
for p in parts:
if not p.endswith('.' + part_type): usage(part_type)
#
# Make the target directory # Make the target directory
# #
top_dir = set_config(target) top_dir = set_config(target, lambda: usage(part_type))
target_dir = top_dir + part_type + 's' target_dir = top_dir + part_type + 's'
deps_dir = top_dir + "deps" deps_dir = top_dir + "deps"
if not os.path.isdir(target_dir): if not os.path.isdir(target_dir):
@ -142,5 +152,5 @@ def make_parts(target, part_type, parts = None):
print(part, "is not a", part_type, "file") print(part, "is not a", part_type, "file")
else: else:
print("Could not find a module called", part[:-4] + module_suffix, "to make", part) print("Could not find a module called", part[:-4] + module_suffix, "to make", part)
sys.exit(1) usage(part_type)
times.print_times() times.print_times()

View File

@ -30,6 +30,7 @@ import re
from shutil import copyfile from shutil import copyfile
from tests import update_image from tests import update_image
import sys import sys
import argparse
project_dirs = ['../..', 'examples'] project_dirs = ['../..', 'examples']
target_dir = 'gallery' target_dir = 'gallery'
@ -39,7 +40,6 @@ def gallery(force):
if not os.path.isdir(target_dir): if not os.path.isdir(target_dir):
os.makedirs(target_dir) os.makedirs(target_dir)
paths = sorted([pdir + '/' + i for pdir in project_dirs for i in os.listdir(pdir) if os.path.isdir(pdir + '/' + i + '/assemblies')], key = lambda s: os.path.basename(s)) paths = sorted([pdir + '/' + i for pdir in project_dirs for i in os.listdir(pdir) if os.path.isdir(pdir + '/' + i + '/assemblies')], key = lambda s: os.path.basename(s))
with open(output_name, 'wt') as output_file: with open(output_name, 'wt') as output_file:
print("# A gallery of projects made with NopSCADlib", file = output_file) print("# A gallery of projects made with NopSCADlib", file = output_file)
@ -78,4 +78,8 @@ def gallery(force):
if __name__ == '__main__': if __name__ == '__main__':
init() init()
gallery(force = len(sys.argv) > 1 and sys.argv[1] == '-f') parser = argparse.ArgumentParser()
parser.add_argument("-f", help = "run make_all in each project to force update", action="store_true")
args = parser.parse_args()
gallery(force = args.f)

View File

@ -27,9 +27,17 @@ from bom import boms
from render import render from render import render
from views import views from views import views
from plateup import plateup from plateup import plateup
from set_config import set_config
def usage():
print("\nusage:\n\tmake_all [target_config] - Make all the manufacturing files and readme for a project.")
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 2: usage()
target = None if len(sys.argv) == 1 else sys.argv[1] target = None if len(sys.argv) == 1 else sys.argv[1]
set_config(target, usage)
boms(target) boms(target)
for part in ['stl', 'dxf']: for part in ['stl', 'dxf']:
make_parts(target, part) make_parts(target, part)

View File

@ -25,9 +25,15 @@ import sys
from plateup import plateup from plateup import plateup
def usage():
print("\nusage:\n\tpanels [target_config] - Aggregate DXF files for routing together.")
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 2: usage()
if len(sys.argv) > 1: if len(sys.argv) > 1:
target = sys.argv[1] target = sys.argv[1]
else: else:
target = None target = None
plateup(target, 'dxf') plateup(target, 'dxf', usage)

View File

@ -31,11 +31,11 @@ from shutil import copyfile
source_dirs = { "stl" : "platters", "dxf" : "panels" } source_dirs = { "stl" : "platters", "dxf" : "panels" }
target_dirs = { "stl" : "printed", "dxf" : "routed" } target_dirs = { "stl" : "printed", "dxf" : "routed" }
def plateup(target, part_type): def plateup(target, part_type, usage = None):
# #
# Make the target directory # Make the target directory
# #
top_dir = set_config(target) top_dir = set_config(target, usage)
parts_dir = top_dir + part_type + 's' parts_dir = top_dir + part_type + 's'
target_dir = parts_dir + '/' + target_dirs[part_type] target_dir = parts_dir + '/' + target_dirs[part_type]
source_dir = top_dir + source_dirs[part_type] source_dir = top_dir + source_dirs[part_type]

View File

@ -25,9 +25,15 @@ import sys
from plateup import plateup from plateup import plateup
def usage():
print("\nusage:\n\tplatters [target_config] - Aggregate STL files for printing together.")
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 2: usage()
if len(sys.argv) > 1: if len(sys.argv) > 1:
target = sys.argv[1] target = sys.argv[1]
else: else:
target = None target = None
plateup(target, 'stl') plateup(target, 'stl', usage)

View File

@ -30,11 +30,15 @@ from tests import do_cmd, update_image, colour_scheme, background
from deps import mtime from deps import mtime
from colorama import init from colorama import init
def usage():
print("\nusage:\n\trender [target_config] - Render images of the stl and dxf files.");
sys.exit(1)
def render(target, type): def render(target, type):
# #
# Make the target directory # Make the target directory
# #
target_dir = set_config(target) + type + 's' target_dir = set_config(target, usage) + type + 's'
if not os.path.isdir(target_dir): if not os.path.isdir(target_dir):
os.makedirs(target_dir) os.makedirs(target_dir)
# #
@ -71,6 +75,7 @@ def render(target, type):
if __name__ == '__main__': if __name__ == '__main__':
init() init()
if len(sys.argv) > 2: usage()
target = sys.argv[1] if len(sys.argv) > 1 else None target = sys.argv[1] if len(sys.argv) > 1 else None
render(target, 'stl') render(target, 'stl')
render(target, 'dxf') render(target, 'dxf')

View File

@ -45,20 +45,27 @@ def valid_targets_string():
return result return result
def set_config(target): def set_config(target, usage = None):
if target and target[:1] == '-' and usage: usage()
targets = valid_targets() targets = valid_targets()
if not target: if not target:
if not targets: if not targets:
return "" return ""
print("Must specify a configuration: " + valid_targets_string()) print("Must specify a configuration: " + valid_targets_string())
if usage:
usage()
sys.exit(1) sys.exit(1)
if not targets: if not targets:
print("Not a muli-configuration project (no config_<target>.scad files found)") print("Not a muli-configuration project (no config_<target>.scad files found)")
if usage:
usage()
sys.exit(1) sys.exit(1)
if not target in targets: if not target in targets:
print(target + " is not a configuration, avaliable configurations are: " + valid_targets_string()) print(target + " is not a configuration, avaliable configurations are: " + valid_targets_string())
if usage:
usage()
sys.exit(1) sys.exit(1)
fname = source_dir + "/target.scad" fname = source_dir + "/target.scad"
@ -75,10 +82,13 @@ def set_config(target):
f. write(text); f. write(text);
return target + "/" return target + "/"
def usage():
print("\nusage:\n\tset_config config_name")
sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
args = len(sys.argv) args = len(sys.argv)
if args == 2: if args == 2:
set_config(sys.argv[1]) set_config(sys.argv[1], usage)
else: else:
print("usage: set_config config_name") usage()
sys.exit(1)

View File

@ -85,6 +85,10 @@ def depluralise(name):
def is_plural(name): def is_plural(name):
return name != depluralise(name) return name != depluralise(name)
def usage():
print("\nusage:\n\ttests [test_name1] ... [test_nameN] - Run specified tests or all tests in none specified.");
sys.exit(1)
def tests(tests): def tests(tests):
scad_dir = "tests" scad_dir = "tests"
deps_dir = scad_dir + "/deps" deps_dir = scad_dir + "/deps"
@ -96,6 +100,7 @@ def tests(tests):
doc_name = "readme.md" doc_name = "readme.md"
index = {} index = {}
bodies = {} bodies = {}
done = []
times.read_times() times.read_times()
options.check_options(deps_dir) options.check_options(deps_dir)
# #
@ -114,6 +119,7 @@ def tests(tests):
for scad in scads: for scad in scads:
base_name = scad[:-5] base_name = scad[:-5]
if not tests or base_name in tests: if not tests or base_name in tests:
done.append(base_name)
print(base_name) print(base_name)
cap_name = base_name[0].capitalize() + base_name[1:] cap_name = base_name[0].capitalize() + base_name[1:]
base_name = base_name.lower() base_name = base_name.lower()
@ -234,6 +240,14 @@ def tests(tests):
body += ['\n<a href="#top">Top</a>'] body += ['\n<a href="#top">Top</a>']
body += ["\n---"] body += ["\n---"]
for test in done:
if test in tests:
tests.remove(test)
if tests:
for test in tests:
print(Fore.MAGENTA + "Could not find a test called", test, Fore.WHITE)
usage()
with open(doc_name, "wt") as doc_file: with open(doc_name, "wt") as doc_file:
print('# NopSCADlib', file = doc_file) print('# NopSCADlib', file = doc_file)
print('''\ print('''\
@ -279,4 +293,6 @@ See [usage](docs/usage.md) for requirements, installation instructions and a usa
do_cmd('codespell -L od readme.md'.split()) do_cmd('codespell -L od readme.md'.split())
if __name__ == '__main__': if __name__ == '__main__':
for arg in sys.argv[1:]:
if arg[:1] == '-': usage()
tests(sys.argv[1:]) tests(sys.argv[1:])

View File

@ -97,12 +97,16 @@ def titalise(name):
cap_next = c == ' ' cap_next = c == ' '
return result return result
def usage():
print("\nusage:\n\t views [target_config] [<name1>_assembly] ... [<nameN>_assembly] - Create assembly images and readme.")
sys.exit(1)
def views(target, do_assemblies = None): def views(target, do_assemblies = None):
done_assemblies = [] done_assemblies = []
# #
# Make the target directory # Make the target directory
# #
top_dir = set_config(target) top_dir = set_config(target, usage)
target_dir = top_dir + 'assemblies' target_dir = top_dir + 'assemblies'
deps_dir = top_dir + "deps" deps_dir = top_dir + "deps"
bom_dir = top_dir + "bom" bom_dir = top_dir + "bom"
@ -396,4 +400,7 @@ if __name__ == '__main__':
else: else:
target, assemblies = None, sys.argv[1:] target, assemblies = None, sys.argv[1:]
for a in assemblies:
if a[-9:] != "_assembly": usage()
views(target, assemblies) views(target, assemblies)