Skip to content

Commit

Permalink
Merge pull request #1 from vmario89/master
Browse files Browse the repository at this point in the history
Update for InkScape 1.0
  • Loading branch information
Neon22 committed Jul 31, 2020
2 parents 3b1759b + 14d76d6 commit 391a810
Showing 1 changed file with 49 additions and 115 deletions.
164 changes: 49 additions & 115 deletions zoetrope.py
@@ -1,5 +1,4 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
'''
Zoetrope maker.
- prints disk of given diameter and number of images around the outside.
Expand All @@ -13,13 +12,13 @@
'''

import inkex # Required
import simplestyle # will be needed here for styles support
from lxml import etree

from math import cos, sin, radians, pi

__version__ = '0.2'

inkex.localize()
inkex.localization.localize

### Helper functions
def point_on_circle(radius, angle):
Expand All @@ -30,101 +29,37 @@ def point_on_circle(radius, angle):

def draw_SVG_circle(parent, r, cx, cy, name, style):
" structre an SVG circle entity under parent "
circ_attribs = {'style': simplestyle.formatStyle(style),
circ_attribs = {'style': str(inkex.Style(style)),
'cx': str(cx), 'cy': str(cy),
'r': str(r),
inkex.addNS('label','inkscape'): name}
circle = inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs )

circle = etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs )

Black = '#000000'


class Zoetrope(inkex.Effect):

def __init__(self):
" define how the options are mapped from the inx file "
inkex.Effect.__init__(self) # initialize the super class

# Define your list of parameters defined in the .inx file
self.OptionParser.add_option("-u", "--units",
action="store", type="string",
dest="units", default='mm',
help="Units this dialog is using")

self.OptionParser.add_option("-d", "--diameter",
action="store", type="float",
dest="diameter", default=1.0,
help="Diameter of disk")

self.OptionParser.add_option("-n", "--divisions",
action="store", type="int",
dest="divisions", default=24,
help="Number of divisions")

self.OptionParser.add_option("-i", "--height",
action="store", type="float",
dest="height", default=1.0,
help="Image height")

self.OptionParser.add_option("-t", "--trigger",
action="store", type="inkbool",
dest="trigger", default=False,
help="Trigger")

self.OptionParser.add_option("-q", "--triggerradius",
action="store", type="float",
dest="triggerradius", default=1.0,
help="Height of trigger line")

self.OptionParser.add_option("-e", "--thick",
action="store", type="float",
dest="thick", default=1.0,
help="Thickness of trigger line")

self.OptionParser.add_option("-r", "--ratio",
action="store", type="float",
dest="ratio", default=0.5,
help="Ratio of trigger pulse")

self.OptionParser.add_option("-p", "--phase",
action="store", type="float",
dest="phase", default=0,
help="Delay of trigger pulse")

self.OptionParser.add_option("-w", "--stroke_width",
action="store", type="float",
dest="stroke_width", default=0.1,
help="Line thickness")

self.OptionParser.add_option("-m", "--template",
action="store", type="inkbool",
dest="template", default=False,
help="Show Image Distortion template")

self.OptionParser.add_option("-k", "--dpi",
action="store", type="int",
dest="dpi", default=300,
help="To calculate useful image size")

# here so we can have tabs - but we do not use it directly - else error
self.OptionParser.add_option("", "--active-tab",
action="store", type="string",
dest="active_tab", default='',
help="Active tab. Not used now.")

def getUnittouu(self, param):
" for 0.48 and 0.91 compatibility "
try:
return inkex.unittouu(param)
except AttributeError:
return self.unittouu(param)

self.arg_parser.add_argument("-u", "--units", default='mm', help="Units this dialog is using")
self.arg_parser.add_argument("-d", "--diameter", type=float, default=1.0, help="Diameter of disk")
self.arg_parser.add_argument("-n", "--divisions", type=int, default=24, help="Number of divisions")
self.arg_parser.add_argument("-i", "--height", type=float, default=1.0, help="Image height")
self.arg_parser.add_argument("-t", "--trigger", type=inkex.Boolean, default=False, help="Trigger")
self.arg_parser.add_argument("-q", "--triggerradius", type=float, default=1.0, help="Height of trigger line")
self.arg_parser.add_argument("-e", "--thick", type=float, default=1.0, help="Thickness of trigger line")
self.arg_parser.add_argument("-r", "--ratio", type=float, default=0.5, help="Ratio of trigger pulse")
self.arg_parser.add_argument("-p", "--phase", type=float, default=0, help="Delay of trigger pulse")
self.arg_parser.add_argument("-w", "--stroke_width", type=float, default=0.1, help="Line thickness")
self.arg_parser.add_argument("-m", "--template", type=inkex.Boolean, default=False, help="Show Image Distortion template")
self.arg_parser.add_argument("-k", "--dpi", type=int, default=300, help="To calculate useful image size")
self.arg_parser.add_argument("--active-tab", default='', help="Active tab. Not used now.")

def calc_unit_factor(self):
""" return the scale factor for all dimension conversions.
- Everything in inkscape is expected to be in 90dpi pixel units
"""
unit_factor = self.getUnittouu(str(1.0) + self.options.units)
unit_factor = self.svg.unittouu(str(1.0) + self.options.units)
return unit_factor

def polar_to_cartesian(self, cx, cy, radius, angle):
Expand Down Expand Up @@ -177,28 +112,28 @@ def effect(self):
cross = diameter/50

# This finds center of current view in inkscape
t = 'translate(%s,%s)' % (self.view_center[0], self.view_center[1] )
t = 'translate(%s,%s)' % (self.svg.namedview.center[0], self.svg.namedview.center[1] )
# Make a nice useful name
g_attribs = { inkex.addNS('label','inkscape'): 'Zoetrope',
'transform': t,
'info':'N: '+str(divisions)+';' }
# add the group to the document's current layer
topgroup = inkex.etree.SubElement(self.current_layer, 'g', g_attribs )
topgroup = etree.SubElement(self.svg.get_current_layer(), 'g', g_attribs )
# Group for pulse triggers
g_attr = { inkex.addNS('label','inkscape'): 'Pulse track'}
pulsegroup = inkex.etree.SubElement(topgroup, 'g', g_attr )
pulsegroup = etree.SubElement(topgroup, 'g', g_attr )
# Group for Labels
t = 'translate(%s,%s)' % (0, diameter/1.9 )
g_attr = { inkex.addNS('label','inkscape'): 'Label', 'transform': t }
labelgroup = inkex.etree.SubElement(topgroup, 'g', g_attr )
labelgroup = etree.SubElement(topgroup, 'g', g_attr )

# Center cross
line_style = { 'stroke': Black, 'fill': 'none', 'stroke-width': path_stroke_width }
fill_style = { 'stroke': 'none', 'fill': Black, 'stroke-width': 'none' }
d = 'M {0},0 L {1},0 M 0,{0} L 0,{1}'.format(-cross,cross)
cross_attribs = { inkex.addNS('label','inkscape'): 'Center cross',
'style': simplestyle.formatStyle(line_style), 'd': d }
cross_path = inkex.etree.SubElement(topgroup, inkex.addNS('path','svg'), cross_attribs )
'style': str(inkex.Style(line_style)), 'd': d }
cross_path = etree.SubElement(topgroup, inkex.addNS('path','svg'), cross_attribs )

# Main Disk
draw_SVG_circle(topgroup, diameter/2, 0, 0, 'outer_ring', line_style)
Expand All @@ -216,23 +151,23 @@ def effect(self):
endpt = point_on_circle(diameter/2, angle_radians*i)
path = "M%s,%s L%s,%s"%(startpt[0], startpt[1], endpt[0], endpt[1])
radial_attr = {inkex.addNS('label','inkscape'): 'radial',
'style': simplestyle.formatStyle(line_style), 'd': path }
inkex.etree.SubElement(topgroup, inkex.addNS('path','svg'), radial_attr )
'style': str(inkex.Style(line_style)), 'd': path }
etree.SubElement(topgroup, inkex.addNS('path','svg'), radial_attr )
# second part of radial line (and trigger ring) if needed
if self.options.trigger:
# radial lines
startpt = point_on_circle(triggerradius + thick, angle_radians*i)
endpt = point_on_circle(diameter/2, angle_radians*i)
path = "M%s,%s L%s,%s"%(startpt[0], startpt[1], endpt[0], endpt[1])
radial_attr = {inkex.addNS('label','inkscape'): 'radial',
'style': simplestyle.formatStyle(line_style), 'd': path }
inkex.etree.SubElement(topgroup, inkex.addNS('path','svg'), radial_attr )
'style': str(inkex.Style(line_style)), 'd': path }
etree.SubElement(topgroup, inkex.addNS('path','svg'), radial_attr )
# add the arcs # CCW rotation
arc_offset = angle*i - (angle-trigger_angle)*self.options.phase
t = 'rotate(%s)' % (arc_offset)
attribs = { inkex.addNS('label','inkscape'): 'trigger',
'style': simplestyle.formatStyle(fill_style), 'd': arc_path , 'transform': t,}
inkex.etree.SubElement(pulsegroup, inkex.addNS('path','svg'), attribs )
'style': str(inkex.Style(fill_style)), 'd': arc_path , 'transform': t,}
etree.SubElement(pulsegroup, inkex.addNS('path','svg'), attribs )
# Add animation of bouncing ball
# Add pale grid on each image so can draw directly on template

Expand All @@ -248,57 +183,56 @@ def effect(self):
'text-anchor': 'middle',
'text-align': 'center',
'fill': Black }
text_atts = {'style':simplestyle.formatStyle(text_style),
text_atts = {'style':str(inkex.Style(text_style)),
'x': '0', 'y': '0' }
text = inkex.etree.SubElement(labelgroup, 'text', text_atts)
text = etree.SubElement(labelgroup, 'text', text_atts)
text.text = "Zoetrope"
text_atts = {'style':simplestyle.formatStyle(text_style),
text_atts = {'style':str(inkex.Style(text_style)),
'x': '0', 'y': str(font_height*1.2) }
text = inkex.etree.SubElement(labelgroup, 'text', text_atts)
text = etree.SubElement(labelgroup, 'text', text_atts)
text.text = "Diameter = %4.2f%s. Divisions = %d" % (self.options.diameter, self.options.units, divisions)
text_atts = {'style':simplestyle.formatStyle(text_style),
text_atts = {'style':str(inkex.Style(text_style)),
'x': '0', 'y': str(font_height*2.4) }
if self.options.trigger:
text = inkex.etree.SubElement(labelgroup, 'text', text_atts)
text = etree.SubElement(labelgroup, 'text', text_atts)
text.text = "Pulse Duty = %4.2f, Phase = %4.2f" % (self.options.ratio, self.options.phase)

# Distortion pattern
if self.options.template:
# Group for Labels
t = 'translate(%s,%s)' % (0, -image_height-font_height*5 )
g_attr = { inkex.addNS('label','inkscape'): 'Template', 'transform': t }
templategroup = inkex.etree.SubElement(topgroup, 'g', g_attr )
templategroup = etree.SubElement(topgroup, 'g', g_attr )
# Draw template
arc_path = self.build_trigger_arc(angle, diameter/2, diameter/2-image_height)
t = 'rotate(%s)' % (-90+angle/2)
attribs = { inkex.addNS('label','inkscape'): 'distorted image',
'style': simplestyle.formatStyle(line_style), 'd': arc_path , 'transform': t}
image = inkex.etree.SubElement(templategroup, inkex.addNS('path','svg'), attribs )
'style': str(inkex.Style(line_style)), 'd': arc_path , 'transform': t}
image = etree.SubElement(templategroup, inkex.addNS('path','svg'), attribs )
# Draw Image info
image_width = pi*diameter/divisions
ystart = -diameter/2.0 + image_height
image_ratio = image_width / image_height
text_atts = {'style':simplestyle.formatStyle(text_style),
text_atts = {'style':str(inkex.Style(text_style)),
'x': '0', 'y': str(ystart + font_height*2) }
text = inkex.etree.SubElement(templategroup, 'text', text_atts)
text = etree.SubElement(templategroup, 'text', text_atts)
text.text = "Aspect ratio=1:%4.2f" % (image_ratio)
# template rect
attr = {'x':str(-image_width*1.8), 'y':str(-diameter/2),
'width':str(image_width),
'height':str(image_height),
'style':simplestyle.formatStyle(line_style)}
template_sq = inkex.etree.SubElement(templategroup, 'rect', attr)
'style':str(inkex.Style(line_style))}
template_sq = etree.SubElement(templategroup, 'rect', attr)
# suggested sizes
# image_height is in 90dpi pixels
dpi_factor = self.getUnittouu('1in')/float(self.options.dpi)
dpi_factor = self.svg.unittouu('1in')/float(self.options.dpi)
h = int(image_height / float(dpi_factor))
w = int(h*image_ratio)
text_atts = {'style':simplestyle.formatStyle(text_style),
text_atts = {'style':str(inkex.Style(text_style)),
'x': '0', 'y': str(ystart + font_height*3.2) }
text = inkex.etree.SubElement(templategroup, 'text', text_atts)
text = etree.SubElement(templategroup, 'text', text_atts)
text.text = "At %d dpi. Image = %d x %d pixels" % (self.options.dpi, w, h)

if __name__ == '__main__':
e = Zoetrope()
e.affect()

e.run()

0 comments on commit 391a810

Please sign in to comment.