*******************************************************************************/
package org.simantics.diagram.connection;
-import gnu.trove.list.array.TDoubleArrayList;
-import gnu.trove.map.hash.THashMap;
-import gnu.trove.map.hash.TObjectIntHashMap;
-import gnu.trove.set.hash.THashSet;
-
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.PrintStream;
import java.io.Serializable;
import org.simantics.diagram.connection.segments.Segment;
import org.simantics.diagram.connection.splitting.SplittedRouteGraph;
+import gnu.trove.list.array.TDoubleArrayList;
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.THashSet;
+
public class RouteGraph implements Serializable {
private static final long serialVersionUID = 2004022454972623908L;
routeLine.collectSegments(segments);
return segments;
}
+
+ public Segment findNearestSegment(double x, double y) {
+ Segment nearest = null;
+ double minDistanceSq = Double.MAX_VALUE;
+
+ for (Segment segment : getSegments()) {
+ RoutePoint p1 = segment.p1;
+ RoutePoint p2 = segment.p2;
+
+ double distanceSq = Line2D.ptSegDistSq(p1.x, p1.y, p2.x, p2.y, x, y);
+ if (distanceSq < minDistanceSq) {
+ minDistanceSq = distanceSq;
+ nearest = segment;
+ }
+ }
+ return nearest;
+ }
+
+ public Point2D findNearestPoint(double x, double y) {
+ Segment nearest = findNearestSegment(x, y);
+ if (nearest == null) return null;
+
+ RoutePoint p1 = nearest.p1;
+ RoutePoint p2 = nearest.p2;
+
+ double d = Math.pow(p2.x - p1.x, 2.0) + Math.pow(p2.y - p1.y, 2.0);
+
+ if (d == 0) {
+ return new Point2D.Double(p1.x, p1.y);
+ } else {
+ double u = ((x - p1.x) * (p2.x - p1.x) + (y - p1.y) * (p2.y - p1.y)) / d;
+ if (u > 1.0) {
+ return new Point2D.Double(p2.x, p2.y);
+ } else if (u <= 0.0) {
+ return new Point2D.Double(p1.x, p1.y);
+ } else {
+ return new Point2D.Double(p2.x * u + p1.x * (1.0-u), (p2.y * u + p1.y * (1.0- u)));
+ }
+ }
+ }
public Path2D getPath2D() {
Path2D result = new Path2D.Double();
package org.simantics.modeling.ui.diagram.style;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.variable.Variable;
import org.simantics.db.layer0.variable.Variables;
+import org.simantics.diagram.connection.RouteGraph;
import org.simantics.diagram.elements.DecorationSVGNode;
import org.simantics.diagram.elements.SVGNode;
+import org.simantics.diagram.handler.Paster;
+import org.simantics.diagram.handler.Paster.RouteLine;
import org.simantics.diagram.profile.StyleBase;
+import org.simantics.diagram.stubs.DiagramResource;
import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
import org.simantics.issues.Severity;
import org.simantics.issues.common.IssueResourcesContexts;
import org.simantics.modeling.ui.Activator;
import org.simantics.modeling.ui.diagram.style.IssueDecorationStyle.IssueResult;
import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.g2d.nodes.ConnectionNode;
import org.simantics.scenegraph.g2d.nodes.Decoration;
+import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode;
import org.simantics.scenegraph.profile.EvaluationContext;
import org.simantics.scenegraph.profile.common.ProfileVariables;
import org.simantics.scenegraph.utils.NodeUtil;
+import org.simantics.structural.stubs.StructuralResource2;
import org.simantics.utils.datastructures.map.Tuple;
return null;
List<Resource> contexts = getContexts(graph, element);
- AffineTransform transform = DiagramGraphUtil.getAffineTransform(graph, element);
Map<Severity, List<Resource>> issuesBySeverity = graph.syncRequest(new ListModelIssuesBySeverity(model, true, true, Severity.NOTE),
TransientCacheListener.<Map<Severity, List<Resource>>>instance());
List<Resource> issues = issuesBySeverity.get(severity);
if (issues != null) {
Set<Resource> issueContexts = graph.syncRequest(new IssueResourcesContexts(issues));
- if (!Collections.disjoint(issueContexts, contexts))
- return new IssueResult(severity, transform);
+ if (!Collections.disjoint(issueContexts, contexts)) {
+ return new IssueResult(severity, getIdentifier(graph, runtimeDiagram, element));
+ }
}
}
return null;
}
+ private static Object getIdentifier(ReadGraph graph, Resource runtimeDiagram, Resource element) throws DatabaseException {
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ if (graph.isInstanceOf(element, DIA.RouteGraphConnection)) {
+ Collection<Resource> connectors = graph.getObjects(element, DIA.HasConnector);
+ Collection<Resource> routeNodes = graph.getObjects(element, DIA.HasInteriorRouteNode);
+
+ // This is needed to make this query result change every time the underlying element changes visually.
+ Set<Object> identifier = new HashSet<Object>(connectors.size() + routeNodes.size());
+
+ for (Resource connector : connectors) {
+ for (Resource connectedTo : graph.getObjects(connector, STR.Connects)) {
+ if (!connectedTo.equals(element)) {
+ AffineTransform at = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, connectedTo, DIA.HasDynamicTransform, false);
+ identifier.add(at);
+ }
+ }
+ }
+ for (Resource routeLine : routeNodes) {
+ RouteLine rl = Paster.readRouteLine(graph, routeLine);
+ identifier.add(rl);
+ }
+ return identifier;
+ } else {
+ return DiagramGraphUtil.getAffineTransform(graph, element);
+ }
+ }
+
@Override
public void applyStyleForNode(EvaluationContext observer, INode node, IssueResult result) {
if (result == null) {
protected AffineTransform getDecorationPosition(INode node) {
Rectangle2D bounds = NodeUtil.getLocalBounds(node, Decoration.class);
+ if (node instanceof ConnectionNode) {
+ for (INode child : ((ConnectionNode)node).getSortedNodes()) {
+ if (child instanceof RouteGraphNode) {
+ RouteGraphNode rgn = (RouteGraphNode) child;
+ RouteGraph rg = rgn.getRouteGraph();
+ Point2D nearest = rg.findNearestPoint(bounds.getCenterX(), bounds.getCenterY());
+ if (nearest != null) {
+ return AffineTransform.getTranslateInstance(nearest.getX(), nearest.getY());
+ }
+ }
+ }
+ }
double tx = bounds.getX();
double ty = bounds.getY();
return AffineTransform.getTranslateInstance(tx, ty);
* element moves.
*/
public static class IssueResult extends Tuple {
- public IssueResult(Severity severity, AffineTransform transform) {
- super(severity, transform);
+ public IssueResult(Severity severity, Object identifier) {
+ super(severity, identifier);
}
public Severity getSeverity() {
return (Severity) getField(0);