From: Tuukka Lehtonen Date: Fri, 25 Nov 2022 11:55:12 +0000 (+0200) Subject: Avoid crashes with fully direct-routed connections X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=7ec1db67928f7dfd22b4cc06f33368838b29e9e8;p=simantics%2Fplatform.git Avoid crashes with fully direct-routed connections Also avoids eternal looping in connection path rendering gitlab #885 (cherry picked from commit 6b2f5a6be2bd75df3cc12fa875174b2d117b8563) Change-Id: I18f251d9e430f7477332b97e6677a936bd429852 --- diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/DegeneratedRoutePoint.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/DegeneratedRoutePoint.java new file mode 100644 index 000000000..57b73e10d --- /dev/null +++ b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/DegeneratedRoutePoint.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2022 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.diagram.connection; + +import gnu.trove.map.hash.THashMap; + +/** + * Route point that is connected to two direct terminals. + * + * @author Hannu Niemisto + */ +public class DegeneratedRoutePoint extends RoutePoint { + + public DegeneratedRoutePoint() { + super(); + } + + public DegeneratedRoutePoint(double x, double y) { + super(x, y); + } + + @Override + DegeneratedRoutePoint copy(THashMap map) { + DegeneratedRoutePoint copy = (DegeneratedRoutePoint) map.get(this); + if (copy == null) { + copy = new DegeneratedRoutePoint(x, y); + map.put(this, copy); + } + return copy; + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteGraph.java b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteGraph.java index 62d3de68f..da1fc702a 100644 --- a/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteGraph.java +++ b/bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/RouteGraph.java @@ -302,6 +302,11 @@ public class RouteGraph implements Serializable { needsUpdate = true; } + private boolean isDirectDirectConnection() { + return !isSimpleConnection && terminals.size() == 2 && terminals.get(0).hasDirectConnection() + && terminals.get(1).hasDirectConnection() && lines.size() <= 1; + } + /** * Updates transient route lines, route link positions * and sorts route points of each route line. @@ -375,6 +380,10 @@ public class RouteGraph implements Serializable { } } } + else if(isFullyDirectConnectionCase()) { + routeDirectDirectOneLineCase(); + return; + } else { caseId = SimpleConnectionUtility.COMPLEX_CONNECTION; routeFromTerminals(false); @@ -394,7 +403,36 @@ public class RouteGraph implements Serializable { line.sortPoints(); } } - + + private boolean isFullyDirectConnectionCase() { + if (lines.size() != 1 && terminals.size() > 0) + return false; + for (RouteTerminal t : terminals) { + if (!t.hasDirectConnection()) + return false; + } + return true; + } + + private void routeDirectDirectOneLineCase() { + RouteLine line = lines.get(0); + double x = 0, y = 0; + double scale = 1 / terminals.size(); + if(line.isHorizontal) { + y = line.position; + for (RouteTerminal t : terminals) + x += t.x; + x *= scale; + } + else { + x = line.position; + for (RouteTerminal t : terminals) + y += t.y; + y *= scale; + } + line.addPoint(new DegeneratedRoutePoint(x, y)); + } + static class Interval { public final double min; public final double max; @@ -471,7 +509,7 @@ public class RouteGraph implements Serializable { public RouteLine pickLine(double x, double y, double tolerance, int mask) { if(needsUpdate) update(); - if(isSimpleConnection && transientLines.isEmpty()) { + if( (isSimpleConnection && transientLines.isEmpty()) || isDirectDirectConnection() ) { if(terminals.size() == 2) { if((mask & PICK_TRANSIENT_LINES) == 0) return null; @@ -1383,16 +1421,14 @@ public class RouteGraph implements Serializable { public void getPath2D(Path2D path) { if(needsUpdate) update(); - - if(isSimpleConnection && transientLines.isEmpty()) { - if(terminals.size() == 2) { - RouteTerminal a = terminals.get(0); - RouteTerminal b = terminals.get(1); - if(a.hasDirectConnection() || b.hasDirectConnection()) { - path.moveTo(a.x, a.y); - path.lineTo(b.x, b.y); - return; - } + + if((isSimpleConnection && transientLines.isEmpty() && terminals.size() == 2) || isDirectDirectConnection()) { + RouteTerminal a = terminals.get(0); + RouteTerminal b = terminals.get(1); + if(a.hasDirectConnection() || b.hasDirectConnection()) { + path.moveTo(a.x, a.y); + path.lineTo(b.x, b.y); + return; } } @@ -1428,8 +1464,14 @@ public class RouteGraph implements Serializable { while(true) { if(cur != curLine.getEnd()) cur = curLine.getEnd(); - else - cur = curLine.getBegin(); + else { + RoutePoint next = curLine.getBegin(); + // Break if stuck at the same RoutePoint. + // This can happen with fully direct-routed connections. + if (next == cur) + return; + cur = next; + } if(begins.remove(cur) != null || !(cur instanceof RouteLink)) { addPathEnd(path, cur, curLine); return;