SVG“实例”树行走

问题描述

我有下面的 SVG(从一个更大的自动生成文件中剪下来)

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" height="2880.0px" width="2300.0px">
  <g transform="matrix(1.0,0.0,1.0,0.0)">
    <use height="2048.2" id="outer" transform="matrix(1.0,84.6,3841.0)" width="2048.2" xlink:href="#sprite0"/>
  </g>
  <defs>
    <g id="sprite0" transform="matrix(1.0,1024.1,1024.1)">
      <use height="2048.2" id="inner" transform="matrix(1.0,-1024.1,-1024.1)" width="2048.2" xlink:href="#sprite1"/>
    </g>
    <g id="sprite1" transform="matrix(1.0,1024.1)">
      <use height="444.35" id="elem" transform="matrix(1.0,-368.6,-180.2)" width="335.35" xlink:href="#sprite4"/>
    </g>
    <g id="sprite4" transform="matrix(1.0,167.65,222.15)">
      <use height="401.35" transform="matrix(0.4578,1.1071,-167.6615,-222.146)" width="732.55" xlink:href="#shape4"/>
    </g>
    <g id="shape4" transform="matrix(1.0,366.25,200.65)">
      <path d="M366.3 -200.65 L366.3 200.7 -366.25 200.7 -366.25 -200.65 366.3 -200.65" fill="#a9a9a9" fill-rule="evenodd" stroke="none"/>
    </g>
  </defs>
</svg>

我的目标是获取名为 elem 的元素的变换矩阵,该元素位于 inner 内的 outer(以相对于外)。

我这样做是为了得到外部并确认它有一个我可以使用的转换(蜡染已初始化!!)

        final SvgoMElement outer = (SvgoMElement)docAsSVGElement.getElementById("outer");
        assert outer instanceof SVGLocatable;
        assert ((SVGLocatable)outer).getCTM() != null;
        assert ((SVGLocatable)outer).getCTM().getA() != 0.0;

但是要到达指定的项目 elem - 我该如何走“GVT”?树,而不是 SVG 文档树?还是我遗漏了一些其他明显的东西(似乎没有人在谈论)?

         // this finds the deFinition,not the instance that is ultimately part of the visual "outer"??
        final SvgoMElement inner = (SvgoMElement)docAsSVGElement.getElementById("elem");

注意:不能使用 getTransformtoElement() - 因为 elem 不在实例树中(或似乎不在)。

解决方法

一个答案是导航 SVG 树 - 在每个点提取转换然后将它们组合在一起。

可以使用带有提取的 transform 属性值的 Batik AWTTransformProducer 为每个转换创建一个 AWT AffineTransform。例如

   final String transformAttrVal = "matrix(1.0,0.0,1.0,366.25,200.65)";
   final AffineTransform transform = AWTTransformProducer.createAffineTransform(transformAttrVal);

然后一直向下串联或自下而上工作(和预串联)。

   final AffineTransform sprite0 = ...
   final AffineTransform inner = ...

   final AffineTransform combined = (AffineTransform)sprite0.clone(); // only if you need sprite0 again ..
   combined.concatenate(inner);
   combined.concatenate(nextLevelDown);
   ...
   combined.concatenate(shape4);

然后最后将组合应用于每个点。