title: How to do the group transforms in SVG file programmatically?
body: <p>I have SVG file with following image:</p>
  
  <p><a href="https://i.stack.imgur.com/Myyd0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Myyd0.png" alt="Image"></a></p>
  
  <p>Each of the arrows is represented by a code like this:</p>
  
  <pre><code>&lt;g
     transform="matrix(-1,0,0,-1,149.82549,457.2455)"
     id="signS"
     inkscape:label="#sign"&gt;
    &lt;title
       id="title4249"&gt;South, 180&lt;/title&gt;
    &lt;path
       sodipodi:nodetypes="ccc"
       inkscape:connector-curvature="0"
       id="path4251"
       d="m 30.022973,250.04026 4.965804,-2.91109 4.988905,2.91109"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.6855976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /&gt;
    &lt;rect
       y="250.11305"
       x="29.768578"
       height="2.6057031"
       width="10.105703"
       id="rect4253"
       style="fill:#008000;fill-opacity:1;stroke:#000000;stroke-width:0.53715414;stroke-opacity:1" /&gt;
  &lt;/g&gt;
  </code></pre>
  
  <p>I want to calculate the <strong>absolute position</strong> of the rectangle (<code>rect</code> node). In order to do this, I need to evaluate the expression inside the <code>transform</code> tag of the <code>g</code> tag (<code>matrix(-1,0,0,-1,149.82549,457.2455)</code> in the example above).</p>
  
  <p>How can I do it?</p>
  
  <p>I assume that the first step is to read the file as <code>SVGDocument</code> using <a href="https://xmlgraphics.apache.org/batik/using/dom-api.html" rel="nofollow noreferrer">Apache Batik</a>:</p>
  
  <pre><code>import java.io.IOException;
  
  import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
  import org.apache.batik.util.XMLResourceDescriptor;
  
  import org.w3c.dom.Document;
  
  try {
      String parser = XMLResourceDescriptor.getXMLParserClassName();
      SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
      String uri = "http://www.example.org/diagram.svg";
      Document doc = f.createDocument(uri);
  } catch (IOException ex) {
      // ...
  }
  </code></pre>
  
  <p>As far as I know, <code>doc</code> can be cast to <a href="http://nick-lab.gs.washington.edu/java/batik/org/w3c/dom/svg/SVGDocument.html" rel="nofollow noreferrer">SVGDocument</a>.</p>
  
  <p>How can I get from SVG document to the absolute locations of the rectangles or groups?</p>
  
  <p>Note: I need some <strong>existing</strong> code, which does the transformations above (don't tell me to implement these transformations myself - they must be implemented already and I want to re-use that code).</p>
  
  <p><strong>Update 1 (08.11.2015 12:56 MSK):</strong></p>
  
  <p>First attempt to implement Robert Longson's recommendation:</p>
  
  <pre><code>public final class BatikTest {
      @Test
      public void test() throws XPathExpressionException {
          try {
              final File initialFile =
                  new File("src/main/resources/trailer/scene05_signs.svg");
              InputStream sceneFileStream = Files.asByteSource(initialFile).openStream();
  
  
              String parser = XMLResourceDescriptor.getXMLParserClassName();
              SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
              String uri = "http://www.example.org/diagram.svg";
              final SVGOMDocument doc = (SVGOMDocument) f.createDocument(
                  uri, sceneFileStream);
  
              final NodeList nodes =
                  doc.getDocumentElement().getElementsByTagName("g");
              SVGOMGElement signSouth = null;
  
  
              for (int i=0; (i &lt; nodes.getLength()) &amp;&amp; (signSouth == null); i++) {
                  final Node curNode = nodes.item(i);
                  final Node id = curNode.getAttributes().getNamedItem("id");
                  if ("signS".equals(id.getTextContent())) {
                      signSouth = (SVGOMGElement) curNode;
                  }
  
                  System.out.println("curNode: " + nodes);
              }
              System.out.println("signSouth: " + signSouth);
  
              final NodeList rectNodes = signSouth.getElementsByTagName("rect");
              System.out.println("rectNodes: " + rectNodes);
  
              SVGOMRectElement rectNode = (SVGOMRectElement) rectNodes.item(0);
  
              System.out.println("rectNode: " + rectNode);
  
              final SVGMatrix m2 =
                  signSouth.getTransformToElement(rectNode);
  
              System.out.println("m2: " + m2);
          } catch (IOException ex) {
              Assert.fail(ex.getMessage());
          }
      }
  }
  </code></pre>
  
  <p>Calls to <code>m2.getA()</code>-<code>m2.getF()</code> result in <code>NullPointerException</code>s.</p>
  
  <p><strong>Update 2 (08.11.2015 13:38 MSK):</strong></p>
  
  <p>Added following code to create <code>SVGPoint</code> and apply the matrix transform to it:</p>
  
  <pre><code>final SVGSVGElement docElem = (SVGSVGElement)
      doc.getDocumentElement();
  final SVGPoint svgPoint = docElem.createSVGPoint();
  svgPoint.setX((float) x);
  svgPoint.setY((float) y);
  final SVGPoint svgPoint1 =
      svgPoint.matrixTransform(signSouth.getScreenCTM()); // Line 77
  
  System.out.println("x: " + svgPoint1.getX());
  System.out.println("y: " + svgPoint1.getY());
  </code></pre>
  
  <p>Result:</p>
  
  <pre><code>java.lang.NullPointerException
      at org.apache.batik.dom.svg.SVGLocatableSupport$3.getAffineTransform(Unknown Source)
      at org.apache.batik.dom.svg.AbstractSVGMatrix.getA(Unknown Source)
      at org.apache.batik.dom.svg.SVGOMPoint.matrixTransform(Unknown Source)
      at org.apache.batik.dom.svg.SVGOMPoint.matrixTransform(Unknown Source)
      at [...].BatikTest.test(BatikTest.java:77)
  </code></pre>
  
  <p><strong>Update 3, terms of the bounty (10.11.2015 MSK):</strong></p>
  
  <p>Conditions, which must be satisfied in order to get the bounty:</p>
  
  <p>I will award the bounty to the hero or heroine, who manages to implement the methods <code>magicallyCalculateXCoordinate</code> and <code>magicallyCalculateYCoordinate</code> in the JUnit test <a href="https://github.com/dpisarenko/svgspike/blob/master/src/test/java/svgspike/BatikTest.java" rel="nofollow noreferrer">BatikTest</a> such that I can get in my Java code the coordinates of the shapes, which are displayed in InkScape (see the following screenshot for an example).</p>
  
  <p><a href="https://i.stack.imgur.com/6yniH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6yniH.png" alt="Image with coordinates"></a></p>
  
  <p>The presented method of calculating the position of shapes in SVG files must work either</p>
  
  <ol>
  <li>for group nodes (like the one in the picture and in the <a href="https://github.com/dpisarenko/svgspike/blob/master/src/test/resources/scene05_signs.svg" rel="nofollow noreferrer">sample file</a>) or</li>
  <li>for triangles.</li>
  </ol>
  
  <p>The code you provide must work for all four shapes in the sample file, i. e. using it I must be able to calculate in Java code the coordinates of them, which are equal to those displayed in Inkscape.</p>
  
  <p>You can add parameters to the methods <code>magicallyCalculateXCoordinate</code> and <code>magicallyCalculateYCoordinate</code>, and you also can create your own methods, which calculate the coordinates.</p>
  
  <p>You may use any libraries, which can be used legally for commercial purposes.</p>
  
  <p>All files related to this request are available on <a href="https://github.com/dpisarenko/svgspike" rel="nofollow noreferrer">GitHub</a>. I managed to compile the test using IntelliJ Idea Community Edition 14.1.5.</p>