1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.sysdyn.ui.editor.participant;
\r
14 import java.awt.geom.AffineTransform;
\r
15 import java.awt.geom.Point2D;
\r
16 import java.util.ArrayList;
\r
17 import java.util.Deque;
\r
18 import java.util.Iterator;
\r
19 import java.util.List;
\r
21 import org.simantics.db.Resource;
\r
22 import org.simantics.db.WriteGraph;
\r
23 import org.simantics.db.common.utils.OrderedSetUtils;
\r
24 import org.simantics.db.exception.DatabaseException;
\r
25 import org.simantics.diagram.content.ConnectionUtil;
\r
26 import org.simantics.diagram.participant.ConnectionBuilder;
\r
27 import org.simantics.diagram.participant.ControlPoint;
\r
28 import org.simantics.diagram.stubs.DiagramResource;
\r
29 import org.simantics.diagram.stubs.G2DResource;
\r
30 import org.simantics.diagram.ui.DiagramModelHints;
\r
31 import org.simantics.g2d.diagram.IDiagram;
\r
32 import org.simantics.g2d.diagram.handler.Topology.Terminal;
\r
33 import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil;
\r
34 import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo;
\r
35 import org.simantics.g2d.element.ElementClass;
\r
36 import org.simantics.g2d.element.ElementClasses;
\r
37 import org.simantics.g2d.element.ElementHints;
\r
38 import org.simantics.g2d.element.ElementUtils;
\r
39 import org.simantics.g2d.element.IElement;
\r
40 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
\r
41 import org.simantics.g2d.element.impl.Element;
\r
42 import org.simantics.g2d.elementclass.FlagClass;
\r
43 import org.simantics.layer0.Layer0;
\r
44 import org.simantics.structural2.modelingRules.ConnectionJudgement;
\r
45 import org.simantics.structural2.modelingRules.IModelingRules;
\r
46 import org.simantics.sysdyn.ui.elements.SysdynElementClasses;
\r
47 import org.simantics.sysdyn.ui.elements.ValveFactory;
\r
48 import org.simantics.sysdyn.ui.elements.connections.ConnectionClasses;
\r
49 import org.simantics.utils.datastructures.Pair;
\r
51 public class SysdynConnectionBuilder extends ConnectionBuilder{
\r
53 public SysdynConnectionBuilder(IDiagram diagram) {
\r
60 * @param controlPoints
\r
61 * @param startTerminal
\r
62 * @param endTerminal
\r
63 * @throws DatabaseException
\r
65 public void create(WriteGraph graph, ConnectionJudgement judgment, Deque<ControlPoint> controlPoints,
\r
66 TerminalInfo startTerminal, TerminalInfo endTerminal) throws DatabaseException {
\r
67 // If needs a valve, we will create two separate connections
\r
68 if(needsValve(startTerminal, endTerminal)) {
\r
69 createValveAndConnections(graph, judgment, controlPoints, startTerminal, endTerminal);
\r
71 // If no need for valve, just call createConnection with false on createValve parameter
\r
73 createConnection(graph, judgment, controlPoints, startTerminal, endTerminal, false);
\r
79 * @param controlPoints
\r
80 * @param startTerminal
\r
81 * @param endTerminal
\r
82 * @throws DatabaseException
\r
84 public TerminalInfo createConnection(WriteGraph graph, ConnectionJudgement judgment, Deque<ControlPoint> controlPoints,
\r
85 TerminalInfo startTerminal, TerminalInfo endTerminal, boolean createValve) throws DatabaseException {
\r
86 TerminalInfo newValve = null;
\r
88 this.cu = new ConnectionUtil(graph);
\r
90 // 1. Get diagram connection to construct.
\r
91 Resource connection = getOrCreateConnection(graph, startTerminal, endTerminal);
\r
93 // 2. Add branch points
\r
94 List<Pair<ControlPoint, Resource>> bps = createBranchPoints(graph, connection, controlPoints);
\r
96 // 3. Create edges between branch points.
\r
97 Resource firstBranchPoint = null;
\r
98 Resource lastBranchPoint = null;
\r
99 if (!bps.isEmpty()) {
\r
100 Iterator<Pair<ControlPoint, Resource>> it = bps.iterator();
\r
101 Pair<ControlPoint, Resource> prev = it.next();
\r
102 firstBranchPoint = prev.second;
\r
103 while (it.hasNext()) {
\r
104 Pair<ControlPoint, Resource> next = it.next();
\r
105 cu.connect(prev.second, next.second);
\r
108 lastBranchPoint = prev.second;
\r
111 // 4. Connect start/end terminals if those exist.
\r
112 // If first/lastBranchPoint != null, connect to those.
\r
113 // Otherwise connect the start/end terminals together.
\r
114 Connector startConnector = null;
\r
115 Connector endConnector = null;
\r
116 IElement startFlag = null;
\r
117 IElement endFlag = null;
\r
119 if (startTerminal != null) {
\r
120 startConnector = createConnectorForNode(graph, connection, startTerminal, EdgeEnd.Begin, judgment);
\r
121 } else if (createFlags) {
\r
122 startFlag = createFlag(graph, connection, EdgeEnd.Begin, controlPoints.getFirst(), FlagClass.Type.In, "");
\r
123 ArrayList<Terminal> terminals = new ArrayList<Terminal>();
\r
124 ElementUtils.getTerminals(startFlag, terminals, false);
\r
125 Terminal st = terminals.get(1);
\r
126 startConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(startFlag),
\r
127 st, EdgeEnd.Begin, judgment);
\r
130 if (endTerminal != null) {
\r
131 endConnector = createConnectorForNode(graph, connection, endTerminal, EdgeEnd.End, judgment);
\r
132 } else if (createFlags) {
\r
134 endFlag = createValveElement(graph, connection, EdgeEnd.End, controlPoints.getLast());
\r
136 endFlag = createFlag(graph, connection, EdgeEnd.End, controlPoints.getLast(), FlagClass.Type.Out, "");
\r
137 ArrayList<Terminal> terminals = new ArrayList<Terminal>();
\r
138 ElementUtils.getTerminals(endFlag, terminals, false);
\r
139 Terminal et = terminals.get(0);
\r
140 endConnector = createConnectorForNode(graph, connection, (Resource) ElementUtils.getObject(endFlag),
\r
141 et, EdgeEnd.End, judgment);
\r
144 newValve = new TerminalInfo();
\r
145 newValve.e = endFlag;
\r
146 newValve.t = terminals.get(1);
\r
147 newValve.posElem = TerminalUtil.getTerminalPosOnElement(endFlag, newValve.t);
\r
148 newValve.posDia = TerminalUtil.getTerminalPosOnDiagram(endFlag, newValve.t);
\r
152 if (firstBranchPoint == null || lastBranchPoint == null) {
\r
153 cu.connect(startConnector.getConnector(), endConnector.getConnector());
\r
155 cu.connect(startConnector.getConnector(), firstBranchPoint);
\r
156 cu.connect(lastBranchPoint, endConnector.getConnector());
\r
159 // 5. Finally, set connection type according to modelling rules
\r
160 IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);
\r
161 if (judgment.connectionType != null && modelingRules != null) {
\r
162 modelingRules.setConnectionType(graph, connection, judgment.connectionType);
\r
172 * @param connection
\r
176 * @return an element describing the new created flag resource
\r
177 * @throws DatabaseException
\r
179 public IElement createValveElement(WriteGraph graph, Resource connection, EdgeEnd end, ControlPoint cp) throws DatabaseException {
\r
180 ElementClass valveClass = elementClassProvider.get(SysdynElementClasses.VALVE);
\r
181 IElement valveElement = Element.spawnNew(valveClass);
\r
182 Resource valveClassResource = ElementUtils.checkedAdapt(valveClass, Resource.class);
\r
184 Layer0 L0 = Layer0.getInstance(graph);
\r
185 G2DResource G2D = G2DResource.getInstance(graph);
\r
186 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
188 Resource valve = graph.newResource();
\r
189 graph.claim(valve, L0.InstanceOf, null, valveClassResource);
\r
190 graph.claim(valve, L0.PartOf, diagramResource);
\r
191 valveElement.setHint(ElementHints.KEY_OBJECT, valve);
\r
193 OrderedSetUtils.add(graph, diagramResource, valve);
\r
195 AffineTransform at = AffineTransform.getTranslateInstance(cp.getPosition().getX(), cp.getPosition().getY());
\r
196 valveElement.setHint(ElementHints.KEY_TRANSFORM, at);
\r
197 double[] matrix = new double[6];
\r
198 at.getMatrix(matrix);
\r
199 graph.claimLiteral(valve, DIA.HasTransform, G2D.Transform, matrix);
\r
201 // Put the element on all the currently active layers if possible.
\r
202 if (layerManager != null) {
\r
203 layerManager.removeFromAllLayers(graph, valve);
\r
204 layerManager.putElementOnVisibleLayers(diagram, graph, valve);
\r
207 return valveElement;
\r
210 private boolean needsValve(TerminalInfo startTerminal, TerminalInfo endTerminal) {
\r
211 if (!elementClassProvider.get(ElementClasses.CONNECTION)
\r
212 .equals(elementClassProvider.get(ConnectionClasses.FLOW)))
\r
214 if(startTerminal != null && startTerminal.e != null && startTerminal.e.getElementClass().getId().equals(ValveFactory.class.getSimpleName())) {
\r
216 } else if(endTerminal != null && endTerminal.e != null && endTerminal.e.getElementClass().getId().equals(ValveFactory.class.getSimpleName())) {
\r
222 private void createValveAndConnections(WriteGraph graph, ConnectionJudgement judgment, Deque<ControlPoint> controlPoints,
\r
223 TerminalInfo startTerminal, TerminalInfo endTerminal) throws DatabaseException {
\r
225 ControlPoint cpfirst = controlPoints.getFirst();
\r
226 ControlPoint cplast = controlPoints.getLast();
\r
228 // Set the position in the middle of the route
\r
229 double startX = cpfirst.getPosition().getX();
\r
230 double startY = cpfirst.getPosition().getY();
\r
231 double x = cplast.getPosition().getX();
\r
232 double y = cplast.getPosition().getY();
\r
233 Point2D pos = new Point2D.Double(startX - (startX - x) / 2, startY - (startY - y) / 2);
\r
235 // Replace the last control point with the control point in the middle
\r
236 controlPoints.getLast().setPosition(pos);
\r
238 // Create a connection to a new valve and get the new valve
\r
239 TerminalInfo newValve = createConnection(graph, judgment, controlPoints, startTerminal, null, true);
\r
241 // Replace the last control point with the original control point
\r
242 controlPoints.getLast().setPosition(x, y);
\r
244 // Create a connection starting from the new valve
\r
245 createConnection(graph, judgment, controlPoints, newValve, endTerminal, false);
\r