У меня есть файл 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
node). Для этого мне нужно оценить выражение внутри тега transform
тега g
(matrix(-1,0,0,-1,149.82549,457.2455)
в приведенном выше примере).
Как я могу это сделать?
Я полагаю, что первый шаг должен прочитать файл как SVGDocument
, используя Apache Batik:
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):
Первая попытка реализовать рекомендацию Роберта Лонгсона:
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()
приводит к NullPointerException
s.
Обновление 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):
Условия, которые должны выполняться для получения награды:
Я вручит награду герою или героине, которому удается реализовать методы magicallyCalculateXCoordinate
и magicallyCalculateYCoordinate
в JUnit тест BatikTest, так что я могу получить в своем Java-коде координаты фигур, которые отображаются в InkScape (см. следующий скриншот для примера).
Представленный метод вычисления положения фигур в SVG файлах должен работать либо
- для групповых узлов (например, тот, что находится на картинке, и в пример файла) или
- для треугольников.
Код, который вы предоставляете, должен работать для всех четырех фигур в файле примера, т.е. е. используя его, я должен уметь вычислять в Java код их координаты, которые равны тем, которые отображаются в Inkscape.
Вы можете добавить параметры к методам magicallyCalculateXCoordinate
и magicallyCalculateYCoordinate
, и вы также можете создать свои собственные методы, которые вычисляют координаты.
Вы можете использовать любые библиотеки, которые могут использоваться на законных основаниях в коммерческих целях.
Все файлы, связанные с этим запросом, доступны на GitHub. Мне удалось скомпилировать тест, используя IntelliJ Idea Community Edition 14.1.5.