From fc1c79c597119592c231ff771f9c543d88aebb4a Mon Sep 17 00:00:00 2001 From: James Ball Date: Thu, 6 May 2021 21:29:31 +0100 Subject: [PATCH] Finish implementation of elliptical arcs; now correctly rotating --- pom.xml | 2 +- .../sh/ball/parser/svg/EllipticalArcTo.java | 33 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index 9358aec..0daf093 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ sh.ball osci-render - 1.0.1 + 1.0.2 osci-render diff --git a/src/main/java/sh/ball/parser/svg/EllipticalArcTo.java b/src/main/java/sh/ball/parser/svg/EllipticalArcTo.java index 1f6379b..f1db2fc 100644 --- a/src/main/java/sh/ball/parser/svg/EllipticalArcTo.java +++ b/src/main/java/sh/ball/parser/svg/EllipticalArcTo.java @@ -1,5 +1,6 @@ package sh.ball.parser.svg; +import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.util.ArrayList; import java.util.List; @@ -25,8 +26,6 @@ class EllipticalArcTo { newPoint = isAbsolute ? newPoint : state.currPoint.translate(newPoint); - System.out.println(args.get(i + 2)); - arcs.addAll(createArc( state.currPoint, args.get(i), @@ -51,11 +50,11 @@ class EllipticalArcTo { if (rx == 0 || ry == 0) { return List.of(new Line(start, end)); } - double x0 = start.getX(); - double y0 = start.getY(); + double x1 = start.getX(); + double y1 = start.getY(); // Compute the half distance between the current and the final point - double dx2 = (x0 - x2) / 2.0f; - double dy2 = (y0 - y2) / 2.0f; + double dx2 = (x1 - x2) / 2.0; + double dy2 = (y1 - y2) / 2.0; // Convert theta from degrees to radians theta = (float) Math.toRadians(theta % 360); @@ -69,9 +68,9 @@ class EllipticalArcTo { ry = Math.abs(ry); double Prx = rx * rx; double Pry = ry * ry; - double Px1 = x1prime * x1prime; - double Py1 = y1prime * y1prime; - double d = Px1 / Prx + Py1 / Pry; + double Px1prime = x1prime * x1prime; + double Py1prime = y1prime * y1prime; + double d = Px1prime / Prx + Py1prime / Pry; if (d > 1) { rx = Math.abs(Math.sqrt(d) * rx); ry = Math.abs(Math.sqrt(d) * ry); @@ -83,16 +82,18 @@ class EllipticalArcTo { // Step 2 : Compute (cx', cy') // double sign = (largeArcFlag == sweepFlag) ? -1.0 : 1.0; + // Forcing the inner term to be positive. It should be >= 0 but can sometimes be negative due + // to double precision. double coef = sign * - Math.sqrt(((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1))); + Math.sqrt(Math.abs((Prx * Pry) - (Prx * Py1prime) - (Pry * Px1prime)) / ((Prx * Py1prime) + (Pry * Px1prime))); double cxprime = coef * ((rx * y1prime) / ry); double cyprime = coef * -((ry * x1prime) / rx); // // Step 3 : Compute (cx, cy) from (cx', cy') // - double sx2 = (x0 + x2) / 2.0f; - double sy2 = (y0 + y2) / 2.0f; + double sx2 = (x1 + x2) / 2.0; + double sy2 = (y1 + y2) / 2.0; double cx = sx2 + Math.cos(theta) * cxprime - Math.sin(theta) * cyprime; double cy = sy2 + Math.sin(theta) * cxprime + Math.cos(theta) * cyprime; @@ -125,12 +126,14 @@ class EllipticalArcTo { Arc2D.Float arc = new Arc2D.Float(); arc.x = (float) (cx - rx); arc.y = (float) (cy - ry); - arc.width = (float) (rx * 2.0f); - arc.height = (float) (ry * 2.0f); + arc.width = (float) (rx * 2.0); + arc.height = (float) (ry * 2.0); arc.start = (float) -angleStart; arc.extent = (float) -angleExtent; - return Shape.convert(arc); + AffineTransform transform = AffineTransform.getRotateInstance(theta, arc.getX() + arc.getWidth()/2, arc.getY() + arc.getHeight()/2); + + return Shape.convert(transform.createTransformedShape(arc)); } static List absolute(SvgState state, List args) {