X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fconnection%2FRouteGraphConnectionClass.java;h=72b8232c131040ed9951c7d6159fd09c52d95dc4;hp=0a82dd584c1895f120bcb5ada31681ccce5a2730;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/connection/RouteGraphConnectionClass.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/connection/RouteGraphConnectionClass.java index 0a82dd584..72b8232c1 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/connection/RouteGraphConnectionClass.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/connection/RouteGraphConnectionClass.java @@ -1,267 +1,267 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 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: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.diagram.connection; - -import java.awt.Shape; -import java.awt.geom.Rectangle2D; -import java.util.Collection; -import java.util.Collections; - -import org.simantics.diagram.connection.rendering.IRouteGraphRenderer; -import org.simantics.g2d.connection.ConnectionEntity; -import org.simantics.g2d.connection.handler.ConnectionHandler; -import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy; -import org.simantics.g2d.diagram.handler.Topology.Connection; -import org.simantics.g2d.element.ElementClass; -import org.simantics.g2d.element.ElementHints; -import org.simantics.g2d.element.ElementUtils; -import org.simantics.g2d.element.IElement; -import org.simantics.g2d.element.SceneGraphNodeKey; -import org.simantics.g2d.element.handler.InternalSize; -import org.simantics.g2d.element.handler.Outline; -import org.simantics.g2d.element.handler.Pick; -import org.simantics.g2d.element.handler.SceneGraph; -import org.simantics.g2d.element.handler.SelectionOutline; -import org.simantics.g2d.element.handler.impl.ConfigurableEdgeVisuals; -import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline; -import org.simantics.g2d.element.handler.impl.FillColorImpl; -import org.simantics.g2d.element.handler.impl.TextImpl; -import org.simantics.g2d.elementclass.connection.EdgeClass.FixedTransform; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.scenegraph.g2d.nodes.connection.IRouteGraphListener; -import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode; -import org.simantics.utils.datastructures.hints.IHintContext.Key; -import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; - -/** - * An element class for single connection entity elements. A connection entity - * consists of connection edge segments and branch points as its children. - * - * @author Tuukka Lehtonen - */ -public class RouteGraphConnectionClass { - - public static final Key KEY_ROUTEGRAPH = new KeyOf(RouteGraph.class, "ROUTE_GRAPH"); - public static final Key KEY_RENDERER = new KeyOf(IRouteGraphRenderer.class, "ROUTE_GRAPH_RENDERER"); - public static final Key KEY_PICK_TOLERANCE = new KeyOf(Double.class, "PICK_TOLERANCE"); - public static final Key KEY_USE_TOLERANCE_IN_SELECTION = new KeyOf(Boolean.class, "PICK_TOLERANCE_SELECTION"); - public static final Key KEY_RG_LISTENER = new KeyOf(IRouteGraphListener.class, "ROUTE_GRAPH_LISTENER"); - public static final Key KEY_RG_NODE = new SceneGraphNodeKey(RouteGraphNode.class, "ROUTE_GRAPH_NODE"); - - public static final double BOUND_TOLERANCE = 0.9; - - public static final ElementClass CLASS = - ElementClass.compile( - TextImpl.INSTANCE, - - FixedTransform.INSTANCE, - - ConnectionBoundsAndPick.INSTANCE, - ConnectionSelectionOutline.INSTANCE, - ConnectionHandlerImpl.INSTANCE, - ConnectionSceneGraph.INSTANCE, - //SimpleElementLayers.INSTANCE, - - // Exists only loading connection visuals through ConnectionVisualsLoader - ConfigurableEdgeVisuals.DEFAULT, - FillColorImpl.BLACK - ).setId(RouteGraphConnectionClass.class.getSimpleName()); - - - static class ConnectionHandlerImpl implements ConnectionHandler { - - public static final ConnectionHandlerImpl INSTANCE = new ConnectionHandlerImpl(); - - private static final long serialVersionUID = 3267139233182458330L; - - @Override - public Collection getBranchPoints(IElement connection, Collection result) { - return Collections.emptySet(); - } - - @Override - public Collection getChildren(IElement connection, Collection result) { - return Collections.emptySet(); - } - - @Override - public Collection getSegments(IElement connection, Collection result) { - return Collections.emptySet(); - } - - @Override - public Collection getTerminalConnections(IElement connection, Collection result) { - ConnectionEntity ce = connection.getHint(ElementHints.KEY_CONNECTION_ENTITY); - if (ce == null) - return Collections.emptySet(); - return ce.getTerminalConnections(result); - } - - } - - static final class ConnectionSceneGraph implements SceneGraph { - - public static final ConnectionSceneGraph INSTANCE = new ConnectionSceneGraph(); - - private static final long serialVersionUID = 4232871859964883266L; - - @Override - public void init(IElement connection, G2DParentNode parent) { - RouteGraph rg = connection.getHint(KEY_ROUTEGRAPH); - IRouteGraphRenderer renderer = connection.getHint(KEY_RENDERER); - if (rg == null || renderer == null) { - cleanup(connection); - } else { - RouteGraphNode rgn = connection.getHint(KEY_RG_NODE); - if (rgn == null) { - rgn = parent.addNode(ElementUtils.generateNodeId(connection), RouteGraphNode.class); - connection.setHint(KEY_RG_NODE, rgn); - } - rgn.setRouteGraph(rg); - rgn.setRenderer(renderer); - - IRouteGraphListener listener = connection.getHint(KEY_RG_LISTENER); - rgn.setRouteGraphListener(listener); - - Double tolerance = connection.getHint(KEY_PICK_TOLERANCE); - if (tolerance != null) - rgn.setPickTolerance(tolerance); - } - } - - @Override - public void cleanup(IElement connection) { - ElementUtils.removePossibleNode(connection, KEY_RG_NODE); - connection.removeHint(KEY_RG_NODE); - } - } - - static final class ConnectionBoundsAndPick implements InternalSize, Outline, Pick { - - private static final long serialVersionUID = 4232871859964883266L; - - public static final ConnectionBoundsAndPick INSTANCE = new ConnectionBoundsAndPick(); - - // Single-threaded system, should be fine to use this for everything. - Rectangle2D temp = new Rectangle2D.Double(); - - private Shape getSelectionShape(IElement e) { - for (SelectionOutline so : e.getElementClass().getItemsByClass(SelectionOutline.class)) { - Shape shape = so.getSelectionShape(e); - if (shape != null) - return shape; - } - // Using on-diagram coordinates because neither connections nor - // edges have a non-identity transform which means that - // coordinates are always absolute. Therefore branch point - // shape also needs to be calculated in absolute coordinates. - Shape shape = ElementUtils.getElementShapeOrBoundsOnDiagram(e); - return shape; - } - - @Override - public boolean pickTest(IElement e, Shape s, PickPolicy policy) { - RouteGraph rg = getRouteGraph(e); - if (rg == null) - return false; - - Rectangle2D bounds = getBounds(s); - switch (policy) { - case PICK_CONTAINED_OBJECTS: - Shape selectionShape = getSelectionShape(e); - return bounds.contains(selectionShape.getBounds2D()); - case PICK_INTERSECTING_OBJECTS: - double tolerance = 0.0; - if (e.containsHint(KEY_USE_TOLERANCE_IN_SELECTION)) - tolerance = getTolerance(e); - else - tolerance = (bounds.getHeight()+bounds.getHeight()) * 0.25; - Object node = rg.pickLine(bounds.getCenterX(), bounds.getCenterY(), tolerance); - return node != null; - } - return false; - } - - @Override - public Rectangle2D getBounds(IElement e, Rectangle2D size) { - RouteGraph rg = getRouteGraph(e); - if (rg != null) { - if (size == null) - size = new Rectangle2D.Double(); - rg.getBounds(size); - } - return size; - } - - @Override - public Shape getElementShape(IElement e) { - RouteGraph rg = getRouteGraph(e); - return rg == null ? null : rg.getPath2D(); - } - - private Rectangle2D getBounds(Shape shape) { - if (shape instanceof Rectangle2D) - return (Rectangle2D) shape; - return shape.getBounds2D(); - } - - private RouteGraph getRouteGraph(IElement e) { - RouteGraphNode rgn = e.getHint(KEY_RG_NODE); - return rgn == null ? null : rgn.getRouteGraph(); - } - - private double getTolerance(IElement e) { - RouteGraphNode rgn = e.getHint(KEY_RG_NODE); - return rgn.getPickTolerance(); - } - - } - - public static int shortestDirectionOutOfBounds(double x, double y, Rectangle2D bounds) { - double mx = bounds.getMinX(); - double Mx = bounds.getMaxX(); - double my = bounds.getMinY(); - double My = bounds.getMaxY(); - - double up = y - my; - double down = My - y; - double left = x - mx; - double right = Mx - x; - - // Insertion sort - double[] dists = { right, down, left, up }; - byte[] masks = { 0x1, 0x2, 0x4, 0x8 }; - for (int i = 1; i < 4; ++i) { - double value = dists[i]; - byte mask = masks[i]; - int j = i - 1; - while (j >= 0 && dists[j] > value) { - dists[j + 1] = dists[j]; - masks[j + 1] = masks[j]; - --j; - } - dists[j + 1] = value; - masks[j + 1] = mask; - } - - // Construct mask out of the shortest equal directions - int mask = masks[0]; - double value = dists[0] / BOUND_TOLERANCE; - for (int i = 1; i < 4; ++i) { - if (dists[i] > value) - break; - mask |= masks[i]; - } - return mask; - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 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: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.diagram.connection; + +import java.awt.Shape; +import java.awt.geom.Rectangle2D; +import java.util.Collection; +import java.util.Collections; + +import org.simantics.diagram.connection.rendering.IRouteGraphRenderer; +import org.simantics.g2d.connection.ConnectionEntity; +import org.simantics.g2d.connection.handler.ConnectionHandler; +import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy; +import org.simantics.g2d.diagram.handler.Topology.Connection; +import org.simantics.g2d.element.ElementClass; +import org.simantics.g2d.element.ElementHints; +import org.simantics.g2d.element.ElementUtils; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.SceneGraphNodeKey; +import org.simantics.g2d.element.handler.InternalSize; +import org.simantics.g2d.element.handler.Outline; +import org.simantics.g2d.element.handler.Pick; +import org.simantics.g2d.element.handler.SceneGraph; +import org.simantics.g2d.element.handler.SelectionOutline; +import org.simantics.g2d.element.handler.impl.ConfigurableEdgeVisuals; +import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline; +import org.simantics.g2d.element.handler.impl.FillColorImpl; +import org.simantics.g2d.element.handler.impl.TextImpl; +import org.simantics.g2d.elementclass.connection.EdgeClass.FixedTransform; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.nodes.connection.IRouteGraphListener; +import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphNode; +import org.simantics.utils.datastructures.hints.IHintContext.Key; +import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; + +/** + * An element class for single connection entity elements. A connection entity + * consists of connection edge segments and branch points as its children. + * + * @author Tuukka Lehtonen + */ +public class RouteGraphConnectionClass { + + public static final Key KEY_ROUTEGRAPH = new KeyOf(RouteGraph.class, "ROUTE_GRAPH"); + public static final Key KEY_RENDERER = new KeyOf(IRouteGraphRenderer.class, "ROUTE_GRAPH_RENDERER"); + public static final Key KEY_PICK_TOLERANCE = new KeyOf(Double.class, "PICK_TOLERANCE"); + public static final Key KEY_USE_TOLERANCE_IN_SELECTION = new KeyOf(Boolean.class, "PICK_TOLERANCE_SELECTION"); + public static final Key KEY_RG_LISTENER = new KeyOf(IRouteGraphListener.class, "ROUTE_GRAPH_LISTENER"); + public static final Key KEY_RG_NODE = new SceneGraphNodeKey(RouteGraphNode.class, "ROUTE_GRAPH_NODE"); + + public static final double BOUND_TOLERANCE = 0.9; + + public static final ElementClass CLASS = + ElementClass.compile( + TextImpl.INSTANCE, + + FixedTransform.INSTANCE, + + ConnectionBoundsAndPick.INSTANCE, + ConnectionSelectionOutline.INSTANCE, + ConnectionHandlerImpl.INSTANCE, + ConnectionSceneGraph.INSTANCE, + //SimpleElementLayers.INSTANCE, + + // Exists only loading connection visuals through ConnectionVisualsLoader + ConfigurableEdgeVisuals.DEFAULT, + FillColorImpl.BLACK + ).setId(RouteGraphConnectionClass.class.getSimpleName()); + + + static class ConnectionHandlerImpl implements ConnectionHandler { + + public static final ConnectionHandlerImpl INSTANCE = new ConnectionHandlerImpl(); + + private static final long serialVersionUID = 3267139233182458330L; + + @Override + public Collection getBranchPoints(IElement connection, Collection result) { + return Collections.emptySet(); + } + + @Override + public Collection getChildren(IElement connection, Collection result) { + return Collections.emptySet(); + } + + @Override + public Collection getSegments(IElement connection, Collection result) { + return Collections.emptySet(); + } + + @Override + public Collection getTerminalConnections(IElement connection, Collection result) { + ConnectionEntity ce = connection.getHint(ElementHints.KEY_CONNECTION_ENTITY); + if (ce == null) + return Collections.emptySet(); + return ce.getTerminalConnections(result); + } + + } + + static final class ConnectionSceneGraph implements SceneGraph { + + public static final ConnectionSceneGraph INSTANCE = new ConnectionSceneGraph(); + + private static final long serialVersionUID = 4232871859964883266L; + + @Override + public void init(IElement connection, G2DParentNode parent) { + RouteGraph rg = connection.getHint(KEY_ROUTEGRAPH); + IRouteGraphRenderer renderer = connection.getHint(KEY_RENDERER); + if (rg == null || renderer == null) { + cleanup(connection); + } else { + RouteGraphNode rgn = connection.getHint(KEY_RG_NODE); + if (rgn == null) { + rgn = parent.addNode(ElementUtils.generateNodeId(connection), RouteGraphNode.class); + connection.setHint(KEY_RG_NODE, rgn); + } + rgn.setRouteGraph(rg); + rgn.setRenderer(renderer); + + IRouteGraphListener listener = connection.getHint(KEY_RG_LISTENER); + rgn.setRouteGraphListener(listener); + + Double tolerance = connection.getHint(KEY_PICK_TOLERANCE); + if (tolerance != null) + rgn.setPickTolerance(tolerance); + } + } + + @Override + public void cleanup(IElement connection) { + ElementUtils.removePossibleNode(connection, KEY_RG_NODE); + connection.removeHint(KEY_RG_NODE); + } + } + + static final class ConnectionBoundsAndPick implements InternalSize, Outline, Pick { + + private static final long serialVersionUID = 4232871859964883266L; + + public static final ConnectionBoundsAndPick INSTANCE = new ConnectionBoundsAndPick(); + + // Single-threaded system, should be fine to use this for everything. + Rectangle2D temp = new Rectangle2D.Double(); + + private Shape getSelectionShape(IElement e) { + for (SelectionOutline so : e.getElementClass().getItemsByClass(SelectionOutline.class)) { + Shape shape = so.getSelectionShape(e); + if (shape != null) + return shape; + } + // Using on-diagram coordinates because neither connections nor + // edges have a non-identity transform which means that + // coordinates are always absolute. Therefore branch point + // shape also needs to be calculated in absolute coordinates. + Shape shape = ElementUtils.getElementShapeOrBoundsOnDiagram(e); + return shape; + } + + @Override + public boolean pickTest(IElement e, Shape s, PickPolicy policy) { + RouteGraph rg = getRouteGraph(e); + if (rg == null) + return false; + + Rectangle2D bounds = getBounds(s); + switch (policy) { + case PICK_CONTAINED_OBJECTS: + Shape selectionShape = getSelectionShape(e); + return bounds.contains(selectionShape.getBounds2D()); + case PICK_INTERSECTING_OBJECTS: + double tolerance = 0.0; + if (e.containsHint(KEY_USE_TOLERANCE_IN_SELECTION)) + tolerance = getTolerance(e); + else + tolerance = (bounds.getHeight()+bounds.getHeight()) * 0.25; + Object node = rg.pickLine(bounds.getCenterX(), bounds.getCenterY(), tolerance); + return node != null; + } + return false; + } + + @Override + public Rectangle2D getBounds(IElement e, Rectangle2D size) { + RouteGraph rg = getRouteGraph(e); + if (rg != null) { + if (size == null) + size = new Rectangle2D.Double(); + rg.getBounds(size); + } + return size; + } + + @Override + public Shape getElementShape(IElement e) { + RouteGraph rg = getRouteGraph(e); + return rg == null ? null : rg.getPath2D(); + } + + private Rectangle2D getBounds(Shape shape) { + if (shape instanceof Rectangle2D) + return (Rectangle2D) shape; + return shape.getBounds2D(); + } + + private RouteGraph getRouteGraph(IElement e) { + RouteGraphNode rgn = e.getHint(KEY_RG_NODE); + return rgn == null ? null : rgn.getRouteGraph(); + } + + private double getTolerance(IElement e) { + RouteGraphNode rgn = e.getHint(KEY_RG_NODE); + return rgn.getPickTolerance(); + } + + } + + public static int shortestDirectionOutOfBounds(double x, double y, Rectangle2D bounds) { + double mx = bounds.getMinX(); + double Mx = bounds.getMaxX(); + double my = bounds.getMinY(); + double My = bounds.getMaxY(); + + double up = y - my; + double down = My - y; + double left = x - mx; + double right = Mx - x; + + // Insertion sort + double[] dists = { right, down, left, up }; + byte[] masks = { 0x1, 0x2, 0x4, 0x8 }; + for (int i = 1; i < 4; ++i) { + double value = dists[i]; + byte mask = masks[i]; + int j = i - 1; + while (j >= 0 && dists[j] > value) { + dists[j + 1] = dists[j]; + masks[j + 1] = masks[j]; + --j; + } + dists[j + 1] = value; + masks[j + 1] = mask; + } + + // Construct mask out of the shortest equal directions + int mask = masks[0]; + double value = dists[0] / BOUND_TOLERANCE; + for (int i = 1; i < 4; ++i) { + if (dists[i] > value) + break; + mask |= masks[i]; + } + return mask; + } + +}