RE: LDBoxer
2018-01-10, 23:37 (This post was last modified: 2018-01-11, 1:07 by Michael Horvath.)
2018-01-10, 23:37 (This post was last modified: 2018-01-11, 1:07 by Michael Horvath.)
(2018-01-10, 7:41)Jarema Wrote: Roger that. I Take this in my free-time.
I have started fixing it myself, but the script now boxes every single part, so I must have made a mistake somewhere. Can you find the error?
Code:
'''
Created on 16 mar 2017
Updated on 10 jan 2018
@author: Jeremy Czajkowski
@author: Tore Eriksson <[email protected]>
@author: Michael Horvath
@license: GNU General Public License version 3
@version: 2017c
@note: A utility to help you replace LDraw parts with no visible studs or tubes with boxes.
Saves rendering time and CPU power.
'''
import os
import sys
from macpath import dirname
__appname__ = "LDBoxer"
__version__ = "2017c"
NOTFOUND_MSG = "FileNotFoundError: [Errno 2] No such file or directory: '%s'"
INVALIDACCESS_MSG = "ImportError: Invalid access to %s."
CHKLST_INFILE = []
REPLACEDTOTAL_COUNT = 0
LDRAWPATH = MODELPATH = ""
def isBox(fil): # mjh
if fil[0:2].upper() == "B\\":
return True
else:
return False
def ldLineType(ldline):
result = -1;
s = ldline.strip()
if len(s)>0 :
if s[0]=='0' : result = 0 # mjh
if s[0]=='1' : result = 1 # mjh
if s[0]=='2' : result = 2 # mjh
if s[0]=='3' : result = 3 # mjh
if s[0]=='4' : result = 4 # mjh
if s[0]=='5' : result = 5 # mjh
return result
def ldLineUpdate(ldline, ItemNr, NewVal):
color1 = ldExtractFromLine(ldline, 2)
x1 = float(ldExtractFromLine(ldline, 3))
y1 = float(ldExtractFromLine(ldline, 4))
z1 = float(ldExtractFromLine(ldline, 5))
a1 = float(ldExtractFromLine(ldline, 6))
b1 = float(ldExtractFromLine(ldline, 7))
c1 = float(ldExtractFromLine(ldline, 8))
d1 = float(ldExtractFromLine(ldline, 9))
e1 = float(ldExtractFromLine(ldline, 10))
f1 = float(ldExtractFromLine(ldline, 11))
g1 = float(ldExtractFromLine(ldline, 12))
h1 = float(ldExtractFromLine(ldline, 13))
i1 = float(ldExtractFromLine(ldline, 14))
fil = ldExtractFromLine(ldline, 15)
if ItemNr == 2:
color1 = NewVal
if ItemNr == 3:
x1 = float(NewVal)
if ItemNr == 4:
y1 = float(NewVal)
if ItemNr == 5:
z1 = float(NewVal)
if ItemNr == 6:
a1 = float(NewVal)
if ItemNr == 7:
b1 = float(NewVal)
if ItemNr == 8:
c1 = float(NewVal)
if ItemNr == 9:
d1 = float(NewVal)
if ItemNr == 10:
e1 = float(NewVal)
if ItemNr == 11:
f1 = float(NewVal)
if ItemNr == 12:
g1 = float(NewVal)
if ItemNr == 13:
h1 = float(NewVal)
if ItemNr == 14:
i1 = float(NewVal)
if ItemNr == 15:
fil = NewVal
s = '1 ' + color1 + ' '
s = s + FloatToLDraw(x1)+ ' '
s = s + FloatToLDraw(y1)+ ' '
s = s + FloatToLDraw(z1)+ ' '
s = s + FloatToLDraw(a1)+ ' '
s = s + FloatToLDraw(b1)+ ' '
s = s + FloatToLDraw(c1)+ ' '
s = s + FloatToLDraw(d1)+ ' '
s = s + FloatToLDraw(e1)+ ' '
s = s + FloatToLDraw(f1)+ ' '
s = s + FloatToLDraw(g1)+ ' '
s = s + FloatToLDraw(h1)+ ' '
s = s + FloatToLDraw(i1)+ ' '
s = s + fil
return s
def ldExtractFromLine (ldline, post):
post -= 1 # mjh
t = []
s = ldline.strip()
iT = 0; # mjh
while s <> '':
s = s.strip() + ' '
i = 0 # mjh
while s[i] <> ' ': i += 1
# t[iT] = Copy(s, 1, i-1)
# function Copy(const S: string; From: integer = 1; Count: integer = MaxInt): string;
t.insert(iT, s[0:i]) # mjh
iT += 1
s = s[i+1:] # mjh
result = ''
if post < iT: result = t[post]
return result
def FloatToLDraw(inval):
if (inval > -0.0001) and (inval < 0.0001): inval = 0
return '%.5f' % (round(inval*10000)/10000)
def cmdReplace():
replacedCount = 0
for i in range(CHKLST_INFILE.__len__()):
ldline = CHKLST_INFILE[i]
if ldLineType(ldline) == 1 :
fil = ldExtractFromLine(ldline, 15)
if isBox(fil) == False : fil = strPrefix + fil
fname = os.path.join(LDRAWPATH ,'Parts' ,fil)
if os.path.exists(fname):
ldline = ldLineUpdate(ldline, 15, fil)
CHKLST_INFILE[i] = ldline + "\r\n"
replacedCount += 1;
global REPLACEDTOTAL_COUNT;
REPLACEDTOTAL_COUNT += 1;
if replacedCount>0 :
CHKLST_INFILE.append("0 // Boxed {0} parts ({1})\r\n".format(replacedCount ,strPrefix))
if __name__ == '__main__':
if sys.argv.__len__() != 3:
print "Invalid arguments"
sys.exit(2)
LDRAWPATH = sys.argv[1] # mjh, don't change
MODELPATH = sys.argv[2] # mjh, don't change
if not os.path.isdir(LDRAWPATH):
print NOTFOUND_MSG % LDRAWPATH
sys.exit(2)
if not os.path.isfile(MODELPATH):
print NOTFOUND_MSG % MODELPATH
sys.exit(2)
try:
with open(MODELPATH ,"r") as f:
for line in f:
CHKLST_INFILE.append(line)
f.close()
except:
CHKLST_INFILE = []
print INVALIDACCESS_MSG % MODELPATH
sys.exit(2)
else:
print __appname__ ,__version__ ,"processing" ,MODELPATH
i = ii = iii = frg = 0
x1 = y1 = z1 = a1 = c1 = g1 = i1 = x2 = y2 = z2 = x3 = y3 = z3 = 0.0
s = ldline = fil = ""
SkipThis = False
StrLstCover = []
StrListInfil = []
"""
cmdFittingsClick STEP 1: Compile a list of locations (20x20LDU)
Tops and Bottoms that are hiding (=covering) details from next part
Save the list in StrListCover
"""
for i in range(CHKLST_INFILE.__len__()):
ldline = CHKLST_INFILE[i]
if ldLineType(ldline) <> 1: continue
frg = int(ldExtractFromLine(ldline, 2));
if (frg>31) and (frg<48): continue
if ldExtractFromLine(ldline, 7) <> '0' : continue
if ldExtractFromLine(ldline, 9) <> '0' : continue
if ldExtractFromLine(ldline, 10) <> '1' : continue
if ldExtractFromLine(ldline, 11) <> '0' : continue
if ldExtractFromLine(ldline, 13) <> '0' : continue
fil = ldExtractFromLine(ldline ,15);
if len(fil)<5: continue # just to be foolproof...
"""
2010-03-20 also check if already boxed parts cover positions
by removing B\, B\t, or B\B from examined file reference
"""
if fil[0:3].upper() == "B\\T": # mjh
fil = fil[3:] # mjh
if fil[0:3].upper() == "B\\B": # mjh
fil = fil[3:] # mjh
if fil[0:2].upper() == "B\\": # mjh
fil = fil[2:] # mjh
if len(fil)<5 : continue
fil = fil[0:(len(fil)-4)] # mjh
fil = os.path.join(LDRAWPATH ,'Parts' ,'B' ,fil + '.nfo')
print "Searching for" ,fil
if not os.path.exists(fil) : continue
x1 = float(ldExtractFromLine(ldline ,3))
y1 = float(ldExtractFromLine(ldline ,4))
z1 = float(ldExtractFromLine(ldline ,5))
a1 = float(ldExtractFromLine(ldline ,6))
c1 = float(ldExtractFromLine(ldline ,8))
g1 = float(ldExtractFromLine(ldline ,12))
i1 = float(ldExtractFromLine(ldline ,14))
NFOCONTENT = []
try:
with open(fil ,"r") as f:
for line in f:
NFOCONTENT.append(line)
f.close()
except:
NFOCONTENT = []
print INVALIDACCESS_MSG % fil
StrListInfil = []
StrListInfil.extend(NFOCONTENT)
for ii in range(StrListInfil.__len__()):
ldline = StrListInfil[ii]
s = ldExtractFromLine(ldline, 1)
x2 = float(ldExtractFromLine(ldline, 2))
y2 = float(ldExtractFromLine(ldline, 3))
z2 = float(ldExtractFromLine(ldline, 4))
if s=='Top' or s=='Stud' : s = 'T '
if s=='Bottom' : s = 'B '
x3 = x1 + x2*a1 + z2*c1
y3 = y1 + y2
z3 = z1 + x2*g1 + z2*i1
s = s + FloatToLDraw(x3) + ' '
s = s + FloatToLDraw(y3) + ' '
s = s + FloatToLDraw(z3)
StrLstCover.append(s)
"""
END of cmdFittingsClick STEP 1
The model file in chklstInfile has been scanned for locations
meeting all the given criterias
For example:
This following line meets the criteria:
1 15 240 -48 160 1 0 0 0 1 0 0 0 1 3005.dat
The two lines from the file Parts\B\3005.nfo is used:
Stud 0 0 0
Bottom 0 24 0
The output stored in StrListCover is the following two lines:
T 240 -48 160
B 240 -24 160
"""
"""
cmdFittingsClick STEP 2: Replace all parts that can be fully boxed
Checkbox all parts that has all stud and bottom locations covered
according to StrListCover
"""
for i in range(CHKLST_INFILE.__len__()):
ldline = CHKLST_INFILE[i]
if ldLineType(ldline) <> 1 : continue;
frg = int(ldExtractFromLine(ldline, 2))
if (frg>31) and (frg<48) : continue
if ldExtractFromLine(ldline, 7) <> '0' : continue
if ldExtractFromLine(ldline, 9) <> '0' : continue
if ldExtractFromLine(ldline, 10) <> '1' : continue
if ldExtractFromLine(ldline, 11) <> '0' : continue
if ldExtractFromLine(ldline, 13) <> '0' : continue
fil = ldExtractFromLine(ldline, 15)
if len(fil)<5 : continue
fil = fil[0:(len(fil)-4)] # mjh
fil = os.path.join(LDRAWPATH ,'Parts' ,'B' ,fil + '.dat')
if not os.path.exists(fil): continue
fil = fil[0:(len(fil)-4)]
fil = fil + '.nfo';
if not os.path.exists(fil): continue
x1 = float(ldExtractFromLine(ldline, 3))
y1 = float(ldExtractFromLine(ldline, 4))
z1 = float(ldExtractFromLine(ldline, 5))
a1 = float(ldExtractFromLine(ldline, 6))
c1 = float(ldExtractFromLine(ldline, 8))
g1 = float(ldExtractFromLine(ldline, 12))
i1 = float(ldExtractFromLine(ldline, 14))
NFOCONTENT = []
try:
with open(fil ,"r") as f:
for line in f:
NFOCONTENT.append(line)
f.close()
except:
NFOCONTENT = []
print INVALIDACCESS_MSG % fil
StrListInfil = []
StrListInfil.extend(NFOCONTENT)
SkipThis = False
for ii in range(StrListInfil.__len__()):
ldline = StrListInfil[ii]
s = ldExtractFromLine(ldline, 1)
x2 = float(ldExtractFromLine(ldline, 2))
y2 = float(ldExtractFromLine(ldline, 3))
z2 = float(ldExtractFromLine(ldline, 4))
if s =='Top' : continue
if s =='Stud' : s = 'B ' # Scan for matching B
if s =='Bottom' : s = 'T ' # Scan for matching T
x3 = x1 + x2*a1 + z2*c1
y3 = y1 + y2
z3 = z1 + x2*g1 + z2*i1
s = s + FloatToLDraw(x3) + ' '
s = s + FloatToLDraw(y3) + ' '
s = s + FloatToLDraw(z3)
SkipThis == True
for iii in range(StrLstCover.__len__()):
if s==StrLstCover[iii] : SkipThis = False
if SkipThis : break
if SkipThis : continue
strPrefix = "B\\"
cmdReplace()
"""
END of cmdFittingsClick STEP 2
"""
"""
cmdFittingsClick STEP 3: Replace all parts that studs can be removed from
(STEPs 3 & 4 should be easily baked into STEP 2...)
"""
for i in range(CHKLST_INFILE.__len__()):
ldline = CHKLST_INFILE[i]
if ldLineType(ldline) <> 1: continue;
frg = int(ldExtractFromLine(ldline, 2));
if (frg>31) and (frg<48) : continue;
if ldExtractFromLine(ldline, 7) <> '0' : continue
if ldExtractFromLine(ldline, 9) <> '0' : continue
if ldExtractFromLine(ldline, 10) <> '1' : continue
if ldExtractFromLine(ldline, 11) <> '0' : continue
if ldExtractFromLine(ldline, 13) <> '0' : continue
fil = ldExtractFromLine(ldline, 15);
if len(fil)<5 : continue
fil = fil[0:(len(fil)-4)] # mjh
fil = os.path.join(LDRAWPATH ,'Parts' ,'B' ,fil + '.dat')
if not os.path.exists(fil) : continue
fil = fil[0:(len(fil)-4)] # mjh
fil = fil + '.nfo'
if not os.path.exists(fil) : continue
x1 = float(ldExtractFromLine(ldline, 3))
y1 = float(ldExtractFromLine(ldline, 4))
z1 = float(ldExtractFromLine(ldline, 5))
a1 = float(ldExtractFromLine(ldline, 6))
c1 = float(ldExtractFromLine(ldline, 8))
g1 = float(ldExtractFromLine(ldline, 12))
i1 = float(ldExtractFromLine(ldline, 14))
NFOCONTENT = []
try:
with open(fil ,"r") as f:
for line in f:
NFOCONTENT.append(line)
f.close()
except:
NFOCONTENT = []
print INVALIDACCESS_MSG % fil
StrListInfil = []
StrListInfil.extend(NFOCONTENT)
SkipThis = False
for ii in range (StrListInfil.__len__()) :
ldline = StrListInfil[ii]
s = ldExtractFromLine(ldline, 1)
x2 = float(ldExtractFromLine(ldline, 2))
y2 = float(ldExtractFromLine(ldline, 3))
z2 = float(ldExtractFromLine(ldline, 4))
if s =='Top' : continue
#if s == 'Stud': continue
if s =='Stud' : s = 'B ' # Scan for matching B
if s =='Bottom' : continue
#if s == 'Bottom': s = 'T ' # Scan for matching T
x3 = x1 + x2*a1 + z2*c1
y3 = y1 + y2
z3 = z1 + x2*g1 + z2*i1
s = s + FloatToLDraw(x3) + ' '
s = s + FloatToLDraw(y3) + ' '
s = s + FloatToLDraw(z3)
SkipThis = True;
for iii in range (StrLstCover.__len__()) :
if s==StrLstCover[iii] : SkipThis = False
if SkipThis : break
if SkipThis : continue
strPrefix = 'B\\T'
cmdReplace()
"""
END of cmdFittingsClick STEP 3
"""
"""
cmdFittingsClick STEP 4: Replace all parts that bottom details
can be removed from
(STEPs 3 & 4 should be easily baked into STEP 2...)
"""
for i in range (CHKLST_INFILE.__len__()) :
ldline = CHKLST_INFILE[i];
if ldLineType(ldline) <> 1 : continue;
frg = int(ldExtractFromLine(ldline, 2));
if (frg>31) and (frg<48) : continue;
if ldExtractFromLine(ldline, 7) <> '0' : continue;
if ldExtractFromLine(ldline, 9) <> '0' : continue;
if ldExtractFromLine(ldline, 10) <> '1' : continue;
if ldExtractFromLine(ldline, 11) <> '0' : continue;
if ldExtractFromLine(ldline, 13) <> '0' : continue;
fil = ldExtractFromLine(ldline, 15);
if len(fil)<5 : continue
fil = fil[0:(len(fil)-4)] # mjh
fil = os.path.join(LDRAWPATH ,'Parts' ,'B' ,fil + '.dat')
if not os.path.exists(fil) : continue
fil = fil[0:(len(fil)-4)] # mjh
fil = fil + '.nfo'
if not os.path.exists(fil) : continue
x1 = float(ldExtractFromLine(ldline, 3))
y1 = float(ldExtractFromLine(ldline, 4))
z1 = float(ldExtractFromLine(ldline, 5))
a1 = float(ldExtractFromLine(ldline, 6))
c1 = float(ldExtractFromLine(ldline, 8))
g1 = float(ldExtractFromLine(ldline, 12))
i1 = float(ldExtractFromLine(ldline, 14))
NFOCONTENT = []
try:
with open(fil ,"r") as f:
for line in f:
NFOCONTENT.append(line)
f.close()
except:
NFOCONTENT = []
print INVALIDACCESS_MSG % fil
StrListInfil = []
StrListInfil.extend(NFOCONTENT)
SkipThis = False
for ii in range (StrListInfil.__len__()) :
ldline = StrListInfil[ii];
s = ldExtractFromLine(ldline, 1)
x2 = float(ldExtractFromLine(ldline, 2))
y2 = float(ldExtractFromLine(ldline, 3))
z2 = float(ldExtractFromLine(ldline, 4))
if s=='Top' : continue
if s=='Stud' : continue
if s=='Stud' : s = 'B ' # Scan for matching B
#if s=='Bottom' : continue
if s=='Bottom' : s = 'T ' # Scan for matching T
x3 = x1 + x2*a1 + z2*c1
y3 = y1 + y2
z3 = z1 + x2*g1 + z2*i1
s = s + FloatToLDraw(x3) + ' '
s = s + FloatToLDraw(y3) + ' '
s = s + FloatToLDraw(z3)
SkipThis = True
for iii in range (StrLstCover.__len__()) :
if s==StrLstCover[iii] : SkipThis = False
if SkipThis : break
if SkipThis : continue
strPrefix = 'B\\B'
cmdReplace()
"""
END of cmdFittingsClick STEP 4
"""
print
print "Boxed %d parts" % REPLACEDTOTAL_COUNT
if REPLACEDTOTAL_COUNT>0 :
# 0 !LDOXER LEVEL info should also be automatically updated!
CHKLST_INFILE.append("0 // Boxed Total {0} parts by {1} v{2}\r\n".format(REPLACEDTOTAL_COUNT ,__appname__ ,__version__))
CHKLST_INFILE.append("0")
try:
dirname = os.path.dirname(MODELPATH)
basename = "boxed_" + os.path.basename(MODELPATH)
with open(os.path.join(dirname,basename) ,"wb") as f:
for line in CHKLST_INFILE:
f.write(line)
f.close()
except Exception, ex:
print ex.message
else:
print "Saved {0} in {1}".format(basename ,dirname)
[edit]
I updated the code with a few fixes.