diff --git a/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java b/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java
index e9a2caf87..35f187e8d 100644
--- a/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java
+++ b/src/main/java/de/neemann/digital/draw/graphics/PolygonParser.java
@@ -255,6 +255,20 @@ public class PolygonParser {
*/
//CHECKSTYLE.OFF: ParameterNumberCheck
private void addArc(Polygon p, VectorInterface current, float rx, float ry, float rot, boolean large, boolean sweep, VectorFloat pos) {
+
+ // if rx=0 or ry=0 add a straight line
+ if (rx == 0 || ry == 0) {
+ p.add(pos);
+ return;
+ }
+
+ // take the absolute value of rx, ry
+ if (rx < 0)
+ rx = -rx;
+ if (ry < 0)
+ ry = -ry;
+
+ // transform the ellipse to a circle
Transform tr = Transform.IDENTITY;
if (rx != ry)
tr = TransformMatrix.scale(1, rx / ry);
@@ -270,6 +284,11 @@ public class PolygonParser {
// ellipse is transformed to a circle with radius r
float r = rx;
+ // correct invalid radii
+ final float dist = p1.sub(p2).len();
+ if (dist > r * 2)
+ r = dist / 2;
+
double x1 = p1.getXFloat();
double y1 = p1.getYFloat();
double x2 = p2.getXFloat();
@@ -281,50 +300,55 @@ public class PolygonParser {
double y2q = y2 * y2;
double rq = r * r;
- double x0A = (r * (y1 - y2) * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * sign(x1 - x2) + r * (x1 + x2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q))) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
- double y0A = (r * (y1 + y2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)) - r * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * abs(x1 - x2)) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
- double x0B = (r * (x1 + x2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)) - r * (y1 - y2) * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * sign(x1 - x2)) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
- double y0B = (r * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * abs(x1 - x2) + r * (y1 + y2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q))) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
+ try {
+ double x0A = (r * (y1 - y2) * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * sign(x1 - x2) + r * (x1 + x2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q))) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
+ double y0A = (r * (y1 + y2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)) - r * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * abs(x1 - x2)) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
+ double x0B = (r * (x1 + x2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)) - r * (y1 - y2) * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * sign(x1 - x2)) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
+ double y0B = (r * sqrt(rq * (4 * rq - y1q + y2 * (2 * y1 - y2)) - rq * (x1q - 2 * x1 * x2 + x2q)) * abs(x1 - x2) + r * (y1 + y2) * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q))) / (2 * r * sqrt(rq * (y1q - 2 * y1 * y2 + y2q) + rq * (x1q - 2 * x1 * x2 + x2q)));
- double startA = Math.atan2(y1 - y0A, x1 - x0A);
- double endA = Math.atan2(y2 - y0A, x2 - x0A);
+ double startA = Math.atan2(y1 - y0A, x1 - x0A);
+ double endA = Math.atan2(y2 - y0A, x2 - x0A);
- double startB = Math.atan2(y1 - y0B, x1 - x0B);
- double endB = Math.atan2(y2 - y0B, x2 - x0B);
+ double startB = Math.atan2(y1 - y0B, x1 - x0B);
+ double endB = Math.atan2(y2 - y0B, x2 - x0B);
- double delta = 2 * Math.PI / 12;
- if (!sweep) delta = -delta;
+ double delta = 2 * Math.PI / 12;
+ if (!sweep) delta = -delta;
- if (delta > 0) {
- if (endA < startA) endA += 2 * Math.PI;
- if (endB < startB) endB += 2 * Math.PI;
- } else {
- if (endA > startA) endA -= 2 * Math.PI;
- if (endB > startB) endB -= 2 * Math.PI;
- }
+ if (delta > 0) {
+ if (endA < startA) endA += 2 * Math.PI;
+ if (endB < startB) endB += 2 * Math.PI;
+ } else {
+ if (endA > startA) endA -= 2 * Math.PI;
+ if (endB > startB) endB -= 2 * Math.PI;
+ }
- double sizeA = Math.abs(startA - endA);
- double sizeB = Math.abs(startB - endB);
+ double sizeA = Math.abs(startA - endA);
+ double sizeB = Math.abs(startB - endB);
- double start = startA;
- double end = endA;
- double x0 = x0A;
- double y0 = y0A;
- if (large ^ (sizeA > sizeB)) {
- start = startB;
- end = endB;
- x0 = x0B;
- y0 = y0B;
- }
+ double start = startA;
+ double end = endA;
+ double x0 = x0A;
+ double y0 = y0A;
+ if (large ^ (sizeA > sizeB)) {
+ start = startB;
+ end = endB;
+ x0 = x0B;
+ y0 = y0B;
+ }
- double lastStart = start;
- start += delta;
- while (delta < 0 ^ start < end) {
- addArcPoint(p, lastStart, start, x0, y0, r, invert);
- lastStart = start;
+ double lastStart = start;
start += delta;
+ while (delta < 0 ^ start < end) {
+ addArcPoint(p, lastStart, start, x0, y0, r, invert);
+ lastStart = start;
+ start += delta;
+ }
+ addArcPoint(p, lastStart, end, x0, y0, r, invert);
+
+ } catch (SqrtException e) {
+ p.add(pos);
}
- addArcPoint(p, lastStart, end, x0, y0, r, invert);
}
//CHECKSTYLE.ON: ParameterNumberCheck
@@ -336,8 +360,13 @@ public class PolygonParser {
p.add(c.transform(tr), p1.transform(tr));
}
- private static double sqrt(double x) {
- return Math.sqrt(x);
+ private static double sqrt(double x) throws SqrtException {
+ if (x > 0)
+ return Math.sqrt(x);
+ if (x > -1e-6)
+ return 0;
+
+ throw new SqrtException();
}
private static double sign(double x) {
@@ -394,4 +423,6 @@ public class PolygonParser {
return p;
}
+ private static class SqrtException extends Exception {
+ }
}
diff --git a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/Context.java b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/Context.java
index eb82da17c..3cd28e526 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/Context.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/Context.java
@@ -42,6 +42,7 @@ class Context {
tr = Transform.IDENTITY;
thickness = 1;
color = Color.BLACK;
+ fill = Color.BLACK;
}
private Context(Context parent) {
@@ -50,6 +51,7 @@ class Context {
color = parent.color;
thickness = parent.thickness;
fontSize = parent.fontSize;
+ textAnchor = parent.textAnchor;
fillRuleEvenOdd = parent.fillRuleEvenOdd;
}
@@ -128,7 +130,6 @@ class Context {
return fontSize;
}
-
private interface AttrParser {
void parse(Context c, String value) throws SvgException;
}
diff --git a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java
index 257cc6464..c3fb31b66 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java
@@ -135,7 +135,7 @@ public class SvgImporter {
}
private void drawPolygon(CustomShapeDescription csd, Context c, Polygon polygon) {
- if (c.getFilled() != null)
+ if (c.getFilled() != null && polygon.isClosed())
csd.addPolygon(polygon.transform(c.getTransform()), c.getThickness(), c.getFilled(), true);
if (c.getColor() != null)
csd.addPolygon(polygon.transform(c.getTransform()), c.getThickness(), c.getColor(), false);
@@ -184,10 +184,7 @@ public class SvgImporter {
.add(c.v(x + width, y + height))
.add(c.v(x, y + height));
- if (c.getFilled() != null)
- csd.addPolygon(polygon, c.getThickness(), c.getFilled(), true);
- if (c.getColor() != null)
- csd.addPolygon(polygon, c.getThickness(), c.getColor(), false);
+ drawPolygon(csd, c, polygon);
}
private void drawCircle(CustomShapeDescription csd, Element element, Context c) {
@@ -229,10 +226,7 @@ public class SvgImporter {
.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.addPolygon(poly, c.getThickness(), c.getFilled(), true);
- if (c.getColor() != null)
- csd.addPolygon(poly, c.getThickness(), c.getColor(), false);
+ drawPolygon(csd, c, poly);
}
}
diff --git a/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java b/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java
index 4b1ff7a37..7aaac6d80 100644
--- a/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java
+++ b/src/test/java/de/neemann/digital/draw/shapes/custom/SvgImporterTest.java
@@ -278,6 +278,18 @@ public class SvgImporterTest extends TestCase {
.check();
}
+ public void testInvalidArcRadii() throws IOException, SvgException, PolygonParser.ParserException, PinException {
+ CustomShapeDescription custom = new SvgImporter(
+ in("")).create();
+
+ new CSDChecker(custom)
+ .checkPolygon("M 0,0 L 40,0 Q 40,-16.076952 44.019238,-30 Q 48.038475,-43.92305 55,-51.961525 Q 61.961525,-60 70,-60 Q 78.038475,-60 85,-51.961525 Q 91.961525,-43.92305 95.98076,-30 Q 100,-16.076952 100,-1.469576E-14 L 140,0")
+ .check();
+ }
+
public void testInkscape1() throws IOException, SvgException, PolygonParser.ParserException, PinException {
CustomShapeDescription custom = new SvgImporter(
in("