kopia lustrzana https://github.com/evil-mad/EggBot
Code cleanup: uniform indents (tabs)
git-svn-id: https://eggbotcode.googlecode.com/svn/trunk@92 72233254-1b6c-9e9c-5072-401df62706fbpull/47/head
rodzic
2410291d96
commit
d968d29a9d
Plik diff jest za duży
Load Diff
|
@ -30,137 +30,136 @@ import string
|
|||
import math
|
||||
import random
|
||||
|
||||
def dist(x0, y0, x1, y1):
|
||||
return math.sqrt( (x1 - x0)**2 + (y1 - y0)**2 )
|
||||
def dist( x0, y0, x1, y1 ):
|
||||
return math.sqrt( ( x1 - x0 ) ** 2 + ( y1 - y0 ) ** 2 )
|
||||
|
||||
# Takes a list of (id, (startX, startY, endX, endY)), and finds the best ordering.
|
||||
# Doesn't handle anything fancy, like reversing the ordering, but it's useful for now.
|
||||
# Returns a list of JUST THE IDs, in a better order, as well as the original and optimized
|
||||
# "air distance" which is just the distance traveled in the air. Perhaps we want to make
|
||||
# these comparison distances into something more relevant such as degrees traveled?
|
||||
def find_ordering_naive(objlist):
|
||||
def find_ordering_naive( objlist ):
|
||||
|
||||
# let's figure out the default in-air length, so we know how much we improved
|
||||
air_length_default = 0
|
||||
try:
|
||||
oldx = objlist[0][1][2]
|
||||
oldy = objlist[0][1][3]
|
||||
except:
|
||||
inkex.errormsg(gettext.gettext(str(objlist[0])))
|
||||
sys.exit(1)
|
||||
for id, coords in objlist[1:]:
|
||||
air_length_default += dist(oldx, oldy, coords[0], coords[1])
|
||||
oldx = coords[2]
|
||||
oldy = coords[3]
|
||||
#fid.write("Default air distance: %d\n" % air_length_default)
|
||||
# let's figure out the default in-air length, so we know how much we improved
|
||||
air_length_default = 0
|
||||
try:
|
||||
oldx = objlist[0][1][2]
|
||||
oldy = objlist[0][1][3]
|
||||
except:
|
||||
inkex.errormsg( gettext.gettext( str( objlist[0] ) ) )
|
||||
sys.exit( 1 )
|
||||
for id, coords in objlist[1:]:
|
||||
air_length_default += dist( oldx, oldy, coords[0], coords[1] )
|
||||
oldx = coords[2]
|
||||
oldy = coords[3]
|
||||
#fid.write("Default air distance: %d\n" % air_length_default)
|
||||
|
||||
air_length_ordered = 0
|
||||
# for now, start with a random one:
|
||||
sort_list = []
|
||||
random_index = random.randint(0, len(objlist) - 1)
|
||||
sort_list.append(objlist[random_index])
|
||||
objlist.remove(objlist[random_index])
|
||||
# for now, do this in the most naive way:
|
||||
# for the previous end point, iterate over each remaining path and pick the closest starting point
|
||||
while len(objlist) > 0:
|
||||
min_distance = 100000000 # TODO put something else here better?
|
||||
for path in objlist:
|
||||
# instead of having a prevX, prevY, we just look at the last item in sort_list
|
||||
this_distance = dist(sort_list[-1][1][2], sort_list[-1][1][3], path[1][0], path[1][1])
|
||||
# this is such a common thing to do, you'd think there would be a name for it...
|
||||
if this_distance < min_distance:
|
||||
min_distance = this_distance
|
||||
min_path = path
|
||||
air_length_ordered += min_distance
|
||||
sort_list.append(min_path)
|
||||
objlist.remove(min_path)
|
||||
air_length_ordered = 0
|
||||
# for now, start with a random one:
|
||||
sort_list = []
|
||||
random_index = random.randint( 0, len( objlist ) - 1 )
|
||||
sort_list.append( objlist[random_index] )
|
||||
objlist.remove( objlist[random_index] )
|
||||
# for now, do this in the most naive way:
|
||||
# for the previous end point, iterate over each remaining path and pick the closest starting point
|
||||
while len( objlist ) > 0:
|
||||
min_distance = 100000000 # TODO put something else here better?
|
||||
for path in objlist:
|
||||
# instead of having a prevX, prevY, we just look at the last item in sort_list
|
||||
this_distance = dist( sort_list[-1][1][2], sort_list[-1][1][3], path[1][0], path[1][1] )
|
||||
# this is such a common thing to do, you'd think there would be a name for it...
|
||||
if this_distance < min_distance:
|
||||
min_distance = this_distance
|
||||
min_path = path
|
||||
air_length_ordered += min_distance
|
||||
sort_list.append( min_path )
|
||||
objlist.remove( min_path )
|
||||
|
||||
#fid.write("optimized air distance: %d\n" % air_length_ordered)
|
||||
#fid.write("optimized air distance: %d\n" % air_length_ordered)
|
||||
|
||||
# remove the extraneous info from the list order
|
||||
sort_order = [id for id, coords in sort_list]
|
||||
return sort_order, air_length_default, air_length_ordered
|
||||
# remove the extraneous info from the list order
|
||||
sort_order = [id for id, coords in sort_list]
|
||||
return sort_order, air_length_default, air_length_ordered
|
||||
|
||||
# not used currently, but can be used to apply a translation matrix to an (x, y) pair
|
||||
# I'm sure there is a better way to do this using simpletransform or it's ilk
|
||||
def conv(x, y, trans_matrix=None):
|
||||
if trans_matrix:
|
||||
xt = trans_matrix[0][0]*x + trans_matrix[0][1]*y + trans_matrix[0][2]
|
||||
yt = trans_matrix[1][0]*x + trans_matrix[1][1]*y + trans_matrix[1][2]
|
||||
return xt, yt
|
||||
else:
|
||||
return x, y
|
||||
def conv( x, y, trans_matrix=None ):
|
||||
if trans_matrix:
|
||||
xt = trans_matrix[0][0] * x + trans_matrix[0][1] * y + trans_matrix[0][2]
|
||||
yt = trans_matrix[1][0] * x + trans_matrix[1][1] * y + trans_matrix[1][2]
|
||||
return xt, yt
|
||||
else:
|
||||
return x, y
|
||||
|
||||
class EggBotReorderPaths(inkex.Effect):
|
||||
def __init__(self):
|
||||
inkex.Effect.__init__(self)
|
||||
self.OptionParser.add_option('-r', '--reverse', action='store', type="inkbool",
|
||||
dest="reverse", default=True, help="Enable 'reverse path direction' optimizations")
|
||||
self.OptionParser.add_option('-w', '--wrap', action='store', type="inkbool",
|
||||
dest="wrap", default=True, help="Enable 'wrap egg axis' optimizations")
|
||||
class EggBotReorderPaths( inkex.Effect ):
|
||||
def __init__( self ):
|
||||
inkex.Effect.__init__( self )
|
||||
self.OptionParser.add_option( '-r', '--reverse', action='store', type="inkbool",
|
||||
dest="reverse", default=True, help="Enable 'reverse path direction' optimizations" )
|
||||
self.OptionParser.add_option( '-w', '--wrap', action='store', type="inkbool",
|
||||
dest="wrap", default=True, help="Enable 'wrap egg axis' optimizations" )
|
||||
|
||||
|
||||
# Given a node, return the start and end points
|
||||
def get_start_end(self, node, transform):
|
||||
d = node.get('d')
|
||||
sp = simplepath.parsePath(d)
|
||||
# simplepath converts coordinates to absolute and cleans them up, but
|
||||
# these are still some big assumptions here, are they always valid? TODO
|
||||
startX = sp[0][1][0]
|
||||
startY = sp[0][1][1]
|
||||
if sp[-1][0] == 'Z':
|
||||
# go back to start
|
||||
endX = startX
|
||||
endY = startY
|
||||
else:
|
||||
endX = sp[-1][1][-2]
|
||||
endY = sp[-1][1][-1]
|
||||
# Given a node, return the start and end points
|
||||
def get_start_end( self, node, transform ):
|
||||
d = node.get( 'd' )
|
||||
sp = simplepath.parsePath( d )
|
||||
# simplepath converts coordinates to absolute and cleans them up, but
|
||||
# these are still some big assumptions here, are they always valid? TODO
|
||||
startX = sp[0][1][0]
|
||||
startY = sp[0][1][1]
|
||||
if sp[-1][0] == 'Z':
|
||||
# go back to start
|
||||
endX = startX
|
||||
endY = startY
|
||||
else:
|
||||
endX = sp[-1][1][-2]
|
||||
endY = sp[-1][1][-1]
|
||||
|
||||
sx, sy = conv(startX, startY, transform)
|
||||
ex, ey = conv(endX, endY, transform)
|
||||
return (sx, sy, ex, ey)
|
||||
sx, sy = conv( startX, startY, transform )
|
||||
ex, ey = conv( endX, endY, transform )
|
||||
return ( sx, sy, ex, ey )
|
||||
|
||||
|
||||
# This is the main entry point
|
||||
def effect(self):
|
||||
# based partially on the restack.py extension
|
||||
if len(self.selected) > 0:
|
||||
svg = self.document.getroot()
|
||||
# TODO check for non-path elements?
|
||||
# TODO it seems like the order of selection is not consistent
|
||||
# This is the main entry point
|
||||
def effect( self ):
|
||||
# based partially on the restack.py extension
|
||||
if len( self.selected ) > 0:
|
||||
svg = self.document.getroot()
|
||||
# TODO check for non-path elements?
|
||||
# TODO it seems like the order of selection is not consistent
|
||||
|
||||
#fid = open("/home/matthew/debug.txt", "w")
|
||||
#fid = open("/home/matthew/debug.txt", "w")
|
||||
|
||||
# for each selected item - TODO make this be all objects, everywhere
|
||||
# I can think of two options:
|
||||
# 1. Iterate over all paths in root, then iterate over all layers, and their paths
|
||||
# 2. Some magic with xpath? (would this limit us to specific node types?)
|
||||
objlist = []
|
||||
for id, node in self.selected.iteritems():
|
||||
transform = node.get('transform')
|
||||
if transform:
|
||||
transform = simpletransform.parseTransform(transform)
|
||||
# for each selected item - TODO make this be all objects, everywhere
|
||||
# I can think of two options:
|
||||
# 1. Iterate over all paths in root, then iterate over all layers, and their paths
|
||||
# 2. Some magic with xpath? (would this limit us to specific node types?)
|
||||
objlist = []
|
||||
for id, node in self.selected.iteritems():
|
||||
transform = node.get( 'transform' )
|
||||
if transform:
|
||||
transform = simpletransform.parseTransform( transform )
|
||||
|
||||
item = (id, self.get_start_end(node, transform))
|
||||
objlist.append(item)
|
||||
|
||||
# sort / order the objects
|
||||
sort_order, air_distance_default, air_distance_ordered = find_ordering_naive(objlist)
|
||||
item = ( id, self.get_start_end( node, transform ) )
|
||||
objlist.append( item )
|
||||
|
||||
for id in sort_order:
|
||||
# There's some good magic here, that you can use an
|
||||
# object id to index into self.selected. Brilliant!
|
||||
self.current_layer.append(self.selected[id])
|
||||
# sort / order the objects
|
||||
sort_order, air_distance_default, air_distance_ordered = find_ordering_naive( objlist )
|
||||
|
||||
for id in sort_order:
|
||||
# There's some good magic here, that you can use an
|
||||
# object id to index into self.selected. Brilliant!
|
||||
self.current_layer.append( self.selected[id] )
|
||||
|
||||
#fid.close()
|
||||
|
||||
if air_distance_default > 0 : #don't divide by zero. :P
|
||||
improvement_pct = 100 * ( ( air_distance_default - air_distance_ordered ) / ( air_distance_default ) )
|
||||
inkex.errormsg( gettext.gettext( "Okay, selected paths have been reordered and optimized for quicker Eggbot plotting.\n\nOriginal air-distance: %d\nOptimized air-distance: %d\nDistance reduced by: %1.2d%%\n\nHave a nice day!" % ( air_distance_default, air_distance_ordered, improvement_pct ) ) )
|
||||
else:
|
||||
inkex.errormsg( gettext.gettext( "doh-- need to have multiple distinct paths selected!" ) )
|
||||
|
||||
#fid.close()
|
||||
|
||||
if air_distance_default > 0 : #don't divide by zero. :P
|
||||
improvement_pct = 100 * ((air_distance_default - air_distance_ordered) / (air_distance_default))
|
||||
inkex.errormsg(gettext.gettext("Okay, selected paths have been reordered and optimized for quicker Eggbot plotting.\n\nOriginal air-distance: %d\nOptimized air-distance: %d\nDistance reduced by: %1.2d%%\n\nHave a nice day!" % (air_distance_default, air_distance_ordered, improvement_pct)))
|
||||
else:
|
||||
inkex.errormsg(gettext.gettext("doh-- need to have multiple distinct paths selected!"))
|
||||
|
||||
|
||||
e = EggBotReorderPaths()
|
||||
e.affect()
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue