dimension.py revision cc4432ab3a75143cee1c437e6e323ffc05c76f21
#!/usr/bin/env python
'''
dimension.py
An Inkscape effect for adding CAD style dimensions to selected objects
in a drawing.
It uses the selection's bounding box, so if the bounding box has empty
space in the x- or y-direction (such as with some stars) the results
will look strange. Strokes might also overlap the edge of the
bounding box.
The dimension arrows aren't measured: use the "Visualize Path/Measure
Path" effect to add measurements.
This code contains snippets from existing effects in the Inkscape
extensions library, and marker data from markers.svg.
Copyright (C) 2007 Peter Lewerin, peter.lewerin@tele2.se
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
'''
# standard library
import sys
try:
from subprocess import Popen, PIPE
bsubprocess = True
except:
bsubprocess = False
# local library
import inkex
import pathmodifier
from simpletransform import *
inkex.localize()
class Dimension(pathmodifier.PathModifier):
def __init__(self):
inkex.Effect.__init__(self)
self.OptionParser.add_option("-x", "--xoffset",
action="store", type="float",
dest="xoffset", default=100.0,
help="x offset of the vertical dimension arrow")
self.OptionParser.add_option("-y", "--yoffset",
action="store", type="float",
dest="yoffset", default=100.0,
help="y offset of the horizontal dimension arrow")
self.OptionParser.add_option("-t", "--type",
action="store", type="string",
dest="type", default="geometric",
help="Bounding box type")
def addMarker(self, name, rotate):
defs = self.xpathSingle('/svg:svg//svg:defs')
if defs == None:
defs = inkex.etree.SubElement(self.document.getroot(),inkex.addNS('defs','svg'))
marker = inkex.etree.SubElement(defs ,inkex.addNS('marker','svg'))
marker.set('id', name)
marker.set('orient', 'auto')
marker.set('refX', '0.0')
marker.set('refY', '0.0')
marker.set('style', 'overflow:visible')
marker.set(inkex.addNS('stockid','inkscape'), name)
arrow = inkex.etree.Element("path")
arrow.set('d', 'M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z ')
if rotate:
arrow.set('transform', 'scale(0.8) rotate(180) translate(12.5,0)')
else:
arrow.set('transform', 'scale(0.8) translate(12.5,0)')
arrow.set('style', 'fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none')
marker.append(arrow)
def dimHLine(self, y, xlat):
line = inkex.etree.Element("path")
x1 = self.bbox[0] - xlat[0] * self.xoffset
x2 = self.bbox[1]
y = y - xlat[1] * self.yoffset
line.set('d', 'M %f %f H %f' % (x1, y, x2))
return line
def dimVLine(self, x, xlat):
line = inkex.etree.Element("path")
x = x - xlat[0] * self.xoffset
y1 = self.bbox[2] - xlat[1] * self.yoffset
y2 = self.bbox[3]
line.set('d', 'M %f %f V %f' % (x, y1, y2))
return line
def effect(self):
scale = self.unittouu('1px') # convert to document units
self.xoffset = scale*self.options.xoffset
self.yoffset = scale*self.options.yoffset
# query inkscape about the bounding box
if len(self.options.ids) == 0:
inkex.errormsg(_("Please select an object."))
exit()
if self.options.type == "geometric":
self.bbox = computeBBox(self.selected.values())
else:
q = {'x':0,'y':0,'width':0,'height':0}
file = self.args[-1]
id = self.options.ids[0]
for query in q.keys():
if bsubprocess:
p = Popen('inkscape --query-%s --query-id=%s "%s"' % (query,id,file), shell=True, stdout=PIPE, stderr=PIPE)
rc = p.wait()
q[query] = scale*float(p.stdout.read())
err = p.stderr.read()
else:
f,err = os.popen3('inkscape --query-%s --query-id=%s "%s"' % (query,id,file))[1:]
q[query] = scale*float(f.read())
f.close()
err.close()
self.bbox = (q['x'], q['x']+q['width'], q['y'], q['y']+q['height'])
# Avoid ugly failure on rects and texts.
try:
testing_the_water = self.bbox[0]
except TypeError:
inkex.errormsg(_('Unable to process this object. Try changing it into a path first.'))
exit()
layer = self.current_layer
self.addMarker('Arrow1Lstart', False)
self.addMarker('Arrow1Lend', True)
group = inkex.etree.SubElement(layer, 'g')
# group = inkex.etree.Element("g")
group.set('fill', 'none')
group.set('stroke', 'black')
line = self.dimHLine(self.bbox[2], [0, 1])
line.set('marker-start', 'url(#Arrow1Lstart)')
line.set('marker-end', 'url(#Arrow1Lend)')
line.set('stroke-width', str(scale))
group.append(line)
line = self.dimVLine(self.bbox[0], [0, 2])
line.set('stroke-width', str(0.5*scale))
group.append(line)
line = self.dimVLine(self.bbox[1], [0, 2])
line.set('stroke-width', str(0.5*scale))
group.append(line)
line = self.dimVLine(self.bbox[0], [1, 0])
line.set('marker-start', 'url(#Arrow1Lstart)')
line.set('marker-end', 'url(#Arrow1Lend)')
line.set('stroke-width', str(scale))
group.append(line)
line = self.dimHLine(self.bbox[2], [2, 0])
line.set('stroke-width', str(0.5*scale))
group.append(line)
line = self.dimHLine(self.bbox[3], [2, 0])
line.set('stroke-width', str(0.5*scale))
group.append(line)
for id, node in self.selected.iteritems():
group.append(node)
layer.append(group)
if __name__ == '__main__':
e = Dimension()
e.affect()
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99