added more test cases for the svg parser

This commit is contained in:
hneemann 2018-11-30 12:08:45 +01:00
parent 71718b7946
commit e9c620953e
6 changed files with 198 additions and 36 deletions

View File

@ -174,6 +174,20 @@ public class CustomShapeDescription implements Iterable<Drawable> {
public void drawTo(Graphic graphic, Style highLight) {
graphic.drawLine(p1, p2, Style.NORMAL.deriveStyle(thickness, false, color));
}
/**
* @return first coordinate
*/
public Vector getP1() {
return p1;
}
/**
* @return second coordinate
*/
public Vector getP2() {
return p2;
}
}
/**

View File

@ -114,6 +114,16 @@ class Context {
return vector.transform(tr);
}
public VectorInterface v(float x, float y) {
return new VectorFloat(x, y).transform(tr);
}
public VectorInterface v(String xStr, String yStr) {
float x = xStr.isEmpty() ? 0 : Float.parseFloat(xStr);
float y = yStr.isEmpty() ? 0 : Float.parseFloat(yStr);
return v(x, y);
}
public float getFontSize() {
return fontSize;
}

View File

@ -90,8 +90,8 @@ public class SvgImporter {
break;
case "line":
csd.addLine(
vec(element.getAttribute("x1"), element.getAttribute("y1"), c).round(),
vec(element.getAttribute("x2"), element.getAttribute("y2"), c).round(),
c.v(element.getAttribute("x1"), element.getAttribute("y1")).round(),
c.v(element.getAttribute("x2"), element.getAttribute("y2")).round(),
c.getThickness(), c.getColor());
break;
case "rect":
@ -139,22 +139,12 @@ public class SvgImporter {
csd.addPolygon(polygon.transform(c.getTransform()), c.getThickness(), c.getColor(), false);
}
private VectorFloat vec(String xStr, String yStr, Context c) {
return c.getTransform().transform(vec(xStr, yStr));
}
private VectorFloat vec(String xStr, String yStr) {
float x = xStr.isEmpty() ? 0 : Float.parseFloat(xStr);
float y = yStr.isEmpty() ? 0 : Float.parseFloat(yStr);
return new VectorFloat(x, y);
}
private VectorFloat vecD(String xStr, String yStr, Context c) {
float x = xStr.isEmpty() ? 0 : Float.parseFloat(xStr);
float y = yStr.isEmpty() ? 0 : Float.parseFloat(yStr);
return c.getTransform().getMatrix().transformDirection(new VectorFloat(x, y));
}
private void drawRect(CustomShapeDescription csd, Element element, Context c) {
VectorInterface size = vec(element.getAttribute("width"), element.getAttribute("height"));
VectorInterface pos = vec(element.getAttribute("x"), element.getAttribute("y"));
@ -165,31 +155,35 @@ public class SvgImporter {
float width = size.getXFloat();
float height = size.getYFloat();
if (rad.getXFloat() * rad.getYFloat() != 0) {
float w = size.getXFloat() - 2 * rad.getXFloat();
float h = size.getYFloat() - 2 * rad.getYFloat();
float rx = rad.getXFloat();
float ry = rad.getYFloat();
float w = size.getXFloat() - 2 * rx;
float h = size.getYFloat() - 2 * ry;
double f = 4 * (Math.sqrt(2) - 1) / 3;
float cx = (float) (f * rx);
float cy = (float) (f * ry);
csd.addPolygon(new Polygon(true)
.add(c.tr(new VectorFloat(x + rx, y)))
.add(c.tr(new VectorFloat(x + rx + w, y)))
.add(c.tr(new VectorFloat(x + width, y + ry)))
.add(c.tr(new VectorFloat(x + width, y + ry + h)))
.add(c.tr(new VectorFloat(x + rx + w, y + height)))
.add(c.tr(new VectorFloat(x + rx, y + height)))
.add(c.tr(new VectorFloat(x, y + ry + h)))
.add(c.tr(new VectorFloat(x, y + ry))), c.getThickness(), c.getColor(), false);
.add(c.v(x + rx + w, y))
.add(c.v(x + rx + w + cx, y), c.v(x + width, y + ry - cy), c.v(x + width, y + ry))
.add(c.v(x + width, y + ry + h))
.add(c.v(x + width, y + ry + h + cy), c.v(x + rx + w + cx, y + height), c.v(x + rx + w, y + height))
.add(c.v(x + rx, y + height))
.add(c.v(x + rx - cx, y + height), c.v(x, y + ry + h + cy), c.v(x, y + ry + h))
.add(c.v(x, y + ry))
.add(c.v(x, y + ry - cy), c.v(x + rx - cx, y), c.v(x + rx, y)), c.getThickness(), c.getColor(), false);
} else
csd.addPolygon(new Polygon(true)
.add(c.tr(new VectorFloat(x, y)))
.add(c.tr(new VectorFloat(x + width, y)))
.add(c.tr(new VectorFloat(x + width, y + height)))
.add(c.tr(new VectorFloat(x, y + height))), c.getThickness(), c.getColor(), false);
.add(c.v(x, y))
.add(c.v(x + width, y))
.add(c.v(x + width, y + height))
.add(c.v(x, y + height)), c.getThickness(), c.getColor(), false);
}
private void drawCircle(CustomShapeDescription csd, Element element, Context c) {
if (element.hasAttribute("id")) {
VectorFloat pos = vec(element.getAttribute("cx"), element.getAttribute("cy"), c);
VectorInterface pos = c.v(element.getAttribute("cx"), element.getAttribute("cy"));
String id = element.getAttribute("id");
if (id.startsWith("pin:")) {
csd.addPin(id.substring(4).trim(), pos.round(), false);
@ -203,20 +197,33 @@ public class SvgImporter {
VectorFloat r = null;
if (element.hasAttribute("r")) {
final String rad = element.getAttribute("r");
r = vecD(rad, rad, c);
r = vec(rad, rad);
}
if (element.hasAttribute("rx")) {
r = vecD(element.getAttribute("rx"), element.getAttribute("ry"), c);
r = vec(element.getAttribute("rx"), element.getAttribute("ry"));
}
if (r != null) {
VectorFloat pos = vec(element.getAttribute("cx"), element.getAttribute("cy"), c);
VectorFloat oben = pos.sub(r);
VectorFloat unten = pos.add(r);
VectorFloat pos = vec(element.getAttribute("cx"), element.getAttribute("cy"));
float x = pos.getXFloat();
float y = pos.getYFloat();
float rx = r.getXFloat();
float ry = r.getYFloat();
double f = 4 * (Math.sqrt(2) - 1) / 3;
float cx = (float) (f * rx);
float cy = (float) (f * ry);
Polygon poly = new Polygon(true)
.add(c.v(x - rx, y))
.add(c.v(x - rx, y + cy), c.v(x - cx, y + ry), c.v(x, y + ry))
.add(c.v(x + cx, y + ry), c.v(x + rx, y + cy), c.v(x + rx, y))
.add(c.v(x + rx, y - cy), c.v(x + cx, y - ry), c.v(x, y - ry))
.add(c.v(x - cx, y - ry), c.v(x - rx, y - cy), c.v(x - rx, y));
if (c.getFilled() != null)
csd.addCircle(oben.round(), unten.round(), c.getThickness(), c.getFilled(), true);
csd.addPolygon(poly, c.getThickness(), c.getFilled(), true);
if (c.getColor() != null)
csd.addCircle(oben.round(), unten.round(), c.getThickness(), c.getColor(), false);
csd.addPolygon(poly, c.getThickness(), c.getColor(), false);
}
}

View File

@ -957,6 +957,7 @@ Sind evtl. die Namen der Variablen nicht eindeutig?</string>
<string name="err_noRomFound">Kein Programmspeicher im Modell gefunden! Ein Programmspeicher muss gewählt werden!</string>
<string name="err_moreThenOneRomFound">Mehr als einen Programmspeicher gefunden. Es darf nur einen Programmspeicher geben.</string>
<string name="err_errorLoadingRomData">Fehler beim Laden des Programmspeichers.</string>
<string name="err_parsingSVG">Fehler beim Laden der SVG-Datei.</string>
<string name="key_AddrBits">Adress-Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Anzahl der Adress-Bits, die verwendet werden.</string>

View File

@ -954,6 +954,7 @@
<string name="err_noRomFound">No program memory found! The program memory needs to be flagged as such.</string>
<string name="err_moreThenOneRomFound">More then one program memories found! Only one program memory must be flages as such.</string>
<string name="err_errorLoadingRomData">Error loading the program memory.</string>
<string name="err_parsingSVG">Error while reading the SVG file.</string>
<string name="key_AddrBits">Address Bits</string><!-- ROM, RAMDualPort, RAMSinglePort, RAMSinglePortSel, EEPROM -->
<string name="key_AddrBits_tt">Number of address bits used.</string>

View File

@ -1,8 +1,14 @@
/*
* Copyright (c) 2018 Helmut Neemann.
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.draw.shapes.custom;
import de.neemann.digital.draw.elements.PinException;
import de.neemann.digital.draw.graphics.Polygon;
import de.neemann.digital.draw.graphics.PolygonParser;
import de.neemann.digital.draw.graphics.VectorInterface;
import de.neemann.digital.draw.shapes.Drawable;
import de.neemann.digital.draw.shapes.custom.svg.SvgException;
import de.neemann.digital.draw.shapes.custom.svg.SvgImporter;
@ -130,6 +136,100 @@ public class SvgImporterTest extends TestCase {
.check();
}
public void testPolygonRotate() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<g transform=\"rotate(30)\">\n" +
"<path fill=\"none\" stroke=\"black\"\n" +
"d=\"M 0,0 L 0,100 L 100,100 L 100,0 Z\"/>\n" +
"</g>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkPolygon("M 0,0 L -50,86.60254 L 36.60254,136.60254 L 86.60254,50 Z")
.check();
}
public void testPolygonRotate2() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<g transform=\"rotate(45, 50, 50)\">\n" +
"<path fill=\"none\" stroke=\"black\"\n" +
"d=\"M 0,0 L 0,100 L 100,100 L 100,0 Z\"/>\n" +
"</g>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkPolygon("M 50,-20.710678 L -20.710678,50 L 50,120.71068 L 120.71068,50 Z")
.check();
}
public void testPolygonMatrix() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<g transform=\"matrix(0.8,0.2,0.1,0.9,5,10)\">\n" +
"<path fill=\"none\" stroke=\"black\"\n" +
"d=\"M 0,0 L 0,100 L 100,100 L 100,0 Z\"/>\n" +
"</g>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkPolygon("M 5,10 L 15,100 L 95,120 L 85,30 Z")
.check();
}
public void testRect() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<rect fill=\"none\" stroke=\"black\" \n" +
"x=\"10\" y=\"20\" width=\"70\" height=\"80\"/>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkPolygon("M 10,20 L 80,20 L 80,100 L 10,100 Z")
.check();
}
public void testRectRound() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<rect fill=\"none\" stroke=\"black\" \n" +
"x=\"10\" y=\"20\" rx=\"10\" ry=\"20\" width=\"70\" height=\"80\"/>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkPolygon("M 70,20 C 75.52285,20 80,28.954304 80,40 L 80,80 C 80,91.04569 75.52285,100 70,100 L 20,100 C 14.477152,100 10,91.04569 10,80 L 10,40 C 10,28.954304 14.477152,20 20,20 Z")
.check();
}
public void testCircle() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<g transform=\"matrix(0.8,0.2,0.1,0.9,5,10)\">\n" +
"<circle fill=\"none\" stroke=\"black\" \n" +
"cx=\"50\" cy=\"60\" r=\"30\" />\n" +
"</g>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkPolygon("M 27,68 C 28.656855,82.91169 40.745167,97.686295 54,101 C 67.25484,104.313705 76.65685,94.91169 75,80 C 73.34315,65.08831 61.254833,50.31371 48,47 C 34.745167,43.68629 25.343145,53.08831 27,68 Z")
.check();
}
public void testScale() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
"<g transform=\"scale(2,3)\">\n" +
"<line fill=\"none\" stroke=\"black\" \n" +
"x1=\"10\" y1=\"20\" x2=\"80\" y2=\"70\" />\n" +
"</g>\n" +
"</svg>")).create();
new CSDChecker(custom)
.checkLine(20, 60, 160, 210)
.check();
}
//*****************************************************************************************************
@ -191,6 +291,21 @@ public class SvgImporterTest extends TestCase {
return this;
}
public CSDChecker checkLine(int x1, int y1, int x2, int y2) {
checker.add(new Checker() {
@Override
public void check(Drawable d) {
assertTrue(d instanceof CustomShapeDescription.LineHolder);
CustomShapeDescription.LineHolder l = (CustomShapeDescription.LineHolder) d;
assertEquals(x1, l.getP1().x);
assertEquals(y1, l.getP1().y);
assertEquals(x2, l.getP2().x);
assertEquals(y2, l.getP2().y);
}
});
return this;
}
private static class TestPin {
private final int x;
private final int y;
@ -222,8 +337,22 @@ public class SvgImporterTest extends TestCase {
public void check(Drawable d) {
assertTrue("no polygon found", d instanceof CustomShapeDescription.PolygonHolder);
final Polygon polygon = ((CustomShapeDescription.PolygonHolder) d).getPolygon();
assertEquals("wrong polygon shape", should.toString(), polygon.toString());
assertEquals("wrong evanOdd mode", should.getEvenOdd(), polygon.getEvenOdd());
ArrayList<VectorInterface> shouldPoints = new ArrayList<>();
should.traverse(shouldPoints::add);
ArrayList<VectorInterface> isPoints = new ArrayList<>();
polygon.traverse(isPoints::add);
//System.out.println(polygon);
assertEquals("not the correct polygon size", shouldPoints.size(), isPoints.size());
for (int i = 0; i < shouldPoints.size(); i++) {
VectorInterface sh = shouldPoints.get(i);
VectorInterface is = isPoints.get(i);
assertEquals("x coordinate " + i, sh.getXFloat(), is.getXFloat(), 1e-4);
assertEquals("y coordinate " + i, sh.getYFloat(), is.getYFloat(), 1e-4);
}
}
}