kopia lustrzana https://github.com/evil-mad/EggBot
Initial checkin
git-svn-id: https://eggbotcode.googlecode.com/svn/trunk@167 72233254-1b6c-9e9c-5072-401df62706fbpull/47/head
rodzic
cf8cdae71e
commit
2e109eb206
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<_name>Twist</_name>
|
||||
<id>twist.contributed.eggbot</id>
|
||||
<dependency type="extension">org.inkscape.output.svg.inkscape</dependency>
|
||||
<dependency type="executable" location="extensions">eggbot_twist.py</dependency>
|
||||
<dependency type="executable" location="extensions">inkex.py</dependency>
|
||||
<dependency type="executable" location="extensions">simplepath.py</dependency>
|
||||
<dependency type="executable" location="extensions">simpletransform.py</dependency>
|
||||
<dependency type="executable" location="extensions">simplestyle.py</dependency>
|
||||
<dependency type="executable" location="extensions">cubicsuperpath.py</dependency>
|
||||
<dependency type="executable" location="extensions">cspsubdiv.py</dependency>
|
||||
<dependency type="executable" location="extensions">bezmisc.py</dependency>
|
||||
|
||||
<_param name="Header" type="description" xml:space="preserve">
|
||||
Iteratively twist and self-inscribe
|
||||
a polygon within itself.
|
||||
|
||||
The number of twists is how many
|
||||
iterations to perform.
|
||||
|
||||
The step ratio is the fractional
|
||||
distance along an edge to move each
|
||||
vertex.
|
||||
|
||||
***
|
||||
This extension is intended as an
|
||||
example of how to write an Inkscape
|
||||
extension for use with the Eggbot.
|
||||
See the eggbot_twist.py file in the
|
||||
Inkscape extensions directory for
|
||||
this extensions' Python code.
|
||||
***
|
||||
</_param>
|
||||
|
||||
<param name="nSteps" type="int" min="1" max="100"
|
||||
_gui-text=" Number of twists">8</param>
|
||||
<param name="fRatio" type="float" min="-10" max="10" precision="5"
|
||||
_gui-text=" Step ratio">0.15</param>
|
||||
|
||||
<effect needs-live-preview="false">
|
||||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu _name="EggBot Contributed"/>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
<command reldir="extensions" interpreter="python">eggbot_twist.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
||||
|
|
@ -0,0 +1,536 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# twist.py -- Primarily a simple example of writing an Inkscape extension
|
||||
# which manipulates objects in a drawing.
|
||||
#
|
||||
# For a polygon with vertices V[0], V[1], V[2], ..., V[n-1] iteratively
|
||||
# move each vertex V[i] by a constant factor 0 < s < 1.0 along the edge
|
||||
# between V[i] and V[i+1 modulo n] for 0 <= i <= n-1.
|
||||
#
|
||||
# This extension operates on every selected closed path, or, if no paths
|
||||
# are selected, then every closed path in the document. Since the "twisting"
|
||||
# effect only concerns itself with individual paths, no effort is made to
|
||||
# worry about the transforms applied to the paths. That is, it is not
|
||||
# necessary to worry about tracking SVG transforms as all the work can be
|
||||
# done using the untransformed coordinates of each path.
|
||||
|
||||
# Written by Daniel C. Newman ( dan dot newman at mtbaldy dot us )
|
||||
# 19 October 2010
|
||||
|
||||
# This program 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 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
import inkex
|
||||
import simplepath
|
||||
import simplestyle
|
||||
import simpletransform
|
||||
import cubicsuperpath
|
||||
import cspsubdiv
|
||||
import bezmisc
|
||||
|
||||
def subdivideCubicPath( sp, flat, i=1 ):
|
||||
|
||||
'''
|
||||
[ Lifted from eggbot.py with impunity ]
|
||||
|
||||
Break up a bezier curve into smaller curves, each of which
|
||||
is approximately a straight line within a given tolerance
|
||||
(the "smoothness" defined by [flat]).
|
||||
|
||||
This is a modified version of cspsubdiv.cspsubdiv(): rewritten
|
||||
because recursion-depth errors on complicated line segments
|
||||
could occur with cspsubdiv.cspsubdiv().
|
||||
'''
|
||||
|
||||
while True:
|
||||
while True:
|
||||
if i >= len( sp ):
|
||||
return
|
||||
|
||||
p0 = sp[i - 1][1]
|
||||
p1 = sp[i - 1][2]
|
||||
p2 = sp[i][0]
|
||||
p3 = sp[i][1]
|
||||
|
||||
b = ( p0, p1, p2, p3 )
|
||||
|
||||
if cspsubdiv.maxdist( b ) > flat:
|
||||
break
|
||||
|
||||
i += 1
|
||||
|
||||
one, two = bezmisc.beziersplitatt( b, 0.5 )
|
||||
sp[i - 1][2] = one[1]
|
||||
sp[i][0] = two[2]
|
||||
p = [one[2], one[3], two[1]]
|
||||
sp[i:1] = [p]
|
||||
|
||||
def distanceSquared( P1, P2 ):
|
||||
|
||||
'''
|
||||
Pythagorean distance formula WITHOUT the square root. Since
|
||||
we just want to know if the distance is less than some fixed
|
||||
fudge factor, we can just square the fudge factor once and run
|
||||
with it rather than compute square roots over and over.
|
||||
'''
|
||||
|
||||
dx = P2[0] - P1[0]
|
||||
dy = P2[1] - P1[1]
|
||||
|
||||
return ( dx * dx + dy * dy )
|
||||
|
||||
class Twist( inkex.Effect ):
|
||||
|
||||
def __init__( self ):
|
||||
|
||||
inkex.Effect.__init__( self )
|
||||
self.OptionParser.add_option(
|
||||
"--nSteps", action="store", type="int",
|
||||
dest="nSteps", default=8,
|
||||
help="Number of iterations to take" )
|
||||
self.OptionParser.add_option(
|
||||
"--fRatio", action="store", type="float",
|
||||
dest="fRatio", default=float( 0.2 ),
|
||||
help="Some ratio" )
|
||||
|
||||
'''
|
||||
Store each path in an associative array (dictionary) indexed
|
||||
by the lxml.etree pointer for the SVG document element
|
||||
containing the path. Looking up the path in the dictionary
|
||||
yields a list of lists. Each of these lists is a subpath
|
||||
# of the path. E.g., for the SVG path
|
||||
|
||||
<path d="M 10,10 l 0,5 l 5,0 l 0,-5 Z M 30,30 L 30,60"/>
|
||||
|
||||
we'd have two subpaths which will be reduced to absolute
|
||||
coordinates.
|
||||
|
||||
subpath_1 = [ [10, 10], [10, 15], [15, 15], [15, 10], [10,10] ]
|
||||
subpath_2 = [ [30, 30], [30, 60] ]
|
||||
self.paths[<node pointer>] = [ subpath_1, subpath_2 ]
|
||||
|
||||
All of the paths and their subpaths could be drawn as follows:
|
||||
|
||||
for path in self.paths:
|
||||
for subpath in self.paths[path]:
|
||||
first = True
|
||||
for vertex in subpath:
|
||||
if first:
|
||||
moveto( vertex[0], vertex[1] )
|
||||
first = False
|
||||
else:
|
||||
lineto( vertex[0], vertex[1] )
|
||||
|
||||
NOTE: drawing all the paths like the above would not in general
|
||||
give the correct rendering of the document UNLESS path transforms
|
||||
were also tracked and applied.
|
||||
'''
|
||||
|
||||
self.paths = {}
|
||||
|
||||
def addPathVertices( self, path, node=None, transform=None ):
|
||||
|
||||
'''
|
||||
Decompose the path data from an SVG element into individual
|
||||
subpaths, each subpath consisting of absolute move to and line
|
||||
to coordinates. Place these coordinates into a list of polygon
|
||||
vertices.
|
||||
'''
|
||||
|
||||
if ( not path ) or ( len( path ) == 0 ):
|
||||
# Nothing to do
|
||||
return
|
||||
|
||||
# parsePath() may raise an exception. This is okay
|
||||
sp = simplepath.parsePath( path )
|
||||
if ( not sp ) or ( len( sp ) == 0 ):
|
||||
# Path must have been devoid of any real content
|
||||
return
|
||||
|
||||
# Get a cubic super path
|
||||
p = cubicsuperpath.CubicSuperPath( sp )
|
||||
if ( not p ) or ( len( p ) == 0 ):
|
||||
# Probably never happens, but...
|
||||
return
|
||||
|
||||
#if transform:
|
||||
# simpletransform.applyTransformToPath( transform, p )
|
||||
|
||||
# Now traverse the cubic super path
|
||||
subpath_list = []
|
||||
subpath_vertices = []
|
||||
for sp in p:
|
||||
if len( subpath_vertices ):
|
||||
# There's a prior subpath: see if it is closed and should be saved
|
||||
if distanceSquared( subpath_vertices[0], subpath_vertices[-1] ) < 1:
|
||||
# Keep the prior subpath: it appears to be a closed path
|
||||
subpath_list.append( subpath_vertices )
|
||||
subpath_vertices = []
|
||||
subdivideCubicPath( sp, float( 0.2 ) )
|
||||
for csp in sp:
|
||||
# Add this vertex to the list of vetices
|
||||
subpath_vertices.append( csp[1] )
|
||||
|
||||
# Handle final subpath
|
||||
if len( subpath_vertices ):
|
||||
if distanceSquared( subpath_vertices[0], subpath_vertices[-1] ) < 1:
|
||||
# Path appears to be closed so let's keep it
|
||||
subpath_list.append( subpath_vertices )
|
||||
|
||||
# Empty path?
|
||||
if len( subpath_list ) == 0:
|
||||
return
|
||||
|
||||
# Store the list of subpaths in a dictionary keyed off of the path's node pointer
|
||||
self.paths[node] = subpath_list
|
||||
|
||||
def recursivelyTraverseSvg( self, aNodeList,
|
||||
matCurrent=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
|
||||
parent_visibility='visible' ):
|
||||
|
||||
'''
|
||||
[ This too is largely lifted from eggbot.py ]
|
||||
|
||||
Recursively walk the SVG document, building polygon vertex lists
|
||||
for each graphical element we support.
|
||||
|
||||
Rendered SVG elements:
|
||||
<circle>, <ellipse>, <line>, <path>, <polygon>, <polyline>, <rect>
|
||||
|
||||
Supported SVG elements:
|
||||
<group>, <use>
|
||||
|
||||
Ignored SVG elements:
|
||||
<defs>, <eggbot>, <metadata>, <namedview>, <pattern>,
|
||||
processing directives
|
||||
|
||||
All other SVG elements trigger an error (including <text>)
|
||||
'''
|
||||
|
||||
for node in aNodeList:
|
||||
|
||||
# Ignore invisible nodes
|
||||
v = node.get( 'visibility', parent_visibility )
|
||||
if v == 'inherit':
|
||||
v = parent_visibility
|
||||
if v == 'hidden' or v == 'collapse':
|
||||
pass
|
||||
|
||||
# First apply the current matrix transform to this node's tranform
|
||||
matNew = simpletransform.composeTransform( matCurrent,
|
||||
simpletransform.parseTransform( node.get( "transform" ) ) )
|
||||
|
||||
if node.tag == inkex.addNS( 'g', 'svg' ) or node.tag == 'g':
|
||||
|
||||
self.recursivelyTraverseSvg( node, matNew, parent_visibility=v )
|
||||
|
||||
elif node.tag == inkex.addNS( 'use', 'svg' ) or node.tag == 'use':
|
||||
|
||||
# A <use> element refers to another SVG element via an xlink:href="#blah"
|
||||
# attribute. We will handle the element by doing an XPath search through
|
||||
# the document, looking for the element with the matching id="blah"
|
||||
# attribute. We then recursively process that element after applying
|
||||
# any necessary (x,y) translation.
|
||||
#
|
||||
# Notes:
|
||||
# 1. We ignore the height and width attributes as they do not apply to
|
||||
# path-like elements, and
|
||||
# 2. Even if the use element has visibility="hidden", SVG still calls
|
||||
# for processing the referenced element. The referenced element is
|
||||
# hidden only if its visibility is "inherit" or "hidden".
|
||||
|
||||
refid = node.get( inkex.addNS( 'href', 'xlink' ) )
|
||||
if not refid:
|
||||
pass
|
||||
|
||||
# [1:] to ignore leading '#' in reference
|
||||
path = '//*[@id="%s"]' % refid[1:]
|
||||
refnode = node.xpath( path )
|
||||
if refnode:
|
||||
x = float( node.get( 'x', '0' ) )
|
||||
y = float( node.get( 'y', '0' ) )
|
||||
tran = node.get( 'transform' )
|
||||
if tran:
|
||||
tran += ' translate(%f,%f)' % ( x, y )
|
||||
else:
|
||||
tran = 'translate(%f,%f)' % ( x, y )
|
||||
matNew2 = simpletransform.composeTransform( matNew,
|
||||
simpletransform.parseTransform( tran ) )
|
||||
v = node.get( 'visibility', v )
|
||||
self.recursivelyTraverseSvg( refnode, matNew2,
|
||||
parent_visibility=v )
|
||||
|
||||
elif node.tag == inkex.addNS( 'path', 'svg' ):
|
||||
|
||||
path_data = node.get( 'd')
|
||||
if path_data:
|
||||
self.addPathVertices( path_data, node, matNew )
|
||||
|
||||
elif node.tag == inkex.addNS( 'rect', 'svg' ) or node.tag == 'rect':
|
||||
|
||||
# Manually transform
|
||||
#
|
||||
# <rect x="X" y="Y" width="W" height="H"/>
|
||||
#
|
||||
# into
|
||||
#
|
||||
# <path d="MX,Y lW,0 l0,H l-W,0 z"/>
|
||||
#
|
||||
# I.e., explicitly draw three sides of the rectangle and the
|
||||
# fourth side implicitly
|
||||
|
||||
# Create a path with the outline of the rectangle
|
||||
x = float( node.get( 'x' ) )
|
||||
y = float( node.get( 'y' ) )
|
||||
if ( not x ) or ( not y ):
|
||||
pass
|
||||
w = float( node.get( 'width', '0' ) )
|
||||
h = float( node.get( 'height', '0' ) )
|
||||
a = []
|
||||
a.append( ['M ', [x, y]] )
|
||||
a.append( [' l ', [w, 0]] )
|
||||
a.append( [' l ', [0, h]] )
|
||||
a.append( [' l ', [-w, 0]] )
|
||||
a.append( [' Z', []] )
|
||||
self.addPathVertices( simplepath.formatPath( a ), node, matNew )
|
||||
|
||||
elif node.tag == inkex.addNS( 'line', 'svg' ) or node.tag == 'line':
|
||||
|
||||
# Convert
|
||||
#
|
||||
# <line x1="X1" y1="Y1" x2="X2" y2="Y2/>
|
||||
#
|
||||
# to
|
||||
#
|
||||
# <path d="MX1,Y1 LX2,Y2"/>
|
||||
|
||||
x1 = float( node.get( 'x1' ) )
|
||||
y1 = float( node.get( 'y1' ) )
|
||||
x2 = float( node.get( 'x2' ) )
|
||||
y2 = float( node.get( 'y2' ) )
|
||||
if ( not x1 ) or ( not y1 ) or ( not x2 ) or ( not y2 ):
|
||||
pass
|
||||
a = []
|
||||
a.append( ['M ', [x1, y1]] )
|
||||
a.append( [' L ', [x2, y2]] )
|
||||
self.addPathVertices( simplepath.formatPath( a ), node, matNew )
|
||||
|
||||
elif node.tag == inkex.addNS( 'polyline', 'svg' ) or node.tag == 'polyline':
|
||||
|
||||
# Convert
|
||||
#
|
||||
# <polyline points="x1,y1 x2,y2 x3,y3 [...]"/>
|
||||
#
|
||||
# to
|
||||
#
|
||||
# <path d="Mx1,y1 Lx2,y2 Lx3,y3 [...]"/>
|
||||
#
|
||||
# Note: we ignore polylines with no points
|
||||
|
||||
pl = node.get( 'points', '' ).strip()
|
||||
if pl == '':
|
||||
pass
|
||||
|
||||
pa = pl.split()
|
||||
d = "".join( ["M " + pa[i] if i == 0 else " L " + pa[i] for i in range( 0, len( pa ) )] )
|
||||
self.addPathVertices( d, node, matNew )
|
||||
|
||||
elif node.tag == inkex.addNS( 'polygon', 'svg' ) or node.tag == 'polygon':
|
||||
|
||||
# Convert
|
||||
#
|
||||
# <polygon points="x1,y1 x2,y2 x3,y3 [...]"/>
|
||||
#
|
||||
# to
|
||||
#
|
||||
# <path d="Mx1,y1 Lx2,y2 Lx3,y3 [...] Z"/>
|
||||
#
|
||||
# Note: we ignore polygons with no points
|
||||
|
||||
pl = node.get( 'points', '' ).strip()
|
||||
if pl == '':
|
||||
pass
|
||||
|
||||
pa = pl.split()
|
||||
d = "".join( ["M " + pa[i] if i == 0 else " L " + pa[i] for i in range( 0, len( pa ) )] )
|
||||
d += " Z"
|
||||
self.addPathVertices( d, node, matNew )
|
||||
|
||||
elif node.tag == inkex.addNS( 'ellipse', 'svg' ) or \
|
||||
node.tag == 'ellipse' or \
|
||||
node.tag == inkex.addNS( 'circle', 'svg' ) or \
|
||||
node.tag == 'circle':
|
||||
|
||||
# Convert circles and ellipses to a path with two 180 degree arcs.
|
||||
# In general (an ellipse), we convert
|
||||
#
|
||||
# <ellipse rx="RX" ry="RY" cx="X" cy="Y"/>
|
||||
#
|
||||
# to
|
||||
#
|
||||
# <path d="MX1,CY A RX,RY 0 1 0 X2,CY A RX,RY 0 1 0 X1,CY"/>
|
||||
#
|
||||
# where
|
||||
#
|
||||
# X1 = CX - RX
|
||||
# X2 = CX + RX
|
||||
#
|
||||
# Note: ellipses or circles with a radius attribute of value 0 are ignored
|
||||
|
||||
if node.tag == inkex.addNS( 'ellipse', 'svg' ) or node.tag == 'ellipse':
|
||||
rx = float( node.get( 'rx', '0' ) )
|
||||
ry = float( node.get( 'ry', '0' ) )
|
||||
else:
|
||||
rx = float( node.get( 'r', '0' ) )
|
||||
ry = rx
|
||||
if rx == 0 or ry == 0:
|
||||
pass
|
||||
|
||||
cx = float( node.get( 'cx', '0' ) )
|
||||
cy = float( node.get( 'cy', '0' ) )
|
||||
x1 = cx - rx
|
||||
x2 = cx + rx
|
||||
d = 'M %f,%f ' % ( x1, cy ) + \
|
||||
'A %f,%f ' % ( rx, ry ) + \
|
||||
'0 1 0 %f,%f ' % ( x2, cy ) + \
|
||||
'A %f,%f ' % ( rx, ry ) + \
|
||||
'0 1 0 %f,%f' % ( x1, cy )
|
||||
self.addPathVertices( d, node, matNew )
|
||||
|
||||
elif node.tag == inkex.addNS( 'pattern', 'svg' ) or node.tag == 'pattern':
|
||||
|
||||
pass
|
||||
|
||||
elif node.tag == inkex.addNS( 'metadata', 'svg' ) or node.tag == 'metadata':
|
||||
|
||||
pass
|
||||
|
||||
elif node.tag == inkex.addNS( 'defs', 'svg' ) or node.tag == 'defs':
|
||||
|
||||
pass
|
||||
|
||||
elif node.tag == inkex.addNS( 'namedview', 'sodipodi' ) or node.tag == 'namedview':
|
||||
|
||||
pass
|
||||
|
||||
elif node.tag == inkex.addNS( 'eggbot', 'svg' ) or node.tag == 'eggbot':
|
||||
|
||||
pass
|
||||
|
||||
elif node.tag == inkex.addNS( 'text', 'svg' ) or node.tag == 'text':
|
||||
|
||||
inkex.errormsg( 'Warning: unable to draw text, please convert it to a path first.' )
|
||||
|
||||
pass
|
||||
|
||||
elif not isinstance( node.tag, basestring ):
|
||||
|
||||
pass
|
||||
|
||||
else:
|
||||
|
||||
inkex.errormsg( 'Warning: unable to draw object <%s>, please convert it to a path first.' % node.tag )
|
||||
pass
|
||||
|
||||
def joinWithNode ( self, node, path, makeGroup=False ):
|
||||
|
||||
'''
|
||||
Generate a SVG <path> element containing the path data "path".
|
||||
Then put this new <path> element into a <group> with the supplied
|
||||
node. This means making a new <group> element and making the
|
||||
node a child of it with the new <path> as a sibling.
|
||||
'''
|
||||
|
||||
if ( not path ) or ( len( path ) == 0 ):
|
||||
return
|
||||
|
||||
if makeGroup:
|
||||
# Make a new SVG <group> element whose parent is the parent of node
|
||||
parent = node.getparent()
|
||||
if not parent:
|
||||
parent = self.document.getroot()
|
||||
g = inkex.etree.SubElement( parent, inkex.addNS( 'g', 'svg' ) )
|
||||
|
||||
# Move node to be a child of this new <g> element
|
||||
g.append( node )
|
||||
|
||||
# Promote the node's transform to the new parent group
|
||||
# This way, it will apply to the original paths and the
|
||||
# "twisted" paths
|
||||
transform = node.get( 'transform' )
|
||||
if transform:
|
||||
g.set( 'transform', transform )
|
||||
del node.attrib['transform']
|
||||
else:
|
||||
g = node.getparent()
|
||||
|
||||
# Now make a <path> element which contains the hatches & is a child
|
||||
# of the new <g> element
|
||||
style = { 'stroke': '#000000', 'fill': 'none', 'stroke-width': '1' }
|
||||
line_attribs = { 'style':simplestyle.formatStyle( style ), 'd': path }
|
||||
inkex.etree.SubElement( g, inkex.addNS( 'path', 'svg' ), line_attribs )
|
||||
|
||||
def twist( self, ratio ):
|
||||
|
||||
if not self.paths:
|
||||
return
|
||||
|
||||
# Now iterate over all of the polygons
|
||||
for path in self.paths:
|
||||
for subpath in self.paths[path]:
|
||||
for i in range( 0, len( subpath ) - 1 ):
|
||||
subpath[i][0] = subpath[i][0] + ratio * ( subpath[i+1][0] - subpath[i][0] )
|
||||
subpath[i][1] = subpath[i][1] + ratio * ( subpath[i+1][1] - subpath[i][1] )
|
||||
subpath[-1] = subpath[0]
|
||||
|
||||
def draw( self, makeGroup=False ):
|
||||
|
||||
'''
|
||||
Draw the edges of the current list of vertices
|
||||
'''
|
||||
|
||||
if not self.paths:
|
||||
return
|
||||
|
||||
# Now iterate over all of the polygons
|
||||
for path in self.paths:
|
||||
for subpath in self.paths[path]:
|
||||
pdata = ''
|
||||
for vertex in subpath:
|
||||
if pdata == '':
|
||||
pdata = 'M %f,%f' % ( vertex[0], vertex[1] )
|
||||
else:
|
||||
pdata += ' L %f,%f' % ( vertex[0], vertex[1] )
|
||||
self.joinWithNode( path, pdata, makeGroup )
|
||||
|
||||
def effect( self ):
|
||||
|
||||
# Build a list of the vertices for the document's graphical elements
|
||||
if self.options.ids:
|
||||
# Traverse the selected objects
|
||||
for id in self.options.ids:
|
||||
self.recursivelyTraverseSvg( [self.selected[id]] )
|
||||
else:
|
||||
# Traverse the entire document
|
||||
self.recursivelyTraverseSvg( self.document.getroot() )
|
||||
|
||||
# Now iterate over the vertices N times
|
||||
for n in range( 0, self.options.nSteps ):
|
||||
self.twist( self.options.fRatio )
|
||||
self.draw( n == 0 )
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
e = Twist()
|
||||
e.affect()
|
||||
Ładowanie…
Reference in New Issue