GraphHelper.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. package de.tu_darmstadt.informatik.tk.scopviz.graphs;
  2. import java.util.Collection;
  3. import java.util.HashMap;
  4. import java.util.Iterator;
  5. import java.util.Random;
  6. import org.graphstream.algorithm.Toolkit;
  7. import org.graphstream.graph.Edge;
  8. import org.graphstream.graph.Element;
  9. import org.graphstream.graph.Node;
  10. import org.graphstream.ui.geom.Point3;
  11. import de.tu_darmstadt.informatik.tk.scopviz.debug.Debug;
  12. import de.tu_darmstadt.informatik.tk.scopviz.main.Layer;
  13. import de.tu_darmstadt.informatik.tk.scopviz.main.Main;
  14. import de.tu_darmstadt.informatik.tk.scopviz.ui.OptionsManager;
  15. public class GraphHelper {
  16. public static MyGraph newMerge(boolean vertical, MyGraph... sources) {
  17. String newID = "Composite";
  18. for (MyGraph g : sources) {
  19. newID = newID.concat("_" + g.getId());
  20. }
  21. MyGraph result = new MyGraph(newID);
  22. for (MyGraph g : sources) {
  23. result.addSubGraph(g);
  24. mergeInto(result, g);
  25. }
  26. return result;
  27. }
  28. /**
  29. * merges the two graphs into one. every Node gets two attributes,
  30. * originalGraph and originalElement which are the ids of the Graph and the
  31. * graphid + "+#" + nodeid
  32. *
  33. * @param target the graph that the source will be merged into
  34. * @param source the graph that will be merged into the traget graph
  35. */
  36. // TODO better way to do scaling
  37. private static void mergeInto(MyGraph target, MyGraph source) {
  38. double targetMinX = target.getMinX();
  39. double targetMaxX = target.getMaxX();
  40. double sourceMinX = source.getMinX();
  41. double sourceMaxX = source.getMaxX();
  42. double scalingFactorX = ((targetMaxX - targetMinX + 1) / (target.getNodeCount() + 1))
  43. / ((sourceMaxX - sourceMinX + 1) / (source.getNodeCount() + 1));
  44. double xOffset = targetMaxX - sourceMinX + 10;
  45. double targetMinY = target.getMinY();
  46. double sourceMinY = source.getMinY();
  47. double scalingFactorY = scalingFactorX;
  48. // adjust Cordinates and Attributes
  49. adjustSourceXCoordinates(source, scalingFactorX, xOffset, sourceMinX);
  50. graphAttribute(target);
  51. graphAttribute(source);
  52. adjustSourceYCoordinates(source, scalingFactorY, targetMinY, sourceMinY);
  53. // Copy Nodes and Edges
  54. HashMap<String, String> newIds = copyNodes(target, source);
  55. copyEdges(target, source, newIds);
  56. }
  57. /**
  58. * copys all edges from one Graph to another adjusting for nodeId changes.
  59. * this must always be called after copyNodes.
  60. *
  61. * @param target the graph that the new node will be added into
  62. * @param source the Graph that has the nodes to be copied
  63. * @param newIds a HashMap that give the new id Values of copied Nodes
  64. */
  65. private static void copyEdges(MyGraph target, MyGraph source, HashMap<String, String> newIds) {
  66. Random ran = new Random();
  67. boolean searchingForId = true;
  68. for (Edge e : source.getEdgeSet()) {
  69. // finding a new ID for the Node
  70. searchingForId = true;
  71. String newId = source.getId() + e.getId();
  72. while (searchingForId) {
  73. if (target.getEdge(newId) == null) {
  74. searchingForId = false;
  75. target.addEdge(newId, newIds.get(e.getSourceNode().getId()), newIds.get(e.getTargetNode().getId()),
  76. e.isDirected());
  77. if (e.getAttribute("originalElement") == null) {
  78. target.getEdge(newId).addAttribute("originalElement", source.getId().concat("+#" + e.getId()));
  79. } else {
  80. target.getEdge(newId).addAttribute("originalElement",
  81. (Object) e.getAttribute("originalElement"));
  82. }
  83. } else {
  84. newId = newId.concat(String.valueOf((char) (ran.nextInt(52) + 'a')));
  85. }
  86. }
  87. for (String s : e.getAttributeKeySet()) {
  88. target.getEdge(newId).addAttribute(s, (Object) e.getAttribute(s));
  89. }
  90. }
  91. }
  92. /**
  93. * copies all Nodes from one Graph to another
  94. * always must be called before copyEdges
  95. *
  96. * @param target the Graph that the Nodes will be copied into
  97. * @param source the graph that the node will be taken from
  98. * @return a HahMap to convert the old id of Nodes to new ones
  99. */
  100. private static HashMap<String, String> copyNodes(MyGraph target, MyGraph source) {
  101. HashMap<String, String> newIds = new HashMap<>();
  102. Random ran = new Random();
  103. boolean searchingForId = true;
  104. for (Node n : source.getNodeSet()) {
  105. // finding a new ID for the Node
  106. searchingForId = true;
  107. String newId = source.getId() + n.getId();
  108. while (searchingForId) {
  109. if (target.getNode(newId) == null) {
  110. searchingForId = false;
  111. target.addNode(newId);
  112. newIds.put(n.getId(), newId);
  113. if (n.getAttribute("originalElement") == null) {
  114. target.getNode(newId).addAttribute("originalElement", source.getId().concat("+#" + n.getId()));
  115. } else {
  116. target.getNode(newId).addAttribute("originalElement",
  117. (Object) n.getAttribute("originalElement"));
  118. }
  119. } else {
  120. newId = newId.concat(String.valueOf((char) (ran.nextInt(52) + 'a')));
  121. }
  122. }
  123. for (String s : n.getAttributeKeySet()) {
  124. target.getNode(newId).addAttribute(s, (Object) n.getAttribute(s));
  125. }
  126. }
  127. return newIds;
  128. }
  129. /**
  130. * adjusts the y coordinates of the source graph so the two are of similar size
  131. * @param g the source graph with unaltered coordinates
  132. * @param scalingFactor the factor that is used to ensure a roughly similiar size between the Graphs
  133. * @param targetMinY the minimal y Coordinate of the target Graph
  134. * @param sourceMinY the minimal y Coordinate of the source Graph
  135. */
  136. private static void adjustSourceYCoordinates(MyGraph g, double scalingFactor, double targetMinY,
  137. double sourceMinY) {
  138. for (Node n : g.getNodeSet()) {
  139. double d = (Double) n.getAttribute("y");
  140. d = d - sourceMinY;
  141. d = d * scalingFactor;
  142. d = d + targetMinY;
  143. n.addAttribute("y", d);
  144. }
  145. }
  146. /**
  147. * gives all Nodes a parameter that has the Id of the Graph they belonged to before the merge.
  148. * if a node already has this attriute it will be ignored
  149. *
  150. * @param g the originalGraph of the Nodes
  151. */
  152. private static void graphAttribute(MyGraph g) {
  153. for (Node n : g.getNodeSet()) {
  154. if (n.getAttribute("originalGraph") == null) {
  155. n.addAttribute("originalGraph", g.getId());
  156. }
  157. }
  158. }
  159. /**
  160. * adjusts the x coordinates of the source graph so the two are of similar size
  161. * @param g the source graph with unaltered coordinates
  162. * @param scalingFactor the factor that is used to ensure a roughly similiar size between the Graphs
  163. * @param xOffset the x distance between the graphs
  164. * @param sourceMinY the minimal x Coordinate of the source Graph
  165. */
  166. private static void adjustSourceXCoordinates(MyGraph g, Double scalingFactor, Double xOffset, Double SourceMinX) {
  167. for (Node n : g.getNodeSet()) {
  168. Double d = (Double) n.getAttribute("x");
  169. d = d - SourceMinX;
  170. d = d * scalingFactor;
  171. d = d + xOffset;
  172. d = d + SourceMinX;
  173. n.addAttribute("x", d);
  174. }
  175. }
  176. /**
  177. * Converts the Coordinates of all Nodes into a saveable and uniform Format.
  178. */
  179. public static void correctCoordinates(MyGraph g) {
  180. Point3 coords;
  181. Node n = null;
  182. Iterator<Node> allNodes = g.getNodeIterator();
  183. while (allNodes.hasNext()) {
  184. n = allNodes.next();
  185. if (n.hasAttribute("xyz")) {
  186. coords = Toolkit.nodePointPosition(n);
  187. n.setAttribute("x", coords.x);
  188. propagateAttribute(g, n, "x", coords.x);
  189. n.setAttribute("y", coords.y);
  190. propagateAttribute(g, n, "y", coords.y);
  191. n.removeAttribute("xyz");
  192. }
  193. }
  194. }
  195. /**
  196. * Converts the weight property into a label to display on the Graph.
  197. * Removes all labels if that option is set
  198. */
  199. public static void handleEdgeWeight(MyGraph g) {
  200. if (!Layer.UNDERLAY.equals(g.getAttribute("layer"))) {
  201. return;
  202. }
  203. Edge e = null;
  204. Iterator<Edge> allEdges = g.getEdgeIterator();
  205. while (allEdges.hasNext()) {
  206. e = allEdges.next();
  207. if (!e.hasAttribute("weight")) {
  208. e.addAttribute("weight", OptionsManager.getDefaultWeight());
  209. }
  210. if (OptionsManager.isWeightShown()) {
  211. e.setAttribute("ui.label", e.getAttribute("weight").toString());
  212. } else {
  213. e.removeAttribute("ui.label");
  214. }
  215. }
  216. }
  217. /**
  218. * adds default to all Nodes and converts yEd attributes to regular ones.
  219. *
  220. * @param g
  221. * the graph that the attributes will be added onto
  222. */
  223. public static void setAllDefaults(MyGraph g) {
  224. for (Node n : g.getNodeSet()) {
  225. // general defaults
  226. if (!n.hasAttribute("ui.label")) {
  227. n.addAttribute("ui.label", "");
  228. }
  229. if (!n.hasAttribute("typeofNode") || n.getAttribute("typeofNode").equals("")) {
  230. n.addAttribute("typeofNode", "standard");
  231. }
  232. // underlay defaults
  233. if (Layer.UNDERLAY.equals(g.getAttribute("layer"))) {
  234. if (!n.hasAttribute("typeofDevice") || n.getAttribute("typeofDevice").equals("")) {
  235. n.addAttribute("typeofDevice", "unknown");
  236. }
  237. if (!n.hasAttribute("lat") || n.getAttribute("long").equals("")) {
  238. n.addAttribute("lat", OptionsManager.getDefaultLat());
  239. }
  240. if (!n.hasAttribute("long") || n.getAttribute("long").equals("")) {
  241. n.addAttribute("long", OptionsManager.getDefaultLong());
  242. }
  243. if (!n.hasAttribute("process-max") || n.getAttribute("process-max").equals("")) {
  244. n.addAttribute("process-max", 0.0);
  245. }
  246. }
  247. // operator defaults
  248. if (Layer.OPERATOR.equals(g.getAttribute("layer"))) {
  249. if (!n.hasAttribute("process-need") || n.getAttribute("process-need").equals("")) {
  250. n.addAttribute("process-need", 0.0);
  251. }
  252. }
  253. }
  254. }
  255. /**
  256. * propagates an Attribute to the Node in the Graph it originated from
  257. *
  258. * @param g the root of the Multigraph
  259. * @param n the Element of the multigraph that was changed
  260. * @param attribute the attribute that was changed
  261. * @param value the value the attribute was changed to
  262. */
  263. public static void propagateAttribute(MyGraph g, Element n, String attribute, Object value) {
  264. if (n.getAttribute("originalElement") == null) {
  265. Debug.out("Debug: Attribute originalElement does not Exist");
  266. return;
  267. }
  268. String origGraph = n.getAttribute("originalElement").toString().split("\\+#")[0];
  269. String origNode = n.getAttribute("originalElement").toString().split("\\+#")[1];
  270. Node oldNode = null;
  271. Edge oldEdge = null;
  272. MyGraph old = null;
  273. Iterator<MyGraph> graphIter = g.getAllSubGraphs().iterator();
  274. while (graphIter.hasNext()) {
  275. old = graphIter.next();
  276. if (old.getId().equals(origGraph)) {
  277. Iterator<Node> nodeIter = old.getNodeIterator();
  278. while (nodeIter.hasNext()) {
  279. oldNode = nodeIter.next();
  280. if (oldNode.getId().equals(origNode)) {
  281. if (value == null) {
  282. oldNode.removeAttribute(attribute);
  283. } else {
  284. oldNode.addAttribute(attribute, value);
  285. }
  286. Debug.out("Debug: propagating successfull");
  287. return;
  288. }
  289. }
  290. Iterator<Edge> edgeIter = old.getEdgeIterator();
  291. while (edgeIter.hasNext()) {
  292. oldEdge = edgeIter.next();
  293. if (oldEdge.getId().equals(origNode)) {
  294. if (value == null) {
  295. oldEdge.removeAttribute(attribute);
  296. } else {
  297. oldEdge.addAttribute(attribute, value);
  298. }
  299. Debug.out("Debug: propagating successfull");
  300. return;
  301. }
  302. }
  303. Debug.out("WARNING: could not find the specified Element " + origNode + " in the Graph " + origGraph,
  304. 2);
  305. return;
  306. }
  307. }
  308. Debug.out("WARNING: could not find the specified Graph " + origGraph, 2);
  309. }
  310. /**
  311. * propagates the deletion of a collection of Elements to the Graph the element originally came from.
  312. *
  313. * @param g the root graph of the multigraph
  314. * @param col the collection that has to be deleted
  315. * @return the id of the graph that the elements were deleted from or null if no change occurred
  316. */
  317. public static String propagateElementDeletion(MyGraph g, Collection<? extends Element> col) {
  318. Iterator<? extends Element> elementIter = col.iterator();
  319. while (elementIter.hasNext()) {
  320. Element e = elementIter.next();
  321. return propagateElementDeletion(g, e);
  322. }
  323. return null;
  324. }
  325. /**
  326. * propagates the deletion of an Element to the Graph it originated from
  327. *
  328. * @param g the root graph of the multigraph
  329. * @param e the element that will be deleted
  330. * @return the id of the graph that the elements were deleted from or null if no change occurred
  331. */
  332. public static String propagateElementDeletion(MyGraph g, Element e) {
  333. if (e.getAttribute("originalElement") == null) {
  334. return null;
  335. }
  336. String origGraph = e.getAttribute("originalElement").toString().split("\\+#")[0];
  337. String origId = e.getAttribute("originalElement").toString().split("\\+#")[1];
  338. Iterator<MyGraph> graphIter = g.getAllSubGraphs().iterator();
  339. while (graphIter.hasNext()) {
  340. MyGraph temp = graphIter.next();
  341. if (temp.getId().equals(origGraph)) {
  342. if (e instanceof Node && temp.getNode(origId) != null) {
  343. temp.removeNode(origId);
  344. return temp.getId();
  345. } else if (e instanceof Edge && temp.getEdge(origId) != null) {
  346. temp.removeEdge(origId);
  347. return temp.getId();
  348. } else {
  349. Debug.out("INFORMATION: could not Delete Element bećause it didn't exist: " + origGraph + ":"
  350. + origId, 1);
  351. }
  352. return null;
  353. }
  354. }
  355. Debug.out("WARNING: could not find the specified Graph " + origGraph, 2);
  356. return null;
  357. }
  358. /**
  359. * propagates the undeletion of an Element
  360. * @param g the root graph of the multigraph
  361. * @param e the element that will be readded
  362. * @param newNodeId the new id of the undeleted Node, only important if elemen is an Edge
  363. * @return the new originalElement Attribute
  364. */
  365. public static String propagateElementUndeletion(MyGraph g, Element e, String newNodeId) {
  366. if (e.getAttribute("originalElement") == null) {
  367. return null;
  368. }
  369. String origGraph = e.getAttribute("originalElement").toString().split("\\+#")[0];
  370. // String origId =
  371. // e.getAttribute("originalElement").toString().split("\\+#")[1];
  372. Iterator<MyGraph> graphIter = g.getAllSubGraphs().iterator();
  373. HashMap<String, Object> attributes = new HashMap<String, Object>();
  374. for (String s : e.getAttributeKeySet()) {
  375. attributes.put(s, e.getAttribute(s));
  376. }
  377. while (graphIter.hasNext()) {
  378. MyGraph temp = graphIter.next();
  379. if (temp.getId().equals(origGraph)) {
  380. String newId = Main.getInstance().getUnusedID(new GraphManager(temp));
  381. if (e instanceof Node) {
  382. temp.addNode(newId);
  383. temp.getNode(newId).addAttributes(attributes);
  384. return temp.getId() + "+#" + newId;// the id of
  385. // Graph+newNode
  386. } else if (e instanceof Edge) {
  387. Edge ed = (Edge) e;
  388. String sourceId = ed.getSourceNode().getAttribute("originalElement").toString()
  389. .split("\\+#")[newNodeId.split("\\+#").length - 1];
  390. String targetId = ed.getTargetNode().getAttribute("originalElement").toString()
  391. .split("\\+#")[newNodeId.split("\\+#").length - 1];
  392. if (temp.getNode(sourceId) == null) {
  393. sourceId = newNodeId.split("\\+#")[newNodeId.split("\\+#").length - 1];
  394. } else {
  395. targetId = newNodeId.split("\\+#")[newNodeId.split("\\+#").length - 1];
  396. }
  397. temp.addEdge(newId, sourceId, targetId, ed.isDirected());
  398. temp.getEdge(newId).addAttributes(attributes);
  399. return temp.getId() + "+#" + newId;// the id of
  400. // graph+newEdge
  401. }
  402. }
  403. }
  404. Debug.out("WARNING: could not find the specified Graph " + origGraph, 2);
  405. return null;
  406. }
  407. }