mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-15 15:58:41 -04:00
fixes bug if invalid arc radii are used
This commit is contained in:
parent
c3b43b753a
commit
c83cb41210
@ -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 {
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,6 +278,18 @@ public class SvgImporterTest extends TestCase {
|
||||
.check();
|
||||
}
|
||||
|
||||
public void testInvalidArcRadii() 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" +
|
||||
"<path fill=\"none\" stroke=\"black\" stroke-width=\"3\"\n" +
|
||||
" d=\"M 0,0 L 40,0 A 10,20,0,1,1,100,0 L 140,0\"/>\n" +
|
||||
"</svg>")).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("<svg viewBox=\"0 0 200 100\" xmlns=\"http://www.w3.org/2000/svg\">\n" +
|
||||
@ -429,7 +441,7 @@ public class SvgImporterTest extends TestCase {
|
||||
ArrayList<VectorInterface> isPoints = new ArrayList<>();
|
||||
polygon.traverse(isPoints::add);
|
||||
|
||||
//System.out.println(polygon);
|
||||
System.out.println(polygon);
|
||||
|
||||
assertEquals("not the correct polygon size", shouldPoints.size(), isPoints.size());
|
||||
for (int i = 0; i < shouldPoints.size(); i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user