From 9aff21b64add0a82e3147ec0423c93dd546684f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ulrich=20Sch=C3=B6pp?= <schoepp@fortiss.org>
Date: Mon, 3 Feb 2020 10:42:48 +0100
Subject: [PATCH] Fix coordinate calculation in EllipticBorderLocation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Method getLocation should compute the location on the ellipse border
from the angle (counter-clockwise, starting from the x coordinate). THe
formula that was implemented took the angle on a circle and then scales
it to an ellipse. But this scaling does not preserve angles, so the
resulting point isn't right.

This means that if one starts with a point on the border of the ellipse,
uses getClosestLocationOnBounds and then getLocation, then one does not
get the point that one started with. When dragging an anchorage on an
elliptic component, the anchorage will often not be in the right place.

Issue-Ref: 3924
Issue-Url: https://af3-developer.fortiss.org/issues/3924
Signed-off-by: Ulrich Schöpp <schoepp@fortiss.org>
---
 .../ui/javafx/lwfxef/visual/elliptic/.ratings |  2 +-
 .../elliptic/EllipticBorderLocation.java      | 19 ++++++++++++-------
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/.ratings b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/.ratings
index c2c5235bd..b09199709 100644
--- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/.ratings
+++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/.ratings
@@ -3,5 +3,5 @@ CircularContentVisualBase.java cc3caea328e36e90069b915e413c8e7e9522a939 YELLOW
 CircularDiagramAnchorageVisualBase.java 7a3b92fb1b135c218b9a5e16506acfc74a6b5468 YELLOW
 CurveLinkVisualBase.java 0b8706214320d715966c86a5242ad21c8bf5a315 YELLOW
 CurveSegment.java 445bc2607cb70ae1c788c27ba9fc637dd7df4956 YELLOW
-EllipticBorderLocation.java 1e9b3d42c7fcd5495004fb30b0c499096a839967 YELLOW
+EllipticBorderLocation.java 6775dd54c01f8d76ecf1721185b60b63f1eec6c2 YELLOW
 EllipticContentVisualBase.java dc2fddc9cfe5605bc8a5d09dd862845e360b23f5 YELLOW
diff --git a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/EllipticBorderLocation.java b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/EllipticBorderLocation.java
index 1e9b3d42c..6775dd54c 100644
--- a/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/EllipticBorderLocation.java
+++ b/org.fortiss.tooling.common.ui/src/org/fortiss/tooling/common/ui/javafx/lwfxef/visual/elliptic/EllipticBorderLocation.java
@@ -10,8 +10,6 @@
 package org.fortiss.tooling.common.ui.javafx.lwfxef.visual.elliptic;
 
 import static java.lang.Math.atan2;
-import static java.lang.Math.cos;
-import static java.lang.Math.sin;
 import static java.util.Objects.requireNonNull;
 
 import org.fortiss.tooling.common.ui.javafx.lwfxef.DiagramCoordinate;
@@ -55,12 +53,19 @@ public final class EllipticBorderLocation {
 	 * ellipse center.
 	 */
 	public DiagramCoordinate getLocation() {
-		double rw = radiuses.getWidth();
-		double rh = radiuses.getHeight();
 		double angle = Math.PI * angleInDegree / 180;
-		double x = rw - correction.getWidth() / 2 + rw * cos(angle);
-		double y = rh - correction.getHeight() / 2 - rh * sin(angle);
-		return new DiagramCoordinate(x, y);
+		double rh = radiuses.getWidth();
+		double rv = radiuses.getHeight();
+		DiagramCoordinate middle = new DiagramCoordinate(rh, rv);
+		double cos = Math.cos(angle);
+		double sin = Math.sin(angle);
+		double tan = (sin / cos);
+		// Division by zero will result in tan being Infinity,
+		// which gives the right results for x and y.
+		double x = rh * rv / Math.sqrt(rv * rv + rh * rh * tan * tan);
+		double y = rh * rv * Math.signum(tan) / Math.sqrt(rv * rv / (tan * tan) + rh * rh);
+		return middle.add(x * Math.signum(cos), -y * Math.signum(cos))
+				.subtract(correction.getWidth() / 2.0, correction.getHeight() / 2.0);
 	}
 
 	/**
-- 
GitLab