+ // 3.1. Ensure that all mapped route nodes in the target connection\r
+ // are tagged with MOD.IsTemplatized. Future synchronization\r
+ // can then take advantage of this information to more easily\r
+ // decide which parts of the connection are originated from\r
+ // the template and which are not.\r
+ changed |= markMappedRouteNodesTemplatized(graph, s2t.values());\r
+\r
+ // 4. Add temporarily disconnected instance-specific connectors\r
+ // back to the synchronized connection. The route line to attach\r
+ // to is based on a simple heuristic.\r
+ if (instanceOnlyConnectors != null) {\r
+ if (originalSourceToRouteLine.isEmpty()) {\r
+ // If there are 0 route lines in the template connection,\r
+ // then one must be added to the instance connection.\r
+ // This can only happen if the template connection is\r
+ // simple, i.e. just between two terminals without any\r
+ // custom routing.\r
+\r
+ // Attach all target connection connectors to the newly created route line\r
+ Resource rl = cu.newRouteLine(targetConnection, null, null);\r
+ for (Resource sourceConnector : sourceConnectors) {\r
+ Resource targetConnector = s2t.get(sourceConnector);\r
+ graph.deny(targetConnector, DIA.AreConnected);\r
+ graph.claim(targetConnector, DIA.AreConnected, DIA.AreConnected, rl);\r
+ }\r
+\r
+ // Copy orientation and position for new route line from original target route lines.\r
+ // This is a simplification that will attach any amount of route lines in the original\r
+ // target connection into just one route line. There is room for improvement here\r
+ // but it will require a more elaborate algorithm to find and cut the non-templatized\r
+ // route lines as well as connectors out of the connection before synchronizing it.\r
+ //\r
+ // TODO: This implementation chooses the added route line position at random if\r
+ // there are multiple route lines in the target connection.\r
+ if (!originalTargetToRouteLine.isEmpty()) {\r
+ RouteLine originalRl = originalTargetToRouteLine.values().iterator().next();\r
+ setRouteLine(graph, rl, originalRl);\r
+ }\r
+\r
+ // Attach the instance specific connectors also to the only route line\r
+ for (Connector connector : instanceOnlyConnectors) {\r
+ graph.claim(targetConnection, connector.attachmentRelation, connector.connector);\r
+ graph.claim(connector.connector, DIA.AreConnected, DIA.AreConnected, rl);\r
+ }\r
+\r
+ changed = true;\r
+ } else {\r
+ for (Connector connector : instanceOnlyConnectors) {\r
+ // Find the route line that most closely matches the original\r
+ // route line that the connector was connected to.\r
+ Resource closestMatch = null;\r
+ double closestDistance = Double.MAX_VALUE;\r
+ if (connector.attachedTo != null) {\r
+ for (Map.Entry<Resource, Paster.RouteLine> sourceLine : originalSourceToRouteLine.entrySet()) {\r
+ double dist = distance(sourceLine.getValue(), connector.attachedTo);\r
+ if (dist < closestDistance) {\r
+ closestMatch = s2t.get(sourceLine.getKey());\r
+ closestDistance = dist;\r
+ }\r
+ }\r
+ } else {\r
+ closestMatch = originalSourceToRouteLine.keySet().iterator().next();\r
+ }\r
+ graph.claim(targetConnection, connector.attachmentRelation, connector.connector);\r
+ graph.claim(connector.connector, DIA.AreConnected, DIA.AreConnected, closestMatch);\r
+ if (closestDistance > 0)\r
+ changed = true;\r
+ typicalInfo.messageLog.add("\t\t\treattached instance-specific connector "\r
+ + NameUtils.getSafeName(graph, connector.connector) + " to nearest existing route line "\r
+ + NameUtils.getSafeName(graph, closestMatch) + " with distance " + closestDistance);\r
+ }\r
+ }\r
+ }\r
+\r