- RouteGraph rg = new RouteGraph();\r
-\r
- // Default capacity should be enough for common cases.\r
- Set<EdgeResource> links = new THashSet<EdgeResource>();\r
- Map<Object, RouteNode> nodeByData = new THashMap<Object, RouteNode>();\r
-\r
- // Load all route graph interior RouteNodes: route lines and points\r
- for (Resource interiorNode : graph.getObjects(connection, DIA.HasInteriorRouteNode)) {\r
- if (graph.isInstanceOf(interiorNode, DIA.RouteLine)) {\r
- Boolean isHorizontal = graph.getRelatedValue(interiorNode, DIA.IsHorizontal, Bindings.BOOLEAN);\r
- Double position = graph.getRelatedValue(interiorNode, DIA.HasPosition, Bindings.DOUBLE);\r
- RouteLine line = rg.addLine(isHorizontal, position);\r
- line.setData( RouteGraphConnection.serialize(graph, interiorNode) );\r
-\r
- nodeByData.put( interiorNode, line );\r
-\r
- for (Resource connectedTo : graph.getObjects(interiorNode, DIA.AreConnected)) {\r
- links.add( new EdgeResource(interiorNode, connectedTo) );\r
- }\r
- } else if (graph.isInstanceOf(interiorNode, DIA.RoutePoint)) {\r
- // Not supported yet. Ignore.\r
- }\r
- }\r
-\r
- Rectangle2D bounds = new Rectangle2D.Double();\r
- Map<Resource, Resource> connectorToModeledAttachment = null;\r
-\r
- // Primarily the loader will believe what modeling rules say about\r
- // connector attachment relations.\r
- // \r
- // If modeling rules decide nothing, then we simply believe what the\r
- // the attachment relations in the graph say.\r
- // \r
- // Special case 1: connection with two (2) terminals\r
- // If the attachment of one of two terminals is decided by modeling\r
- // rules, the other attachment shall be the opposite of the decided\r
- // attachment (see forcedAttachmentRelation below).\r
- // \r
- // Special case 2: connected to a flag\r
- // If the attached element is a flag and modeling rules say nothing\r
- // about it, believe the direction stated by the flag type.\r
-\r
- Collection<Statement> toConnectorStatements = graph.getStatements(connection, DIA.HasConnector);\r
- int terminalCount = 0;\r
-\r
- // See if modeling rules judge any of the connection terminal attachments.\r
- if (modelingRules != null) {\r
- for (Statement toConnector : toConnectorStatements) {\r
- Resource connector = toConnector.getObject();\r
-\r
- Statement terminalStm = findTerminalStatement(graph, connection, connector);\r
- if (terminalStm == null)\r
- // Ignore broken connector: attached to the connection but not to any terminal.\r
- continue;\r
-\r
- Resource terminalElement = terminalStm.getObject();\r
- Resource connectionRelation = graph.getPossibleInverse(terminalStm.getPredicate());\r
- if (connectionRelation == null)\r
- continue;\r
-\r
- ++terminalCount;\r
-\r
- IAttachmentRelationMap map = modelingRules.getAttachmentRelations(graph, connection);\r
- Resource attachment = map.get(graph, new CPTerminal(terminalElement, connectionRelation));\r
- if (attachment != null) {\r
- // Primary: believe modeling rules\r
- if (connectorToModeledAttachment == null)\r
- connectorToModeledAttachment = new THashMap<Resource, Resource>(toConnectorStatements.size());\r
- connectorToModeledAttachment.put(connector, attachment);\r
- if (DEBUG)\r
- System.out.println("modeling rules decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")");\r
- } else if (graph.isInstanceOf(terminalElement, DIA.Flag)) {\r
- // Secondary: believe flag type\r
- attachment = resolveFlagAttachment(graph, connection, terminalElement, modelingRules);\r
- if (attachment != null) {\r
- if (connectorToModeledAttachment == null)\r
- connectorToModeledAttachment = new THashMap<Resource, Resource>(toConnectorStatements.size());\r
- connectorToModeledAttachment.put(connector, attachment);\r
- if (DEBUG)\r
- System.out.println("flag type decided attachment: " + NameUtils.getSafeName(graph, attachment, true) + " for (" + NameUtils.toString(graph, toConnector, true) + ") & (" + NameUtils.toString(graph, terminalStm, true) + ")");\r
- }\r
- }\r
- }\r
- }\r
-\r
- if (connectorToModeledAttachment == null)\r
- connectorToModeledAttachment = Collections.emptyMap();\r
-\r
- Resource forcedAttachmentRelation = null;\r
- if (terminalCount == 2 && connectorToModeledAttachment.size() == 1) {\r
- forcedAttachmentRelation = getInverseAttachment(graph, connectorToModeledAttachment.values().iterator().next());\r
- if (DEBUG)\r
- System.out.println("set forced attachment: " + NameUtils.getSafeLabel(graph, forcedAttachmentRelation));\r
- }\r
-\r
- Resource connectionType = graph.getPossibleObject(connection, STR.HasConnectionType); \r
-\r
- // Needed to support ConnectionEntity#getTerminalConnections\r
- Set<BackendConnection> backendConnections = new THashSet<BackendConnection>(toConnectorStatements.size(), 0.75f);\r
-\r
- // Load all node terminal connections as RouteTerminals\r
- for (Statement toConnector : toConnectorStatements) {\r
- Resource connector = toConnector.getObject();\r
- Resource attachmentRelation = toConnector.getPredicate();\r
- if (DEBUG)\r
- System.out.println("original attachment relation: " + NameUtils.getSafeLabel(graph, attachmentRelation));\r
-\r
- Statement terminalStm = findTerminalStatement(graph, connection, connector);\r
- if (terminalStm == null)\r
- // Ignore broken connector: attached to the connection but not to any terminal.\r
- continue;\r
-\r
- Resource terminalElement = terminalStm.getObject();\r
- Resource terminalElementType = graph.getPossibleType(terminalElement, DIA.Element);\r
- if (terminalElementType == null)\r
- // Ignore non-element terminal elements\r
- continue;\r
-\r
- Resource connectionRelation = graph.getPossibleInverse(terminalStm.getPredicate());\r
- if (connectionRelation == null)\r
- continue;\r
-\r
- // Discover node and terminal this connector is connected to.\r
- TerminalMap terminals = graph.syncRequest(DiagramRequests.elementTypeTerminals(terminalElementType),\r
- TransientCacheListener.<TerminalMap>instance());\r
- Resource terminal = terminals.getTerminal(connectionRelation);\r
- if (terminal == null) {\r
- System.err.println(getClass().getSimpleName()\r
- + ": Could not find terminal for connection point "\r
- + NameUtils.getSafeName(graph, connectionRelation, true)\r
- + " in element "\r
- + NameUtils.getSafeName(graph, terminalElement, true)); \r
- continue;\r
- }\r
-\r
- double[] position = graph.getRelatedValue(connector, DIA.HasRelativeLocation, Bindings.DOUBLE_ARRAY);\r
- if (position.length != 2)\r
- position = new double[] { 0, 0 };\r
-\r
- if (DEBUG) {\r
- System.out.println("terminalStm: " + NameUtils.toString(graph, terminalStm));\r
- System.out.println("terminal: " + graph.getURI(terminalStm.getPredicate()));\r
- }\r
- AffineTransform terminalElementTr = DiagramGraphUtil.getDynamicWorldTransform(graph, diagramRuntime, terminalElement);\r
- if (DEBUG)\r
- System.out.println("terminalElementTr: " + terminalElementTr);\r
-\r
- double x = terminalElementTr.getTranslateX();\r
- double y = terminalElementTr.getTranslateY();\r
- double minx = x-1, miny = y-1, maxx = x+1, maxy = y+1;\r
- int direction = 0x0;\r
-\r
- // Use modelingRules to ascertain the proper attachmentRelation\r
- // for this terminal connection, if available.\r
- Resource att = connectorToModeledAttachment.get(connector);\r
- if (att != null) {\r
- attachmentRelation = att;\r
- if (DEBUG)\r
- System.out.println("modeling rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));\r
- } else if (forcedAttachmentRelation != null) {\r
- attachmentRelation = forcedAttachmentRelation;\r
- if (DEBUG)\r
- System.out.println("forced rules attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));\r
- }\r
- if (DEBUG)\r
- System.out.println("decided attachment: " + NameUtils.getSafeLabel(graph, attachmentRelation));\r
-\r
- // Get element bounds to decide allowed terminal direction(s)\r
- IElement te = graph.syncRequest(DiagramRequests.getElement(canvas, diagram, terminalElement, null));\r
- ElementUtils.getElementBounds(te, bounds);\r
- {\r
- Shape shp = org.simantics.g2d.utils.GeometryUtils.transformShape(bounds, terminalElementTr);\r
- bounds.setFrame(shp.getBounds2D());\r
- }\r
-\r
- // Expand bounds by 2mm to make the connections enter the terminals\r
- // at a straight angle and from a distance instead of coming in\r
- // "horizontally".\r
- GeometryUtils.expandRectangle(bounds, 2);\r
- minx = bounds.getMinX();\r
- miny = bounds.getMinY();\r
- maxx = bounds.getMaxX();\r
- maxy = bounds.getMaxY();\r
-\r
- AffineTransform terminalPos = DiagramGraphUtil.getDynamicAffineTransform(graph, terminalElement, terminal);\r
- //AffineTransform terminalPos2 = DiagramGraphUtil.getAffineTransform(graph, terminal);\r
- if (terminalPos != null) {\r
- if (DEBUG) {\r
- System.out.println("terminalPos: " + terminalPos);\r
- //System.out.println("terminalPos2: " + terminalPos2);\r
- }\r
- terminalElementTr.concatenate(terminalPos);\r
- if (DEBUG)\r
- System.out.println("terminalElementTr: " + terminalElementTr);\r
- x = terminalElementTr.getTranslateX();\r
- y = terminalElementTr.getTranslateY();\r
- }\r
-\r
- Integer allowedDirections = graph.getPossibleRelatedValue(terminal, DIA.Terminal_AllowedDirections, Bindings.INTEGER);\r
- if (allowedDirections != null) {\r
- direction |= allowedDirections;\r
- direction = RouteGraphUtils.rotateDirection(direction, terminalElementTr);\r
- } else {\r
- direction |= RouteGraphConnectionClass.shortestDirectionOutOfBounds(x, y, bounds);\r
- }\r
- //System.out.println("DIR(" + x + ", " + y + ", " + bounds + "): " + Integer.toHexString(direction));\r
-\r
- backendConnections.add(\r
- new BackendConnection(\r
- toEdgeEnd(graph, attachmentRelation, EdgeEnd.Begin),\r
- terminalElement,\r
- terminal)\r
- );\r
-\r
- if (direction == 0)\r
- // Accept any horizontal/vertical direction if nothing is defined\r
- direction = 0xf;\r
-\r
- if (graph.<Boolean>getRelatedValue(connector, DIA.Connector_straight, Bindings.BOOLEAN))\r
- direction |= RouteTerminal.DIR_DIRECT;\r
- // FIXME: routegraph crashes if this is done for all terminals regardless of the amount of terminals.\r
-\r
- if (DEBUG)\r
- System.out.println("load line style: " + NameUtils.getSafeLabel(graph, attachmentRelation));\r
- ILineEndStyle endStyle = loadLineEndStyle(graph, attachmentRelation, connectionType, TAIL);\r
-\r
- RouteTerminal routeTerminal = rg.addTerminal(x, y, minx, miny, maxx, maxy, direction, endStyle);\r
- routeTerminal.setData( RouteGraphConnection.serialize(graph, connector) );\r
-\r
- nodeByData.put( connector, routeTerminal );\r
-\r
- for (Resource connectedTo : graph.getObjects(connector, DIA.AreConnected)) {\r
- links.add( new EdgeResource(connectedTo, connector) );\r
- }\r
- }\r
-\r
- // Finish route graph loading by Linking route nodes together\r
- for (EdgeResource link : links) {\r
- RouteNode n1 = nodeByData.get(link.first());\r
- RouteNode n2 = nodeByData.get(link.second());\r
- if (n1 == null || n2 == null) {\r
- System.err.println("Stray connection link found: " + link.toString(graph));\r
- continue;\r
- }\r
- rg.link(n1, n2);\r
- }\r