home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Inkscape / Inkscape-0.48.2-1-win32.exe / share / extensions / measure.py < prev    next >
Text File  |  2011-07-08  |  9KB  |  202 lines

  1. #!/usr/bin/env python 
  2. '''
  3. This extension module can measure arbitrary path and object length
  4. It adds a text to the selected path containing the length in a
  5. given unit.
  6.  
  7. Copyright (C) 2010 Alvin Penner
  8. Copyright (C) 2006 Georg Wiora
  9. Copyright (C) 2006 Nathan Hurst
  10. Copyright (C) 2005 Aaron Spike, aaron@ekips.org
  11.  
  12. This program is free software; you can redistribute it and/or modify
  13. it under the terms of the GNU General Public License as published by
  14. the Free Software Foundation; either version 2 of the License, or
  15. (at your option) any later version.
  16.  
  17. This program is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. GNU General Public License for more details.
  21.  
  22. You should have received a copy of the GNU General Public License
  23. along with this program; if not, write to the Free Software
  24. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  25.  
  26. TODO:
  27.  * should use the standard attributes for text
  28.  * Implement option to keep text orientation upright 
  29.     1. Find text direction i.e. path tangent,
  30.     2. check direction >90 or <-90 Degrees
  31.     3. rotate by 180 degrees around text center
  32. '''
  33. import inkex, simplestyle, simplepath, sys, cubicsuperpath, bezmisc, locale
  34. # Set current system locale
  35. locale.setlocale(locale.LC_ALL, '')
  36.  
  37. def numsegs(csp):
  38.     return sum([len(p)-1 for p in csp])
  39. def interpcoord(v1,v2,p):
  40.     return v1+((v2-v1)*p)
  41. def interppoints(p1,p2,p):
  42.     return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)]
  43. def pointdistance((x1,y1),(x2,y2)):
  44.     return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
  45. def bezlenapprx(sp1, sp2):
  46.     return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1])
  47. def tpoint((x1,y1), (x2,y2), t = 0.5):
  48.     return [x1+t*(x2-x1),y1+t*(y2-y1)]
  49. def cspbezsplit(sp1, sp2, t = 0.5):
  50.     m1=tpoint(sp1[1],sp1[2],t)
  51.     m2=tpoint(sp1[2],sp2[0],t)
  52.     m3=tpoint(sp2[0],sp2[1],t)
  53.     m4=tpoint(m1,m2,t)
  54.     m5=tpoint(m2,m3,t)
  55.     m=tpoint(m4,m5,t)
  56.     return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
  57. def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001):
  58.     bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
  59.     t = bezmisc.beziertatlength(bez, l, tolerance)
  60.     return cspbezsplit(sp1, sp2, t)
  61. def cspseglength(sp1,sp2, tolerance = 0.001):
  62.     bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
  63.     return bezmisc.bezierlength(bez, tolerance)    
  64. def csplength(csp):
  65.     total = 0
  66.     lengths = []
  67.     for sp in csp:
  68.         lengths.append([])
  69.         for i in xrange(1,len(sp)):
  70.             l = cspseglength(sp[i-1],sp[i])
  71.             lengths[-1].append(l)
  72.             total += l            
  73.     return lengths, total
  74. def csparea(csp):
  75.     area = 0.0
  76.     n0 = 0.0
  77.     x0 = 0.0
  78.     y0 = 0.0
  79.     for sp in csp:
  80.         for i in range(len(sp)):            # calculate polygon area
  81.             area += 0.5*sp[i-1][1][0]*(sp[i][1][1] - sp[i-2][1][1])
  82.             if abs(sp[i-1][1][0]-sp[i][1][0]) > 0.001 or abs(sp[i-1][1][1]-sp[i][1][1]) > 0.001:
  83.                 n0 += 1.0
  84.                 x0 += sp[i][1][0]
  85.                 y0 += sp[i][1][1]
  86.         for i in range(1, len(sp)):         # add contribution from cubic Bezier
  87.             bezarea  = ( 0.0*sp[i-1][1][1] + 2.0*sp[i-1][2][1] + 1.0*sp[i][0][1] - 3.0*sp[i][1][1])*sp[i-1][1][0]
  88.             bezarea += (-2.0*sp[i-1][1][1] + 0.0*sp[i-1][2][1] + 1.0*sp[i][0][1] + 1.0*sp[i][1][1])*sp[i-1][2][0]
  89.             bezarea += (-1.0*sp[i-1][1][1] - 1.0*sp[i-1][2][1] + 0.0*sp[i][0][1] + 2.0*sp[i][1][1])*sp[i][0][0]
  90.             bezarea += ( 3.0*sp[i-1][1][1] - 1.0*sp[i-1][2][1] - 2.0*sp[i][0][1] + 0.0*sp[i][1][1])*sp[i][1][0]
  91.             area += 0.15*bezarea
  92.     return abs(area), x0/n0, y0/n0
  93.  
  94. class Length(inkex.Effect):
  95.     def __init__(self):
  96.         inkex.Effect.__init__(self)
  97.         self.OptionParser.add_option("--type",
  98.                         action="store", type="string", 
  99.                         dest="type", default="length",
  100.                         help="Type of measurement")
  101.         self.OptionParser.add_option("-f", "--fontsize",
  102.                         action="store", type="int", 
  103.                         dest="fontsize", default=20,
  104.                         help="Size of length lable text in px")
  105.         self.OptionParser.add_option("-o", "--offset",
  106.                         action="store", type="float", 
  107.                         dest="offset", default=-6,
  108.                         help="The distance above the curve")
  109.         self.OptionParser.add_option("-u", "--unit",
  110.                         action="store", type="string", 
  111.                         dest="unit", default="mm",
  112.                         help="The unit of the measurement")
  113.         self.OptionParser.add_option("-p", "--precision",
  114.                         action="store", type="int", 
  115.                         dest="precision", default=2,
  116.                         help="Number of significant digits after decimal point")
  117.         self.OptionParser.add_option("-s", "--scale",
  118.                         action="store", type="float", 
  119.                         dest="scale", default=1,
  120.                         help="The distance above the curve")
  121.         self.OptionParser.add_option("-r", "--orient",
  122.                         action="store", type="inkbool", 
  123.                         dest="orient", default=True,
  124.                         help="Keep orientation of text upright")
  125.         self.OptionParser.add_option("--tab",
  126.                         action="store", type="string", 
  127.                         dest="tab", default="sampling",
  128.                         help="The selected UI-tab when OK was pressed") 
  129.         self.OptionParser.add_option("--measurehelp",
  130.                         action="store", type="string", 
  131.                         dest="measurehelp", default="",
  132.                         help="dummy") 
  133.                         
  134.     def effect(self):
  135.         # get number of digits
  136.         prec = int(self.options.precision)
  137.         # loop over all selected paths
  138.         for id, node in self.selected.iteritems():
  139.             if node.tag == inkex.addNS('path','svg'):
  140.                 self.group = inkex.etree.SubElement(node.getparent(),inkex.addNS('text','svg'))
  141.                 
  142.                 t = node.get('transform')
  143.                 # Removed to fix LP #308183 
  144.                 # (Measure Path text shifted when used with a copied object)
  145.                 #if t:
  146.                 #    self.group.set('transform', t)
  147.  
  148.  
  149.                 a =[]
  150.                 p = cubicsuperpath.parsePath(node.get('d'))
  151.                 num = 1
  152.                 factor = 1.0/inkex.unittouu('1'+self.options.unit)
  153.                 if self.options.type == "length":
  154.                     slengths, stotal = csplength(p)
  155.                 else:
  156.                     stotal,x0,y0 = csparea(p)
  157.                     stotal *= factor*self.options.scale
  158.                 # Format the length as string
  159.                 lenstr = locale.format("%(len)25."+str(prec)+"f",{'len':round(stotal*factor*self.options.scale,prec)}).strip()
  160.                 if self.options.type == "length":
  161.                     self.addTextOnPath(self.group,0, 0,lenstr+' '+self.options.unit, id, self.options.offset)
  162.                 else:
  163.                     self.addTextWithTspan(self.group,x0,y0,lenstr+' '+self.options.unit+'^2', id, self.options.offset)
  164.  
  165.  
  166.     def addTextOnPath(self,node,x,y,text, id,dy=0):
  167.                 new = inkex.etree.SubElement(node,inkex.addNS('textPath','svg'))
  168.                 s = {'text-align': 'center', 'vertical-align': 'bottom',
  169.                     'text-anchor': 'middle', 'font-size': str(self.options.fontsize),
  170.                     'fill-opacity': '1.0', 'stroke': 'none',
  171.                     'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
  172.                 new.set('style', simplestyle.formatStyle(s))
  173.                 new.set(inkex.addNS('href','xlink'), '#'+id)
  174.                 new.set('startOffset', "50%")
  175.                 new.set('dy', str(dy)) # dubious merit
  176.                 #new.append(tp)
  177.                 new.text = str(text)
  178.                 #node.set('transform','rotate(180,'+str(-x)+','+str(-y)+')')
  179.                 node.set('x', str(x))
  180.                 node.set('y', str(y))
  181.  
  182.     def addTextWithTspan(self,node,x,y,text,id,dy=0):
  183.                 new = inkex.etree.SubElement(node,inkex.addNS('tspan','svg'), {inkex.addNS('role','sodipodi'): 'line'})
  184.                 s = {'text-align': 'center', 'vertical-align': 'bottom',
  185.                     'text-anchor': 'middle', 'font-size': str(self.options.fontsize),
  186.                     'fill-opacity': '1.0', 'stroke': 'none',
  187.                     'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
  188.                 new.set('style', simplestyle.formatStyle(s))
  189.                 new.set(inkex.addNS('href','xlink'), '#'+id)
  190.                 new.set('startOffset', "50%")
  191.                 new.set('dy', str(dy))
  192.                 new.text = str(text)
  193.                 node.set('x', str(x))
  194.                 node.set('y', str(y))
  195.  
  196. if __name__ == '__main__':
  197.     e = Length()
  198.     e.affect()
  199.  
  200.  
  201. # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
  202.