working first implementation
This commit is contained in:
parent
14ffc19da8
commit
41e5ec2706
5 changed files with 717 additions and 0 deletions
318
arrange_spread2.py
Normal file
318
arrange_spread2.py
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
import svg
|
||||||
|
import random
|
||||||
|
|
||||||
|
# rounds to the next biggest even number
|
||||||
|
def roundeven(num):
|
||||||
|
return (num+1)/2*2
|
||||||
|
|
||||||
|
def arrange_in_layer(abin, pwidth, pheight, rot_article=False):
|
||||||
|
# articles are longer than wider
|
||||||
|
# default rotation: width: x-direction
|
||||||
|
# height: y-direction
|
||||||
|
|
||||||
|
layer = list()
|
||||||
|
rest = list()
|
||||||
|
root = {'x': 0, 'y': 0,
|
||||||
|
'width': pwidth, 'height': pheight,
|
||||||
|
'article': None,
|
||||||
|
'down': None,
|
||||||
|
'right': None}
|
||||||
|
|
||||||
|
# traverse the tree until a node is found that is big enough for article
|
||||||
|
# with size width x height and return this node or None if not found
|
||||||
|
def find_node(root, width, height):
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
elif root['article']:
|
||||||
|
return (find_node(root['right'], width, height)
|
||||||
|
or find_node(root['down'], width, height))
|
||||||
|
elif width <= root['width'] and height <= root['height']:
|
||||||
|
return root
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# after finding a node where an article fits, put article into the node and
|
||||||
|
# create childnodes
|
||||||
|
def split_node(node, width, height, article):
|
||||||
|
node['article'] = article
|
||||||
|
node['article']['PlacePosition']['X'] = node['x']+width/2
|
||||||
|
node['article']['PlacePosition']['Y'] = node['y']+height/2
|
||||||
|
if node['width'] > 0 and node['height']-height > 0:
|
||||||
|
node['down'] = {'x': node['x'], 'y': node['y']+height,
|
||||||
|
'width': node['width'],
|
||||||
|
'height': node['height']-height,
|
||||||
|
'article': None,
|
||||||
|
'down': None,
|
||||||
|
'right': None}
|
||||||
|
else:
|
||||||
|
node['down'] = None
|
||||||
|
if node['width']-width > 0 and height > 0:
|
||||||
|
node['right'] = {'x': node['x']+width, 'y': node['y'],
|
||||||
|
'width': node['width']-width,
|
||||||
|
'height': height,
|
||||||
|
'article': None,
|
||||||
|
'down': None,
|
||||||
|
'right': None}
|
||||||
|
else:
|
||||||
|
node['right'] = None
|
||||||
|
return node
|
||||||
|
|
||||||
|
# for each article in abin, check and place article at a node. If it doesnt
|
||||||
|
# fit, try to rotate. If it still doesnt fit, append to rest
|
||||||
|
for article in abin:
|
||||||
|
# output format only accepts integer positions, round article sizes up
|
||||||
|
# to even numbers
|
||||||
|
owidth, oheight = article['Article']['Length'], article['Article']['Width']
|
||||||
|
if rot_article:
|
||||||
|
article['Orientation'] = 2
|
||||||
|
width, height = roundeven(oheight), roundeven(owidth)
|
||||||
|
else:
|
||||||
|
article['Orientation'] = 1
|
||||||
|
width, height = roundeven(owidth), roundeven(oheight)
|
||||||
|
|
||||||
|
node = find_node(root, width, height)
|
||||||
|
if (node):
|
||||||
|
node = split_node(node, width, height, article)
|
||||||
|
else:
|
||||||
|
# rotate article
|
||||||
|
# output format only accepts integer positions, round article sizes up
|
||||||
|
# to even numbers
|
||||||
|
if rot_article:
|
||||||
|
article['Orientation'] = 1
|
||||||
|
width, height = roundeven(owidth), roundeven(oheight)
|
||||||
|
else:
|
||||||
|
article['Orientation'] = 2
|
||||||
|
width, height = roundeven(oheight), roundeven(owidth)
|
||||||
|
node = find_node(root, width, height)
|
||||||
|
if (node):
|
||||||
|
node = split_node(node, width, height, article)
|
||||||
|
else:
|
||||||
|
# rotate back
|
||||||
|
if rot_article:
|
||||||
|
article['Orientation'] = 2
|
||||||
|
else:
|
||||||
|
article['Orientation'] = 1
|
||||||
|
rest.append(article)
|
||||||
|
|
||||||
|
# gather all articles that were
|
||||||
|
def find_articles(node):
|
||||||
|
if not node['article']:
|
||||||
|
return
|
||||||
|
layer.append(node['article'])
|
||||||
|
if node['right']:
|
||||||
|
find_articles(node['right'])
|
||||||
|
if node['down']:
|
||||||
|
find_articles(node['down'])
|
||||||
|
|
||||||
|
find_articles(root)
|
||||||
|
|
||||||
|
return root, layer, rest
|
||||||
|
|
||||||
|
# generate a list of random articles of three different type
|
||||||
|
# each type is of the same size and color
|
||||||
|
# numbers of articles of each type linearly depend on their area
|
||||||
|
# articles are generated with more width that height
|
||||||
|
def generate_bin():
|
||||||
|
abin = []
|
||||||
|
for i in 1,2,3:
|
||||||
|
w, h = random.randint(20,150), random.randint(20,150)
|
||||||
|
if h > w:
|
||||||
|
w, h = h, w
|
||||||
|
color = random.randint(0,255), random.randint(0,255), random.randint(0,255)
|
||||||
|
for j in range(200000/(w*h)):
|
||||||
|
abin.append({'x':0, 'y':0, 'width':w, 'height':h, 'color':color})
|
||||||
|
return abin
|
||||||
|
|
||||||
|
# given a node tree with articles inside, spread them out over the full
|
||||||
|
# available area evenly
|
||||||
|
def spread_articles(root):
|
||||||
|
def get_width(article):
|
||||||
|
if article['Orientation'] == 1:
|
||||||
|
return article['Article']['Length']
|
||||||
|
else:
|
||||||
|
return article['Article']['Width']
|
||||||
|
|
||||||
|
def get_height(article):
|
||||||
|
if article['Orientation'] == 1:
|
||||||
|
return article['Article']['Width']
|
||||||
|
else:
|
||||||
|
return article['Article']['Length']
|
||||||
|
|
||||||
|
# get only nodes on the left branch of the tree. This is all nodes below
|
||||||
|
def get_down_nodes(node):
|
||||||
|
if node is None or not node['article']:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
return [node] + get_down_nodes(node['down'])
|
||||||
|
|
||||||
|
# move this node and its whole subtree down
|
||||||
|
def move_tree_down(node, y):
|
||||||
|
if not node['article']:
|
||||||
|
return
|
||||||
|
node['article']['PlacePosition']['Y'] += y
|
||||||
|
if node['right']:
|
||||||
|
move_tree_down(node['right'], y)
|
||||||
|
if node['down']:
|
||||||
|
move_tree_down(node['down'], y)
|
||||||
|
|
||||||
|
# for each child on the very left, spread vertically and adjust subtree y
|
||||||
|
# position accordingly
|
||||||
|
def spread_vertically(node):
|
||||||
|
downnodes = get_down_nodes(node)
|
||||||
|
# process innermost nodes before outer nodes
|
||||||
|
for n in downnodes:
|
||||||
|
if n['right']:
|
||||||
|
spread_vertically(n['right'])
|
||||||
|
if len(downnodes) == 0:
|
||||||
|
return
|
||||||
|
elif len(downnodes) == 1:
|
||||||
|
# arrange them in the center of parent
|
||||||
|
# treat the article height as even and round the gap size to the
|
||||||
|
# next smallest even number
|
||||||
|
gap = (node['height']-roundeven(get_height(downnodes[0]['article'])))/4*2
|
||||||
|
move_tree_down(node, gap)
|
||||||
|
else:
|
||||||
|
# get the sum of all heights of the leftmodes articles as if they
|
||||||
|
# had even heights
|
||||||
|
sumdownnodes = sum([roundeven(get_height(n['article'])) for n in downnodes])
|
||||||
|
# do some fancy math to figure out even gap sizes between
|
||||||
|
# the nodes
|
||||||
|
d, m = divmod((node['height']-sumdownnodes)/2, len(downnodes)-1)
|
||||||
|
gaps = (m)*[(d+1)*2]+((len(downnodes)-1)-m)*[d*2]
|
||||||
|
# iteratively move trees down by vgap except for first row
|
||||||
|
for node, gap in zip(downnodes[1:], gaps):
|
||||||
|
move_tree_down(node, gap)
|
||||||
|
|
||||||
|
# for a given node, return a tuple consisting of a list of nodes that
|
||||||
|
# make out the longest row in horizontal direction and a list of nodes that
|
||||||
|
# start a shorter end
|
||||||
|
def get_max_horiz_nodes(node):
|
||||||
|
if node is None or not node['article']:
|
||||||
|
return [], []
|
||||||
|
elif node['down'] and node['down']['article']:
|
||||||
|
# if the node has an article below, check out the rightbranch
|
||||||
|
rightbranch, sr = get_max_horiz_nodes(node['right'])
|
||||||
|
rightbranch = [node] + rightbranch
|
||||||
|
# as well as the down branch
|
||||||
|
downbranch, sd = get_max_horiz_nodes(node['down'])
|
||||||
|
# get information about the last article in each branch
|
||||||
|
ar = rightbranch[len(rightbranch)-1]['article']
|
||||||
|
ad = downbranch[len(downbranch)-1]['article']
|
||||||
|
# and return as the first tuple entry the branch that stretches the
|
||||||
|
# longest while having as the second tuple entry the nodes that
|
||||||
|
# were dismissed as starting shorter branches
|
||||||
|
if ar['PlacePosition']['X']+get_width(ar)/2 > ad['PlacePosition']['X']+get_width(ad)/2:
|
||||||
|
return rightbranch, sr+[downbranch[0]]
|
||||||
|
else:
|
||||||
|
return downbranch, sd+[rightbranch[0]]
|
||||||
|
else:
|
||||||
|
# if there is no article below, just recursively call itself on the
|
||||||
|
# next node to the right
|
||||||
|
rightbranch, short = get_max_horiz_nodes(node['right'])
|
||||||
|
return [node] + rightbranch, short
|
||||||
|
|
||||||
|
# move a node and the article inside to the right and reduce node width
|
||||||
|
# recursively call for children
|
||||||
|
def move_tree_right(node, x):
|
||||||
|
if not node['article']:
|
||||||
|
return
|
||||||
|
node['article']['PlacePosition']['X'] += x
|
||||||
|
node['x'] += x
|
||||||
|
node['width'] -= x
|
||||||
|
if node['right']:
|
||||||
|
move_tree_right(node['right'], x)
|
||||||
|
if node['down']:
|
||||||
|
move_tree_right(node['down'], x)
|
||||||
|
|
||||||
|
# for each child on the very right, spread horizontally and adjust subtree
|
||||||
|
# x position accordingly
|
||||||
|
def spread_horizontally(node):
|
||||||
|
maxhoriznodes, short = get_max_horiz_nodes(node['right'])
|
||||||
|
maxhoriznodes = [node] + maxhoriznodes
|
||||||
|
if len(maxhoriznodes) == 0:
|
||||||
|
return
|
||||||
|
elif len(maxhoriznodes) == 1:
|
||||||
|
# arrange them in the center of parent
|
||||||
|
# treat article width as even and round the gap size to the next
|
||||||
|
# smallest even number
|
||||||
|
gap = (node['width']-roundeven(get_width(maxhoriznodes[0]['article'])))/4*2
|
||||||
|
maxhoriznodes[0]['article']['PlacePosition']['X'] += gap
|
||||||
|
else:
|
||||||
|
# get the sum of all widths of the articles that make the longest
|
||||||
|
# row of articles as if they had even widths
|
||||||
|
summaxhoriznodes= sum([roundeven(get_width(n['article'])) for n in maxhoriznodes])
|
||||||
|
# do some fancy math to figure out even gap sizes between the nodes
|
||||||
|
d, m = divmod((node['width']-summaxhoriznodes)/2, len(maxhoriznodes)-1)
|
||||||
|
gaps = (m)*[(d+1)*2]+((len(maxhoriznodes)-1)-m)*[d*2]
|
||||||
|
# iteratively move trees right by hgap except for first node
|
||||||
|
for node, gap in zip(maxhoriznodes[1:], gaps):
|
||||||
|
move_tree_right(node, gap)
|
||||||
|
# recursively call for all nodes starting a shorter subtree
|
||||||
|
for node in short:
|
||||||
|
spread_horizontally(node)
|
||||||
|
|
||||||
|
# spread nodes vertically
|
||||||
|
spread_vertically(root)
|
||||||
|
|
||||||
|
# and horizontally
|
||||||
|
for node in get_down_nodes(root):
|
||||||
|
spread_horizontally(node)
|
||||||
|
|
||||||
|
# sanity checks
|
||||||
|
def sanity_check(layer):
|
||||||
|
def intersects(a1, a2):
|
||||||
|
return (a1['x'] < a2['x']+a2['width']
|
||||||
|
and a1['x']+a1['width'] > a2['x']
|
||||||
|
and a1['y'] < a2['y']+a2['height']
|
||||||
|
and a1['y']+a1['height'] > a2['y'])
|
||||||
|
odds = list()
|
||||||
|
overhangs = list()
|
||||||
|
inters = list()
|
||||||
|
for article1 in layer:
|
||||||
|
if (article1['x']%2 != 0
|
||||||
|
or article1['y']%2 != 0):
|
||||||
|
odds.append(article1)
|
||||||
|
if (article1['x'] < 0
|
||||||
|
or article1['y'] < 0
|
||||||
|
or article1['x']+article1['width'] > pwidth
|
||||||
|
or article1['y']+article1['height'] > pheight):
|
||||||
|
overhangs.append(article1)
|
||||||
|
for article2 in layer:
|
||||||
|
if article1 == article2:
|
||||||
|
continue
|
||||||
|
if intersects(article1, article2):
|
||||||
|
inters.append((article1, article2))
|
||||||
|
for odd in odds:
|
||||||
|
print "odd:", odd
|
||||||
|
for overhang in overhangs:
|
||||||
|
print "overhang:", overhang
|
||||||
|
for inter in inters:
|
||||||
|
print "intersect:", inter
|
||||||
|
if len(odds) or len(overhangs) or len(inters):
|
||||||
|
print layer
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# draw layer of articles
|
||||||
|
def draw_layer(filename, layer):
|
||||||
|
scene = svg.Scene(filename, (pwidth, pheight))
|
||||||
|
for a in layer:
|
||||||
|
scene.add(svg.Rectangle((a['x'], a['y']),(a['width'], a['height']),a['color']))
|
||||||
|
scene.write()
|
||||||
|
|
||||||
|
# return all articles in a node tree
|
||||||
|
def find_articles(node):
|
||||||
|
if node is None or not node['article']:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
return [node['article']] + find_articles(node['right']) + find_articles(node['down'])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
abin = generate_bin()
|
||||||
|
pwidth, pheight = 800, 600
|
||||||
|
abin = sorted(abin, key=lambda article: article['width']*article['height'], reverse=True)
|
||||||
|
root, layer, rest = arrange_in_layer(abin, pwidth, pheight)
|
||||||
|
draw_layer('test1', layer)
|
||||||
|
spread_articles(root)
|
||||||
|
layer = find_articles(root)
|
||||||
|
draw_layer('test2', layer)
|
||||||
|
sanity_check(layer)
|
79
bruteforce2.py
Normal file
79
bruteforce2.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import itertools
|
||||||
|
import shutil
|
||||||
|
from util import xmlfiletodict, dicttoxmlfile, get_pallet, get_articles, get_packlist_dict
|
||||||
|
from arrange_spread2 import arrange_in_layer, spread_articles, find_articles
|
||||||
|
import cPickle
|
||||||
|
from binascii import b2a_base64
|
||||||
|
|
||||||
|
def get_layers(bins, pallet, rot_article=False, rot_pallet=False):
|
||||||
|
for abin in bins:
|
||||||
|
bins[abin] = sorted(bins[abin], key=lambda article: article['Article']['Length']*article['Article']['Width'], reverse=True)
|
||||||
|
plength, pwidth = (pallet['Dimensions']['Length'], pallet['Dimensions']['Width'])
|
||||||
|
root, layer, rest = arrange_in_layer(bins[abin], plength, pwidth, rot_article=rot_article)
|
||||||
|
while layer:
|
||||||
|
spread_articles(root)
|
||||||
|
|
||||||
|
occupied_area = 0
|
||||||
|
for article in layer:
|
||||||
|
length, width = article['Article']['Length'], article['Article']['Width']
|
||||||
|
occupied_area += length*width
|
||||||
|
|
||||||
|
# print "layer occupation:", occupied_area/float(plength*pwidth)
|
||||||
|
if occupied_area/float(plength*pwidth) <= 0.7:
|
||||||
|
rot_article, rot_pallet = (yield None, layer)
|
||||||
|
else:
|
||||||
|
rot_article, rot_pallet = (yield layer, None)
|
||||||
|
|
||||||
|
root, layer, rest = arrange_in_layer(rest, plength, pwidth, rot_article=rot_article)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print "usage:", sys.argv[0], "order.xml packlist.xml"
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
orderline = xmlfiletodict(sys.argv[1])
|
||||||
|
pallet = get_pallet(orderline)
|
||||||
|
articles = get_articles(orderline)
|
||||||
|
bins = dict()
|
||||||
|
|
||||||
|
for article in articles:
|
||||||
|
abin = bins.get(article['Article']['Height'])
|
||||||
|
if abin:
|
||||||
|
abin.append(article)
|
||||||
|
else:
|
||||||
|
bins[article['Article']['Height']] = [article]
|
||||||
|
|
||||||
|
scores = list()
|
||||||
|
|
||||||
|
stuff1 = list()
|
||||||
|
|
||||||
|
#for order in itertools.product([True, False], repeat=12):
|
||||||
|
for order in [[True]*12,]:
|
||||||
|
rests = list()
|
||||||
|
layers = list()
|
||||||
|
|
||||||
|
it = get_layers(bins, pallet, order[0], False)
|
||||||
|
layer, rest = it.next()
|
||||||
|
if layer:
|
||||||
|
layers.append(layer)
|
||||||
|
if rest:
|
||||||
|
rests.append(rest)
|
||||||
|
|
||||||
|
fail = True
|
||||||
|
for rot_article in order[1:]:
|
||||||
|
try:
|
||||||
|
layer, rest = it.send((rot_article, False))
|
||||||
|
if layer:
|
||||||
|
layers.append(layer)
|
||||||
|
if rest:
|
||||||
|
rests.append(rest)
|
||||||
|
except StopIteration:
|
||||||
|
fail = False
|
||||||
|
break
|
||||||
|
if fail:
|
||||||
|
raise Exception("finished early")
|
||||||
|
print b2a_base64(cPickle.dumps((layers, rests, pallet))),
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
81
bruteforce3.py
Normal file
81
bruteforce3.py
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import itertools
|
||||||
|
import shutil
|
||||||
|
from util import xmlfiletodict, dicttoxmlfile, get_pallet, get_articles, get_packlist_dict
|
||||||
|
from arrange_spread2 import arrange_in_layer, spread_articles, find_articles
|
||||||
|
import cPickle
|
||||||
|
import marshal
|
||||||
|
from binascii import a2b_base64
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
|
||||||
|
def evaluate_layers_rests(layers, rests, scores, pallet):
|
||||||
|
rest_layers = list()
|
||||||
|
# sort rests by space they cover and move them to the center of the pile
|
||||||
|
# append them to the layer list
|
||||||
|
for rest in sorted(rests, key=lambda rest: sum([article['Article']['Length']*article['Article']['Width'] for article in rest]), reverse=True):
|
||||||
|
plength, pwidth = (pallet['Dimensions']['Length'], pallet['Dimensions']['Width'])
|
||||||
|
root, layer, rest = arrange_in_layer(rest, plength, pwidth)
|
||||||
|
|
||||||
|
com_x = 0
|
||||||
|
com_y = 0
|
||||||
|
for article in layer:
|
||||||
|
com_x += article['PlacePosition']['X']
|
||||||
|
com_y += article['PlacePosition']['Y']
|
||||||
|
com_x, com_y = com_x/len(layer), com_y/len(layer)
|
||||||
|
|
||||||
|
diff_x, diff_y = plength*0.5-com_x, pwidth*0.5-com_y
|
||||||
|
|
||||||
|
for article in layer:
|
||||||
|
article['PlacePosition']['X'] += diff_x
|
||||||
|
article['PlacePosition']['Y'] += diff_y
|
||||||
|
|
||||||
|
rest_layers.append(layer)
|
||||||
|
|
||||||
|
for permut_layers in itertools.permutations(layers):
|
||||||
|
pack_sequence = 1
|
||||||
|
pack_height = 0
|
||||||
|
articles_to_pack = list()
|
||||||
|
|
||||||
|
for layer in list(permut_layers)+rest_layers:
|
||||||
|
pack_height += layer[0]['Article']['Height']
|
||||||
|
#if pack_height > pallet['Dimensions']['MaxLoadHeight']:
|
||||||
|
# break
|
||||||
|
for article in layer:
|
||||||
|
article['PackSequence'] = pack_sequence
|
||||||
|
article['PlacePosition']['Z'] = pack_height
|
||||||
|
articles_to_pack.append(article)
|
||||||
|
pack_sequence += 1
|
||||||
|
|
||||||
|
packlist = get_packlist_dict(pallet, articles_to_pack)
|
||||||
|
|
||||||
|
_, tmp = tempfile.mkstemp()
|
||||||
|
dicttoxmlfile(packlist, tmp)
|
||||||
|
|
||||||
|
# ugly, ugly, ugly, ugly hack - dont copy this...
|
||||||
|
score = float(subprocess.check_output("../palletandtruckviewer-3.0/palletViewer -o "
|
||||||
|
+sys.argv[1]+" -p "+tmp
|
||||||
|
+" -s ../icra2011TestFiles/scoreAsPlannedConfig1.xml --headless | grep Score", shell=True).split(' ')[1].strip())
|
||||||
|
scores.append(score)
|
||||||
|
if score > max(scores+[0]):
|
||||||
|
shutil.move(tmp, sys.argv[2])
|
||||||
|
else:
|
||||||
|
os.remove(tmp)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
scores = list()
|
||||||
|
for arg in sys.argv[3:]:
|
||||||
|
layers, rests, pallet = cPickle.loads(a2b_base64(arg))
|
||||||
|
evaluate_layers_rests(layers, rests, scores, pallet)
|
||||||
|
|
||||||
|
print max(scores)
|
||||||
|
#print "max:", max(scores)
|
||||||
|
#print "min:", min(scores)
|
||||||
|
#mean = sum(scores)/len(scores)
|
||||||
|
#print "mean:", mean
|
||||||
|
#from math import sqrt
|
||||||
|
#print "stddev:", sqrt(sum([(x-mean)**2 for x in scores])/len(scores))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
42
svg.py
Normal file
42
svg.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Scene:
|
||||||
|
def __init__(self, name, size):
|
||||||
|
self.name = name
|
||||||
|
self.items = []
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
def add(self, item):
|
||||||
|
self.items.append(item)
|
||||||
|
|
||||||
|
def svgstr(self):
|
||||||
|
svgstr = "<?xml version=\"1.0\"?>\n"
|
||||||
|
svgstr += "<svg width=\"%d\" height=\"%d\">\n"%self.size
|
||||||
|
svgstr += " <g style=\"fill-opacity:1.0; stroke:black; stroke-width:1;\">\n"
|
||||||
|
for item in self.items:
|
||||||
|
svgstr += item.svgstr()
|
||||||
|
svgstr += " </g>\n</svg>\n"
|
||||||
|
return svgstr
|
||||||
|
|
||||||
|
def write(self, filename=None):
|
||||||
|
if not filename:
|
||||||
|
filename = self.name + ".svg"
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
f.write(self.svgstr())
|
||||||
|
|
||||||
|
class Rectangle:
|
||||||
|
def __init__(self, pos, size, color):
|
||||||
|
self.pos = pos
|
||||||
|
self.size = size
|
||||||
|
self.color = color
|
||||||
|
|
||||||
|
def svgstr(self):
|
||||||
|
svgstr = " <rect x=\"%d\" y=\"%d\" "%self.pos
|
||||||
|
svgstr += "width=\"%d\" height=\"%d\" "%self.size
|
||||||
|
svgstr += "style=\"fill:#%02x%02x%02x;\"/>\n"%self.color
|
||||||
|
return svgstr
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
scene = Scene('test', (400, 400))
|
||||||
|
scene.add(Rectangle((0,0),(100,100),(255,0,0)))
|
||||||
|
scene.write()
|
197
util.py
Normal file
197
util.py
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
|
def xmltodict(element):
|
||||||
|
if not isinstance(element, ElementTree.Element):
|
||||||
|
raise ValueError("must pass xml.etree.ElementTree.Element object")
|
||||||
|
|
||||||
|
def xmltodict_handler(parent_element):
|
||||||
|
result = dict()
|
||||||
|
for element in parent_element:
|
||||||
|
if len(element):
|
||||||
|
obj = xmltodict_handler(element)
|
||||||
|
else:
|
||||||
|
obj = element.text
|
||||||
|
|
||||||
|
if result.get(element.tag):
|
||||||
|
if hasattr(result[element.tag], "append"):
|
||||||
|
result[element.tag].append(obj)
|
||||||
|
else:
|
||||||
|
result[element.tag] = [result[element.tag], obj]
|
||||||
|
else:
|
||||||
|
result[element.tag] = obj
|
||||||
|
return result
|
||||||
|
|
||||||
|
return {element.tag: xmltodict_handler(element)}
|
||||||
|
|
||||||
|
|
||||||
|
def dicttoxml(element):
|
||||||
|
if not isinstance(element, dict):
|
||||||
|
raise ValueError("must pass dict type")
|
||||||
|
if len(element) != 1:
|
||||||
|
raise ValueError("dict must have exactly one root key")
|
||||||
|
|
||||||
|
def dicttoxml_handler(result, key, value):
|
||||||
|
if isinstance(value, list):
|
||||||
|
for e in value:
|
||||||
|
dicttoxml_handler(result, key, e)
|
||||||
|
elif isinstance(value, basestring):
|
||||||
|
elem = ElementTree.Element(key)
|
||||||
|
elem.text = value
|
||||||
|
result.append(elem)
|
||||||
|
elif isinstance(value, int) or isinstance(value, float):
|
||||||
|
elem = ElementTree.Element(key)
|
||||||
|
elem.text = str(value)
|
||||||
|
result.append(elem)
|
||||||
|
elif value is None:
|
||||||
|
result.append(ElementTree.Element(key))
|
||||||
|
else:
|
||||||
|
res = ElementTree.Element(key)
|
||||||
|
for k, v in value.items():
|
||||||
|
dicttoxml_handler(res, k, v)
|
||||||
|
result.append(res)
|
||||||
|
|
||||||
|
result = ElementTree.Element(element.keys()[0])
|
||||||
|
for key, value in element[element.keys()[0]].items():
|
||||||
|
dicttoxml_handler(result, key, value)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def xmlfiletodict(filename):
|
||||||
|
return xmltodict(ElementTree.parse(filename).getroot())
|
||||||
|
|
||||||
|
def dicttoxmlfile(element, filename):
|
||||||
|
ElementTree.ElementTree(dicttoxml(element)).write(filename)
|
||||||
|
|
||||||
|
def xmlstringtodict(xmlstring):
|
||||||
|
return xmltodict(ElementTree.fromstring(xmlstring).getroot())
|
||||||
|
|
||||||
|
def dicttoxmlstring(element):
|
||||||
|
return ElementTree.tostring(dicttoxml(element))
|
||||||
|
|
||||||
|
def get_pallet(orderline):
|
||||||
|
p = orderline['Message']['PalletInit']['Pallets']['Pallet']
|
||||||
|
return {
|
||||||
|
'PalletNumber': int(p['PalletNumber']),
|
||||||
|
'Description': p['Description'],
|
||||||
|
'Dimensions': {
|
||||||
|
'MaxLoadHeight': int(p['Dimensions']['MaxLoadHeight']),
|
||||||
|
'MaxLoadWeight': int(p['Dimensions']['MaxLoadWeight']),
|
||||||
|
'Length': int(p['Dimensions']['Length']),
|
||||||
|
'Width': int(p['Dimensions']['Width']),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_articles(orderline):
|
||||||
|
articles = list()
|
||||||
|
for o in orderline['Message']['Order']['OrderLines']['OrderLine']:
|
||||||
|
for barcode in o['Barcodes']['Barcode']:
|
||||||
|
articles.append(
|
||||||
|
{'ApproachPoint1': {'X': 0, 'Y': 0, 'Z': 0},
|
||||||
|
'ApproachPoint2': {'X': 0, 'Y': 0, 'Z': 0},
|
||||||
|
'ApproachPoint3': {'X': 0, 'Y': 0, 'Z': 0},
|
||||||
|
'Article': { 'Description': o['Article']['Description'],
|
||||||
|
'ID': int(o['Article']['ID']),
|
||||||
|
'Type': int(o['Article']['Type']), # currently only Type=1 is allowed
|
||||||
|
'Family': int(o['Article']['Family']),
|
||||||
|
'Length': int(o['Article']['Length']), # should be larger than width
|
||||||
|
'Width': int(o['Article']['Width']),
|
||||||
|
'Height': int(o['Article']['Height']),
|
||||||
|
'Weight': int(o['Article']['Weight']) # in grams
|
||||||
|
},
|
||||||
|
'Barcode': barcode,
|
||||||
|
'Orientation': 1, # 1: 0 deg the long side parallel to X direction
|
||||||
|
# 2: 90 deg the long side parallel to Y direction
|
||||||
|
'PackSequence': 0,
|
||||||
|
'PlacePosition': {'X': 0, 'Y': 0, 'Z': 0}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return articles
|
||||||
|
|
||||||
|
def get_packlist_dict(pallet, articles):
|
||||||
|
pallet['Packages'] = {'Package': articles}
|
||||||
|
return {'Response':
|
||||||
|
{'PackList':
|
||||||
|
{'OrderID': '1',
|
||||||
|
'PackPallets':
|
||||||
|
{'PackPallet': pallet }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
tree = ElementTree.parse('../icra2011TestFiles/GT/gt_d1r1.wpacklist.xml')
|
||||||
|
#tree = ElementTree.parse('../icra2011TestFiles/palDay1R1Order.xml')
|
||||||
|
root = tree.getroot()
|
||||||
|
xmldict = xmltodict(root)
|
||||||
|
|
||||||
|
from pprint import pprint
|
||||||
|
#for package in xmldict['PackList']['PackPallets']['PackPallet']['Packages']['Package']:
|
||||||
|
# pprint(package)
|
||||||
|
|
||||||
|
|
||||||
|
root = dicttoxml(xmldict)
|
||||||
|
|
||||||
|
xmldict = xmltodict(root)
|
||||||
|
pprint(xmldict)
|
||||||
|
|
||||||
|
packages = [{'ApproachPoint1': {'X': '0',
|
||||||
|
'Y': '0',
|
||||||
|
'Z': '0'},
|
||||||
|
'ApproachPoint2': {'X': '0',
|
||||||
|
'Y': '0',
|
||||||
|
'Z': '0'},
|
||||||
|
'ApproachPoint3': {'X': '0',
|
||||||
|
'Y': '0',
|
||||||
|
'Z': '0'},
|
||||||
|
'Article': {'Description': '3',
|
||||||
|
'Family': '0',
|
||||||
|
'Height': '41',
|
||||||
|
'ID': '3',
|
||||||
|
'Length': '44',
|
||||||
|
'Type': '0',
|
||||||
|
'Weight': '500',
|
||||||
|
'Width': '132'},
|
||||||
|
'Barcode': None,
|
||||||
|
'Orientation': '1',
|
||||||
|
'PackSequence': '1',
|
||||||
|
'PlacePosition': {'X': '286',
|
||||||
|
'Y': '330',
|
||||||
|
'Z': '41'},
|
||||||
|
'StackHeightBefore': '0'},
|
||||||
|
{'ApproachPoint1': {'X': '0',
|
||||||
|
'Y': '0',
|
||||||
|
'Z': '0'},
|
||||||
|
'ApproachPoint2': {'X': '0',
|
||||||
|
'Y': '0',
|
||||||
|
'Z': '0'},
|
||||||
|
'ApproachPoint3': {'X': '0',
|
||||||
|
'Y': '0',
|
||||||
|
'Z': '0'},
|
||||||
|
'Article': {'Description': '4',
|
||||||
|
'Family': '0',
|
||||||
|
'Height': '41',
|
||||||
|
'ID': '4',
|
||||||
|
'Length': '66',
|
||||||
|
'Type': '0',
|
||||||
|
'Weight': '550',
|
||||||
|
'Width': '132'},
|
||||||
|
'Barcode': None,
|
||||||
|
'Orientation': '1',
|
||||||
|
'PackSequence': '54',
|
||||||
|
'PlacePosition': {'X': '33',
|
||||||
|
'Y': '66',
|
||||||
|
'Z': '164'},
|
||||||
|
'StackHeightBefore': '0'}]
|
||||||
|
|
||||||
|
packlist = {'Response': {'PackList': {'OrderID': '1',
|
||||||
|
'PackPallets': {'PackPallet': {'BruttoWeight': '63000',
|
||||||
|
'Description': None,
|
||||||
|
'Dimensions': {'Length': '308',
|
||||||
|
'MaxLoadHeight': '406',
|
||||||
|
'MaxLoadWeight': '99999',
|
||||||
|
'Width': '396'},
|
||||||
|
'NumberofPackages': '54',
|
||||||
|
'Overhang': {'Length': '0',
|
||||||
|
'Width': '0'},
|
||||||
|
'Packages': {'Package': packages},
|
||||||
|
'PalletNumber': '1'}}}}}
|
||||||
|
|
Loading…
Reference in a new issue