2019-06-08 17:10:47 -04:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
#
|
|
|
|
# NopSCADlib Copyright Chris Palmer 2018
|
|
|
|
# nop.head@gmail.com
|
|
|
|
# hydraraptor.blogspot.com
|
|
|
|
#
|
|
|
|
# This file is part of NopSCADlib.
|
|
|
|
#
|
|
|
|
# NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the
|
|
|
|
# GNU General Public License as published by the Free Software Foundation, either version 3 of
|
|
|
|
# the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
# See the GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with NopSCADlib.
|
|
|
|
# If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
|
|
import openscad
|
|
|
|
import sys
|
|
|
|
import c14n_stl
|
|
|
|
from set_config import *
|
|
|
|
import time
|
|
|
|
import times
|
|
|
|
from deps import *
|
2021-02-09 04:52:26 -05:00
|
|
|
from tmpdir import *
|
2019-06-11 07:38:00 -04:00
|
|
|
import json
|
2021-02-09 04:18:30 -05:00
|
|
|
import shutil
|
2019-06-08 17:10:47 -04:00
|
|
|
|
2020-03-12 18:47:27 -04:00
|
|
|
def bom_to_parts(bom_dir, part_type, assembly = None):
|
2019-06-08 17:10:47 -04:00
|
|
|
#
|
|
|
|
# Make a list of all the parts in the BOM
|
|
|
|
#
|
|
|
|
part_files = []
|
|
|
|
bom = assembly + '.txt' if assembly else "bom.txt"
|
|
|
|
suffix = ".dxf" if part_type == 'svg' else '.' + part_type
|
2020-03-12 18:47:27 -04:00
|
|
|
with open(bom_dir + '/' + bom, "rt") as f:
|
2019-06-08 17:10:47 -04:00
|
|
|
for line in f.readlines():
|
|
|
|
words = line.split()
|
|
|
|
if words:
|
|
|
|
last_word = words[-1]
|
|
|
|
if last_word.endswith(suffix):
|
|
|
|
part_files.append(last_word[:-4] + '.' + part_type)
|
|
|
|
return part_files
|
|
|
|
|
2020-03-11 19:09:03 -04:00
|
|
|
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)
|
|
|
|
|
2019-06-08 17:10:47 -04:00
|
|
|
def make_parts(target, part_type, parts = None):
|
|
|
|
#
|
2020-03-11 19:09:03 -04:00
|
|
|
# Check list of parts is the correct type
|
|
|
|
#
|
|
|
|
if parts:
|
|
|
|
for p in parts:
|
|
|
|
if not p.endswith('.' + part_type): usage(part_type)
|
|
|
|
#
|
2019-06-08 17:10:47 -04:00
|
|
|
# Make the target directory
|
|
|
|
#
|
2020-03-11 19:09:03 -04:00
|
|
|
top_dir = set_config(target, lambda: usage(part_type))
|
2019-06-08 17:10:47 -04:00
|
|
|
target_dir = top_dir + part_type + 's'
|
2021-02-09 04:18:30 -05:00
|
|
|
deps_dir = target_dir + "/deps"
|
2020-03-12 18:47:27 -04:00
|
|
|
bom_dir = top_dir + "bom"
|
2021-02-09 04:52:26 -05:00
|
|
|
tmp_dir = mktmpdir(top_dir)
|
|
|
|
|
2019-06-08 17:10:47 -04:00
|
|
|
if not os.path.isdir(target_dir):
|
|
|
|
os.makedirs(target_dir)
|
2021-02-09 04:52:26 -05:00
|
|
|
|
2019-06-08 17:10:47 -04:00
|
|
|
if not os.path.isdir(deps_dir):
|
|
|
|
os.makedirs(deps_dir)
|
2021-02-09 04:18:30 -05:00
|
|
|
|
|
|
|
if os.path.isdir(top_dir + '/deps'): #old location
|
|
|
|
shutil.rmtree(top_dir + '/deps')
|
|
|
|
|
2019-06-08 17:10:47 -04:00
|
|
|
times.read_times(target_dir)
|
|
|
|
#
|
|
|
|
# Decide which files to make
|
|
|
|
#
|
2021-02-06 05:39:39 -05:00
|
|
|
all_parts = bom_to_parts(bom_dir, part_type)
|
2019-06-08 17:10:47 -04:00
|
|
|
if parts:
|
|
|
|
targets = list(parts) #copy the list so we dont modify the list passed in
|
|
|
|
else:
|
2021-02-06 05:39:39 -05:00
|
|
|
targets = list(all_parts)
|
2019-06-08 17:10:47 -04:00
|
|
|
for file in os.listdir(target_dir):
|
|
|
|
if file.endswith('.' + part_type):
|
|
|
|
if not file in targets:
|
|
|
|
print("Removing %s" % file)
|
|
|
|
os.remove(target_dir + '/' + file)
|
|
|
|
#
|
2019-06-11 07:38:00 -04:00
|
|
|
# Read existing STL bounds
|
|
|
|
#
|
|
|
|
if part_type == 'stl':
|
|
|
|
bounds_fname = target_dir + '/bounds.json'
|
|
|
|
try:
|
|
|
|
with open(bounds_fname) as json_file:
|
|
|
|
bounds_map = json.load(json_file)
|
|
|
|
except:
|
|
|
|
bounds_map = {}
|
|
|
|
#
|
2019-06-08 17:10:47 -04:00
|
|
|
# Find all the scad files
|
|
|
|
#
|
|
|
|
module_suffix = '_dxf' if part_type == 'svg' else '_' + part_type
|
2020-03-12 18:47:27 -04:00
|
|
|
for dir in source_dirs(bom_dir):
|
|
|
|
if targets and os.path.isdir(dir):
|
2020-02-24 18:58:22 -05:00
|
|
|
for filename in os.listdir(dir):
|
2020-03-12 18:47:27 -04:00
|
|
|
if targets and filename[-5:] == ".scad":
|
2020-02-24 18:58:22 -05:00
|
|
|
#
|
|
|
|
# find any modules ending in _<part_type>
|
|
|
|
#
|
|
|
|
with open(dir + "/" + filename, "r") as f:
|
|
|
|
for line in f.readlines():
|
|
|
|
words = line.split()
|
|
|
|
if(len(words) and words[0] == "module"):
|
|
|
|
module = words[1].split('(')[0]
|
|
|
|
if module.endswith(module_suffix):
|
|
|
|
base_name = module[:-4]
|
|
|
|
part = base_name + '.' + part_type
|
|
|
|
if part in targets:
|
|
|
|
#
|
|
|
|
# Run openscad on the created file
|
|
|
|
#
|
|
|
|
part_file = target_dir + "/" + part
|
|
|
|
dname = deps_name(deps_dir, filename)
|
|
|
|
changed = check_deps(part_file, dname)
|
|
|
|
changed = times.check_have_time(changed, part)
|
|
|
|
if part_type == 'stl' and not changed and not part in bounds_map:
|
|
|
|
changed = "No bounds"
|
|
|
|
if changed:
|
|
|
|
print(changed)
|
2020-03-01 13:35:53 -05:00
|
|
|
#
|
|
|
|
# make a file to use the module
|
|
|
|
#
|
2021-02-09 04:52:26 -05:00
|
|
|
part_maker_name = tmp_dir + '/' + part_type + ".scad"
|
2020-03-01 13:35:53 -05:00
|
|
|
with open(part_maker_name, "w") as f:
|
2021-02-09 04:52:26 -05:00
|
|
|
f.write("use <%s/%s>\n" % (reltmp(dir, target), filename))
|
2020-03-01 13:35:53 -05:00
|
|
|
f.write("%s();\n" % module);
|
2020-02-24 18:58:22 -05:00
|
|
|
t = time.time()
|
|
|
|
openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name)
|
|
|
|
times.add_time(part, t)
|
|
|
|
if part_type == 'stl':
|
|
|
|
bounds = c14n_stl.canonicalise(part_file)
|
|
|
|
bounds_map[part] = bounds
|
2020-03-01 13:35:53 -05:00
|
|
|
os.remove(part_maker_name)
|
2020-02-24 18:58:22 -05:00
|
|
|
targets.remove(part)
|
2019-06-08 17:10:47 -04:00
|
|
|
#
|
2019-06-11 07:38:00 -04:00
|
|
|
# Write new bounds file
|
|
|
|
#
|
|
|
|
if part_type == 'stl':
|
|
|
|
with open(bounds_fname, 'w') as outfile:
|
|
|
|
json.dump(bounds_map, outfile, indent = 4)
|
|
|
|
#
|
2021-02-09 04:52:26 -05:00
|
|
|
# Remove tmp dir
|
|
|
|
#
|
|
|
|
rmtmpdir(tmp_dir)
|
|
|
|
#
|
2019-06-08 17:10:47 -04:00
|
|
|
# List the ones we didn't find
|
|
|
|
#
|
|
|
|
if targets:
|
|
|
|
for part in targets:
|
2020-03-12 18:47:27 -04:00
|
|
|
print("Could not find a module called", part[:-4] + module_suffix, "to make", part)
|
2020-03-11 19:09:03 -04:00
|
|
|
usage(part_type)
|
2021-02-06 05:39:39 -05:00
|
|
|
times.print_times(all_parts)
|