Code

fix Bug 308204, add Visual bbox option
authorAlvin Penner <penner@vaxxine.com>
Tue, 20 Jul 2010 23:00:21 +0000 (19:00 -0400)
committerAlvin Penner <penner@vaxxine.com>
Tue, 20 Jul 2010 23:00:21 +0000 (19:00 -0400)
share/extensions/dimension.inx
share/extensions/dimension.py
share/extensions/simpletransform.py

index 114a3688e444e220aa74ee84e3adc9b4cefbd62e..cce244d4aa79c63e86c1e09633585cb76e1a426c 100644 (file)
@@ -1,19 +1,23 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
-    <_name>Dimensions</_name>
-    <id>se.lewerin.filter.dimension</id>
+       <_name>Dimensions</_name>
+       <id>se.lewerin.filter.dimension</id>
        <dependency type="executable" location="extensions">dimension.py</dependency>
        <dependency type="executable" location="extensions">inkex.py</dependency>
        <dependency type="executable" location="extensions">pathmodifier.py</dependency>
        <param name="xoffset" type="float" min="0" max="1000" _gui-text="X Offset">50</param>
        <param name="yoffset" type="float" min="0" max="1000" _gui-text="Y Offset">50</param>
-    <effect>
+       <param name="type" type="optiongroup" _gui-text="Bounding box type : ">
+               <_option value="geometric">Geometric</_option>
+               <_option value="visual">Visual</_option>
+       </param>
+       <effect>
                <object-type>path</object-type>
-                <effects-menu>
-                    <submenu _name="Visualize Path"/>
-                </effects-menu>
-    </effect>
-    <script>
-        <command reldir="extensions" interpreter="python">dimension.py</command>
-    </script>
+               <effects-menu>
+                       <submenu _name="Visualize Path"/>
+               </effects-menu>
+       </effect>
+       <script>
+               <command reldir="extensions" interpreter="python">dimension.py</command>
+       </script>
 </inkscape-extension>
index cda3a96fda1e568db784a03f413efd0c7475a4a8..1b84642eab44cd2d18b96fb1029c52de2250dd11 100644 (file)
@@ -37,6 +37,12 @@ from simpletransform import *
 import gettext
 _ = gettext.gettext
 
+try:
+    from subprocess import Popen, PIPE
+    bsubprocess = True
+except:
+    bsubprocess = False
+
 class Dimension(pathmodifier.PathModifier):
     def __init__(self):
         inkex.Effect.__init__(self)
@@ -48,6 +54,10 @@ class Dimension(pathmodifier.PathModifier):
                         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')
@@ -90,7 +100,28 @@ class Dimension(pathmodifier.PathModifier):
         self.xoffset = self.options.xoffset
         self.yoffset = self.options.yoffset
 
-        self.bbox = computeBBox(self.selected.values())
+        # 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] = 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] = 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:
@@ -103,7 +134,8 @@ class Dimension(pathmodifier.PathModifier):
         self.addMarker('Arrow1Lstart', False)
         self.addMarker('Arrow1Lend',  True)
 
-        group = inkex.etree.Element("g")
+        group = inkex.etree.SubElement(layer, 'g')
+        # group = inkex.etree.Element("g")
         group.set('fill', 'none')
         group.set('stroke', 'black')
 
index c89d771ec57beb99aca70f68cfb2670e890ddbfb..08aa4c55fd6084c47bf22d36618c8a154675f0fb 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 '''
 Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
+Copyright (C) 2010 Alvin Penner, penner@vaxxine.com
 
 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
@@ -142,6 +143,44 @@ def roughBBox(path):
                 yMax = max(yMax,pt[1])
     return xmin,xMax,ymin,yMax
 
+def refinedBBox(path):
+    xmin,xMax,ymin,yMax = path[0][0][1][0],path[0][0][1][0],path[0][0][1][1],path[0][0][1][1]
+    for pathcomp in path:
+        for i in range(1, len(pathcomp)):
+            cmin, cmax = cubicExtrema(pathcomp[i-1][1][0], pathcomp[i-1][2][0], pathcomp[i][0][0], pathcomp[i][1][0])
+            xmin = min(xmin, cmin)
+            xMax = max(xMax, cmax)
+            cmin, cmax = cubicExtrema(pathcomp[i-1][1][1], pathcomp[i-1][2][1], pathcomp[i][0][1], pathcomp[i][1][1])
+            ymin = min(ymin, cmin)
+            yMax = max(yMax, cmax)
+    return xmin,xMax,ymin,yMax
+
+def cubicExtrema(y0, y1, y2, y3):
+    cmin = min(y0, y3)
+    cmax = max(y0, y3)
+    d1 = y1 - y0
+    d2 = y2 - y1
+    d3 = y3 - y2
+    if (d1 - 2*d2 + d3):
+        if (d2*d2 > d1*d3):
+            t = (d1 - d2 + math.sqrt(d2*d2 - d1*d3))/(d1 - 2*d2 + d3)
+            if (t > 0) and (t < 1):
+                y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t
+                cmin = min(cmin, y)
+                cmax = max(cmax, y)
+            t = (d1 - d2 - math.sqrt(d2*d2 - d1*d3))/(d1 - 2*d2 + d3)
+            if (t > 0) and (t < 1):
+                y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t
+                cmin = min(cmin, y)
+                cmax = max(cmax, y)
+    elif (d3 - d1):
+        t = -d1/(d3 - d1)
+        if (t > 0) and (t < 1):
+            y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t
+            cmin = min(cmin, y)
+            cmax = max(cmax, y)
+    return cmin, cmax
+
 def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
     bbox=None
     for node in aList:
@@ -179,7 +218,7 @@ def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
         if d is not None:
             p = cubicsuperpath.parsePath(d)
             applyTransformToPath(m,p)
-            bbox=boxunion(roughBBox(p),bbox)
+            bbox=boxunion(refinedBBox(p),bbox)
 
         elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
             refid=node.get(inkex.addNS('href','xlink'))