Code

add 'area' calculation to Measure extension
authorAlvin Penner <penner@vaxxine.com>
Mon, 26 Apr 2010 02:57:01 +0000 (22:57 -0400)
committerAlvin Penner <penner@vaxxine.com>
Mon, 26 Apr 2010 02:57:01 +0000 (22:57 -0400)
share/extensions/measure.inx
share/extensions/measure.py

index 8f2f411593d1255950628fc6276b97b7aa79706d..513ff7d70d7acad3dd8dbaebe4d1916fad36b01a 100644 (file)
@@ -1,40 +1,49 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
-  <_name>Measure Path</_name>
-  <id>com.njhurst.filter.measure_length</id>
-  <dependency type="executable" location="extensions">measure.py</dependency>
-  <dependency type="executable" location="extensions">inkex.py</dependency>
-  <param name="tab" type="notebook">
-    <page name="measure" _gui-text="Measure">
-      <param name="fontsize" type="int" min="1" max="1000" _gui-text="Font size [px]">12</param>
-      <param name="offset" type="float" min="-10000" max="10000" _gui-text="Offset [px]">-6</param>
-      <param name="precision" type="int" min="0" max="25" _gui-text="Precision">2</param>
-      <param name="scale" type="float" min="1e-8" max="1e10" _gui-text="Scale Factor (Drawing:Real Length) = 1:">1</param>
-      <!--<param name="orient" type="boolean" _gui-text="Keep text orientation upright">true</param>-->
-      <!--<param name="unit" type="string" _gui-text="Unit {km|m|cm|mm|in|px|pt}">mm</param>-->
-      <param name="unit" type="enum" _gui-text="Length Unit: ">
-        <item value="px">px</item>
-        <item value="pt">pt</item>
-        <item value="in">in</item>
-        <item value="ft">ft</item>
-        <item value="yd">yd</item>
-        <item value="mm">mm</item>
-        <item value="cm">cm</item>
-        <item value="m">m</item>
-        <item value="km">km</item>
-      </param>
-    </page>
-    <page name="desc" _gui-text="Help">
-      <_param name="measurehelp" type="description">This effect measures the length of the selected path and adds it as a text-on-path object with the selected unit. The number of significant digits can be controlled by the Precision field. The Offset field controls the distance from the text to the path. The Scale factor can be used to make measurements in scaled drawings. For example, if 1 cm in the drawing equals 2.5 m in the real world, Scale must be set to 250.</_param>
-    </page>
-  </param>
-  <effect>
-    <object-type>path</object-type>
-    <effects-menu>
-      <submenu _name="Visualize Path"/>
-    </effects-menu>
-  </effect>
-  <script>
-    <command reldir="extensions" interpreter="python">measure.py</command>
-  </script>
+       <_name>Measure Path</_name>
+       <id>com.njhurst.filter.measure_length</id>
+       <dependency type="executable" location="extensions">measure.py</dependency>
+       <dependency type="executable" location="extensions">inkex.py</dependency>
+       <param name="tab" type="notebook">
+               <page name="measure" _gui-text="Measure">
+                       <param name="type" type="enum" _gui-text="Measurement Type: ">
+                               <item value="length">Length</item>
+                               <item value="area">Area</item>
+                       </param>
+                       <param name="fontsize" type="int" min="1" max="1000" _gui-text="Font size [px]">12</param>
+                       <param name="offset" type="float" min="-10000" max="10000" _gui-text="Offset [px]">-6</param>
+                       <param name="precision" type="int" min="0" max="25" _gui-text="Precision">2</param>
+                       <param name="scale" type="float" min="1e-8" max="1e10" _gui-text="Scale Factor (Drawing:Real Length) = 1:">1</param>
+                       <!--<param name="orient" type="boolean" _gui-text="Keep text orientation upright">true</param>-->
+                       <!--<param name="unit" type="string" _gui-text="Unit {km|m|cm|mm|in|px|pt}">mm</param>-->
+                       <param name="unit" type="enum" _gui-text="Length Unit: ">
+                               <item value="px">px</item>
+                               <item value="pt">pt</item>
+                               <item value="in">in</item>
+                               <item value="ft">ft</item>
+                               <item value="yd">yd</item>
+                               <item value="mm">mm</item>
+                               <item value="cm">cm</item>
+                               <item value="m">m</item>
+                               <item value="km">km</item>
+                       </param>
+               </page>
+               <page name="desc" _gui-text="Help">
+                       <_param name="measurehelp" type="description" xml:space="preserve">This effect measures the length, or area, of the selected path and adds it as a text-on-path object with the selected unit.
+            
+  * The number of significant digits can be controlled by the Precision field.
+  * The Offset field controls the distance from the text to the path.
+  * The Scale factor can be used to make measurements in scaled drawings. For example, if 1 cm in the drawing equals 2.5 m in the real world, Scale must be set to 250.
+  * When calculating area, the result should be precise for polygons and Bezier curves. If a circle is used, the area may be too high by as much as 0.03%.</_param>
+               </page>
+       </param>
+       <effect>
+               <object-type>path</object-type>
+               <effects-menu>
+                       <submenu _name="Visualize Path"/>
+               </effects-menu>
+       </effect>
+       <script>
+               <command reldir="extensions" interpreter="python">measure.py</command>
+       </script>
 </inkscape-extension>
index 68586530be826887cfe7b656130ba10375838a6f..0335f3fe9d9d734e6f4e9a872ac1cf9654d30e02 100644 (file)
@@ -4,6 +4,7 @@ This extension module can measure arbitrary path and object length
 It adds a text to the selected path containing the length in a
 given unit.
 
+Copyright (C) 2010 Alvin Penner
 Copyright (C) 2006 Georg Wiora
 Copyright (C) 2006 Nathan Hurst
 Copyright (C) 2005 Aaron Spike, aaron@ekips.org
@@ -70,10 +71,33 @@ def csplength(csp):
             lengths[-1].append(l)
             total += l            
     return lengths, total
+def csparea(csp):
+    area = 0.0
+    n0 = 0.0
+    x0 = 0.0
+    y0 = 0.0
+    for sp in csp:
+        for i in range(len(sp)):            # calculate polygon area
+            area += 0.5*sp[i-1][1][0]*(sp[i][1][1] - sp[i-2][1][1])
+            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:
+                n0 += 1.0
+                x0 += sp[i][1][0]
+                y0 += sp[i][1][1]
+        for i in range(1, len(sp)):         # add contribution from cubic Bezier
+            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]
+            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]
+            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]
+            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]
+            area += 0.15*bezarea
+    return abs(area), x0/n0, y0/n0
 
 class Length(inkex.Effect):
     def __init__(self):
         inkex.Effect.__init__(self)
+        self.OptionParser.add_option("--type",
+                        action="store", type="string", 
+                        dest="type", default="length",
+                        help="Type of measurement")
         self.OptionParser.add_option("-f", "--fontsize",
                         action="store", type="int", 
                         dest="fontsize", default=20,
@@ -125,11 +149,18 @@ class Length(inkex.Effect):
                 a =[]
                 p = cubicsuperpath.parsePath(node.get('d'))
                 num = 1
-                slengths, stotal = csplength(p)
                 factor = 1.0/inkex.unittouu('1'+self.options.unit)
+                if self.options.type == "length":
+                    slengths, stotal = csplength(p)
+                else:
+                    stotal,x0,y0 = csparea(p)
+                    stotal *= factor*self.options.scale
                 # Format the length as string
                 lenstr = locale.format("%(len)25."+str(prec)+"f",{'len':round(stotal*factor*self.options.scale,prec)}).strip()
-                self.addTextOnPath(self.group,0, 0,lenstr+' '+self.options.unit, id, self.options.offset)
+                if self.options.type == "length":
+                    self.addTextOnPath(self.group,0, 0,lenstr+' '+self.options.unit, id, self.options.offset)
+                else:
+                    self.addTextWithTspan(self.group,x0,y0,lenstr+' '+self.options.unit+'^2', id, self.options.offset)
 
 
     def addTextOnPath(self,node,x,y,text, id,dy=0):
@@ -148,6 +179,20 @@ class Length(inkex.Effect):
                 node.set('x', str(x))
                 node.set('y', str(y))
 
+    def addTextWithTspan(self,node,x,y,text,id,dy=0):
+                new = inkex.etree.SubElement(node,inkex.addNS('tspan','svg'), {inkex.addNS('role','sodipodi'): 'line'})
+                s = {'text-align': 'center', 'vertical-align': 'bottom',
+                    'text-anchor': 'middle', 'font-size': str(self.options.fontsize),
+                    'fill-opacity': '1.0', 'stroke': 'none',
+                    'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
+                new.set('style', simplestyle.formatStyle(s))
+                new.set(inkex.addNS('href','xlink'), '#'+id)
+                new.set('startOffset', "50%")
+                new.set('dy', str(dy))
+                new.text = str(text)
+                node.set('x', str(x))
+                node.set('y', str(y))
+
 if __name__ == '__main__':
     e = Length()
     e.affect()