GraphHelper.java 15 KB

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