132 lines
4.6 KiB
Python
132 lines
4.6 KiB
Python
#!/usr/bin/env python
|
|
# Copyright 2014 Jo Pol
|
|
# 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 3 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, see http://www.gnu.org/licenses/.
|
|
#########################################################################
|
|
|
|
|
|
import inkex, cubicsuperpath, bezmisc
|
|
|
|
__author__ = 'Jo Pol'
|
|
__credits__ = ['Jo Pol','Mark Shafer']
|
|
__license__ = 'GPLv3'
|
|
|
|
class ThreadStyle(inkex.Effect):
|
|
"""
|
|
Apply stroke style of selected path to connected paths
|
|
"""
|
|
def __init__(self):
|
|
"""
|
|
Constructor.
|
|
"""
|
|
# Call the base class constructor.
|
|
inkex.Effect.__init__(self)
|
|
self.OptionParser.add_option('-t', '--tolerance', action='store', type='float', dest='tolerance', default=0.05, help='tolerance (max. distance between segments)')
|
|
self.OptionParser.add_option('-u', '--units', action = 'store', type = 'string', dest = 'units', default = 'mm', help = 'The units the measurements are in')
|
|
self.OptionParser.add_option('-w', '--width', action='store', type='float', dest='width', default='1', help='thread width')
|
|
self.OptionParser.add_option('-c', '--color', action='store', type='string', dest='color', default='#FF9999', help='thread color')
|
|
|
|
def getUnittouu(self, param):
|
|
" compatibility between inkscape 0.48 and 0.91 "
|
|
try:
|
|
return inkex.unittouu(param)
|
|
except AttributeError:
|
|
return self.unittouu(param)
|
|
|
|
def startPoint(self, cubicSuperPath):
|
|
"""
|
|
returns the first point of a CubicSuperPath
|
|
"""
|
|
return cubicSuperPath[0][0][0]
|
|
|
|
def endPoint(self, csp):
|
|
"""
|
|
returns the last point of a CubicSuperPath
|
|
"""
|
|
return csp[0][len(csp[0]) - 1][len(csp[0][1]) - 1]
|
|
|
|
def isBezier(self, item):
|
|
return item.tag == inkex.addNS('path', 'svg') and item.get(inkex.addNS('connector-curvature', 'inkscape'))
|
|
|
|
def findCandidatesForStyleChange(self, skip):
|
|
"""
|
|
collect the document items that are a Bezier curve
|
|
"""
|
|
self.candidates = []
|
|
for item in self.document.getiterator():
|
|
if self.isBezier(item) and item != skip:
|
|
csp = cubicsuperpath.parsePath(item.get('d'))
|
|
s = self.startPoint(csp)
|
|
e = self.endPoint(csp)
|
|
self.candidates.append({'s':s, 'e':e, 'i':item})
|
|
|
|
def applyStyle(self, item):
|
|
"""
|
|
Change the style of the item and remove it form the candidates
|
|
"""
|
|
item['i'].attrib['style'] = self.style
|
|
self.candidates.remove(item)
|
|
|
|
def applyToAdjacent(self, point):
|
|
while point != None:
|
|
p = (point[0], point[1])
|
|
next = None
|
|
for item in self.candidates:
|
|
if bezmisc.pointdistance(p, (item['s'][0], item['s'][1])) < self.options.tolerance:
|
|
self.applyStyle(item)
|
|
next = item['e']
|
|
break
|
|
elif bezmisc.pointdistance(p, (item['e'][0], item['e'][1])) < self.options.tolerance:
|
|
self.applyStyle(item)
|
|
next = item['s']
|
|
break
|
|
point = next
|
|
|
|
def getColorString(self, longColor, verbose=False):
|
|
""" Convert the long into a #RRGGBB color value
|
|
- verbose=true pops up value for us in defaults
|
|
conversion back is A + B*256^1 + G*256^2 + R*256^3
|
|
"""
|
|
if verbose: inkex.debug("%s ="%(longColor))
|
|
longColor = long(longColor)
|
|
if longColor <0: longColor = long(longColor) & 0xFFFFFFFF
|
|
hexColor = hex(longColor)[2:-3]
|
|
hexColor = '#' + hexColor.rjust(6, '0').upper()
|
|
if verbose: inkex.debug(" %s for color default value"%(hexColor))
|
|
return hexColor
|
|
|
|
def effect(self):
|
|
"""
|
|
Effect behaviour.
|
|
Overrides base class' method and draws something.
|
|
"""
|
|
self.options.color = self.getColorString(self.options.color)
|
|
conversion = self.getUnittouu("1" + self.options.units)
|
|
if len(self.selected) != 1:
|
|
inkex.debug('no object selected, or more than one selected')
|
|
return
|
|
selected = self.selected.values()[0]
|
|
if not self.isBezier(selected):
|
|
inkex.debug('selected element is not a Bezier curve')
|
|
return
|
|
self.findCandidatesForStyleChange(selected)
|
|
self.style = 'fill:none;stroke:{1};stroke-width:{0}'.format(self.options.width*conversion, self.options.color)
|
|
csp = cubicsuperpath.parsePath(selected.get('d'))
|
|
self.selected.values()[0].attrib['style'] = self.style
|
|
self.applyToAdjacent(self.startPoint(csp))
|
|
self.applyToAdjacent(self.endPoint(csp))
|
|
|
|
# Create effect instance and apply it.
|
|
if __name__ == '__main__':
|
|
ThreadStyle().affect()
|