【发布时间】:2016-02-09 02:17:41
【问题描述】:
我有带有以下图像的 SVG 文件:
每个箭头都用如下代码表示:
<g
transform="matrix(-1,0,0,-1,149.82549,457.2455)"
id="signS"
inkscape:label="#sign">
<title
id="title4249">South, 180</title>
<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" />
<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" />
</g>
我想计算矩形(rect 节点)的绝对位置。为此,我需要评估g 标记的transform 标记内的表达式(上例中的matrix(-1,0,0,-1,149.82549,457.2455))。
我该怎么做?
我假设第一步是使用Apache Batik 将文件读取为SVGDocument:
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) {
// ...
}
据我所知,doc 可以转换为 SVGDocument。
如何从 SVG 文档中获取矩形或组的绝对位置?
注意:我需要一些现有代码来完成上述转换(不要告诉我自己实现这些转换 - 它们必须已经实现并且我想重复使用该代码) .
更新 1(08.11.2015 12:56 MSK):
第一次尝试执行 Robert Longson 的建议:
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 < nodes.getLength()) && (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());
}
}
}
对m2.getA()-m2.getF() 的调用导致NullPointerExceptions。
更新 2(08.11.2015 13:38 MSK):
添加了以下代码来创建SVGPoint 并对其应用矩阵变换:
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());
结果:
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)
更新 3,赏金条款(10.11.2015 MSK):
获得赏金必须满足的条件:
我会将赏金奖励给英雄或女英雄,他们设法在 JUnit 测试 BatikTest 中实现了 magicallyCalculateXCoordinate 和 magicallyCalculateYCoordinate 方法,这样我就可以在我的 Java 代码中获取形状的坐标,这显示在 InkScape 中(示例见以下屏幕截图)。
所提出的计算 SVG 文件中形状位置的方法也必须有效
- 用于组节点(如图片和sample file 中的那个)或
- 用于三角形。
您提供的代码必须适用于示例文件中的所有四种形状,即。 e.使用它,我必须能够在 Java 代码中计算它们的坐标,这些坐标等于 Inkscape 中显示的坐标。
您可以在magicallyCalculateXCoordinate 和magicallyCalculateYCoordinate 方法中添加参数,也可以创建自己的方法来计算坐标。
您可以使用任何可合法用于商业目的的库。
与此请求相关的所有文件都可以在 GitHub 上找到。我设法使用 IntelliJ Idea Community Edition 14.1.5 编译了测试。
【问题讨论】:
-
getScreenCTM、getCTM 或 getTransformToElement 中的任何一个都将为您提供从绝对单位到局部单位的整体转换。将其应用于元素的本地坐标,这将为您提供绝对单位的坐标。
-
@RobertLongson 谢谢。我尝试实施您的方法,请参阅更新 1。我可以在其中找到组节点和 rect 节点。如何应用矩阵来获取该代码中的实际坐标?
-
创建一个 SVGPoint 将其值设置为本地坐标,调用 matrixTransform w3.org/TR/SVG/coords.html#InterfaceSVGPoint 和 w3.org/TR/SVG/struct.html#__svg__SVGSVGElement__createSVGPoint
-
@RobertLongson 当我将矩阵应用于
SVGPoint时,我得到了NullPointerException。请参阅更新 2。 -
不确定,可能 getScreenCTM 为 null,这不应该发生。也许尝试 getCTM 或 getTransformToElement(从根元素)