001    // GraphLab Project: http://graphlab.sharif.edu
002    // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
003    // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/
004    package graphlab.plugins.visualization.treevisualizations;
005    
006    import graphlab.graph.graph.EdgeModel;
007    import graphlab.graph.graph.GraphModel;
008    import graphlab.graph.graph.VertexModel;
009    import graphlab.library.BaseVertexProperties;
010    import graphlab.platform.preferences.lastsettings.UserModifiableProperty;
011    import graphlab.plugins.visualization.corebasics.extension.VisualizationExtension;
012    import graphlab.ui.UIUtils;
013    
014    import java.awt.geom.Point2D;
015    import java.util.HashMap;
016    import java.util.HashSet;
017    import java.util.Iterator;
018    import java.util.Vector;
019    
020    /**
021     * @author Rouzbeh Ebrahimi
022     */
023    public class CircularTreeVisualization implements VisualizationExtension {
024        String event = UIUtils.getUIEventKey("CircularTreeVisualization");
025        public Vector<VertexModel> visitedVertices = new Vector<VertexModel>();
026        public HashSet<VertexModel> placedVertices = new HashSet<VertexModel>();
027        public HashMap<VertexModel, Point2D> vertexPlaces = new HashMap<VertexModel, Point2D>();
028        VertexModel root;
029        public Vector<VertexModel> children = new Vector<VertexModel>();
030        public HashMap<VertexModel, Integer> vertexHeights = new HashMap<VertexModel, Integer>();
031        @UserModifiableProperty(displayName = "Circular Tree Visualization Radius", obeysAncestorCategory = false
032                , category = "Visualization Options")
033        public static Integer radius = 80;
034    
035        private VertexModel findAppropriateRoot(GraphModel g) {
036            VertexModel root = g.getAVertex();
037            Iterator<VertexModel> ei = g.iterator();
038            for (; ei.hasNext();) {
039                VertexModel e = ei.next();
040                root = findHigherVertex(e, root);
041            }
042            return root;
043        }
044    
045        private VertexModel findHigherVertex(VertexModel v1, VertexModel v2) {
046            Vector<VertexModel> t1 = new Vector<VertexModel>();
047            Vector<VertexModel> t2 = new Vector<VertexModel>();
048            t1.add(v1);
049            t2.add(v2);
050            int i = maxHeight(t1, 0);
051            vertexHeights.put(v1, i);
052            int j = maxHeight(t2, 0);
053            vertexHeights.put(v2, i);
054            if (i > j) {
055                return v1;
056            } else {
057                return v2;
058            }
059        }
060    
061        private int maxHeight(Vector<VertexModel> currentLevel, int maxLevel) {
062    
063            Vector<VertexModel> nextLevel = new Vector<VertexModel>();
064            for (VertexModel v : currentLevel) {
065                v.setMark(true);
066                Iterator<EdgeModel> em = g.edgeIterator(v);
067                for (; em.hasNext();) {
068                    EdgeModel e = em.next();
069                    VertexModel v2 = e.source;
070                    if (!v2.getMark()) {
071                        nextLevel.add(v2);
072                        v2.setMark(true);
073                    }
074                }
075            }
076            maxLevel++;
077            if (nextLevel.size() != 0) {
078                return maxHeight(nextLevel, maxLevel);
079            } else {
080                return maxLevel;
081            }
082        }
083    
084        static GraphModel g;
085    
086        /* public void performJob(Event eventName, Object value) {
087    visitedVertices = new Vector<VertexModel>();
088    vertexPlaces = new HashMap<VertexModel, Point2D>();
089    children = new Vector<VertexModel>();
090    placedVertices = new HashSet<VertexModel>();
091    
092    try {
093        root = findAppropriateRoot(g);
094        unMarkVertices();
095        visitedVertices.add(root);
096        locateAll(visitedVertices, 800, 80);
097        *//*BaseVertexProperties properties = new BaseVertexProperties(root.getColor(), root.getMark());
098                properties.obj = new Double(2*Math.PI);
099                root.setProp(properties);
100                locateAllSubTrees(root, 40, 0);*//*
101                GeneralAnimator t = new GeneralAnimator(vertexPlaces, g, blackboard);
102                t.start();
103            } catch (NullPointerException e) {
104                System.out.println("Graph is Empty");
105    //            e.printStackTrace();
106            }
107    
108        }*/
109    
110        public void locateAllSubTrees(VertexModel v, double radius, double offSet) {
111            if (placedVertices.contains(root)) {
112                double angularSpan = (Double) v.getProp().obj;
113                int numberOfDivides = 1;
114                numberOfDivides = g.getOutDegree(v);
115                if (numberOfDivides == 0) {
116                    return;
117                }
118                Iterator<EdgeModel> iter = g.edgeIterator(v);
119                int j = 0;
120                int sum = 0;
121                for (; iter.hasNext();) {
122                    EdgeModel e = iter.next();
123                    VertexModel v1 = e.source.equals(v) ? e.target : e.source;
124                    if (!placedVertices.contains(v1)) {
125                        sum += g.getOutDegree(v1);
126                    } else {
127                    }
128                }
129                iter = g.edgeIterator(v);
130                for (; iter.hasNext();) {
131                    EdgeModel e = iter.next();
132                    VertexModel v1 = e.source.equals(v) ? e.target : e.source;
133                    if (!placedVertices.contains(v1)) {
134                        double x = 350 + radius * Math.cos((angularSpan * j / (numberOfDivides + 1) + offSet));
135                        double y = 350 + radius * Math.sin((angularSpan * j / (numberOfDivides + 1) + offSet));
136                        double newOffset = (angularSpan * j / numberOfDivides + offSet);
137                        Point2D.Double newPoint = new Point2D.Double(x, y);
138                        vertexPlaces.put(v1, newPoint);
139                        placedVertices.add(v1);
140                        BaseVertexProperties properties = new BaseVertexProperties(v1.getColor(), v1.getMark());
141                        properties.obj = new Double((angularSpan / sum) * (g.getOutDegree(v)));
142                        v1.setProp(properties);
143                        locateAllSubTrees(v1, 2 * radius, newOffset);
144                        j++;
145    
146                    } else {
147                    }
148    
149                }
150                return;
151            } else {
152                double x = 350;
153                double y = 350;
154                Point2D.Double newPoint = new Point2D.Double(x, y);
155                placedVertices.add(v);
156                vertexPlaces.put(v, newPoint);
157                locateAllSubTrees(v, radius, offSet);
158            }
159        }
160    
161        private void unMarkVertices() {
162            for (VertexModel v : g) {
163                v.setMark(false);
164            }
165        }
166    
167    
168        public Vector<VertexModel> findNextLevelChildren(Vector<VertexModel> currentLevelVertices) {
169            Vector<VertexModel> newChildren = new Vector<VertexModel>();
170            for (VertexModel v : currentLevelVertices) {
171                Iterator<EdgeModel> e = g.edgeIterator(v);
172                for (; e.hasNext();) {
173                    EdgeModel ed = e.next();
174                    VertexModel dest = ed.source;
175                    if (!visitedVertices.contains(dest)) {
176                        newChildren.add(dest);
177                    }
178                }
179            }
180            return newChildren;
181        }
182    
183    
184        public void locateAll(Vector<VertexModel> currentLevelVertices, int width, int radius) {
185            int currentLevelCount = currentLevelVertices.size();
186            Vector<VertexModel> nextLevel = findNextLevelChildren(currentLevelVertices);
187            int nextLevelCount = nextLevel.size();
188            double degree = 360 / currentLevelCount;
189            int j = 0;
190            if (currentLevelCount == 1 && currentLevelVertices.elementAt(0).equals(root)) {
191                Point2D.Double newPoint = new Point2D.Double(350, 350);
192                vertexPlaces.put(root, newPoint);
193    
194            } else {
195                for (VertexModel v : currentLevelVertices) {
196                    double x = 350 + radius * Math.cos((Math.PI / 180) * (j * degree));
197                    double y = 350 + radius * Math.sin((Math.PI / 180) * (j * degree));
198                    Point2D.Double newPoint = new Point2D.Double(x, y);
199                    vertexPlaces.put(v, newPoint);
200                    j++;
201    
202                }
203            }
204    
205            if (!nextLevel.isEmpty()) {
206                visitedVertices.addAll(nextLevel);
207                locateAll(nextLevel, width, radius + radius * 3 / 8);
208            } else {
209                return;
210            }
211        }
212    
213        public String getName() {
214            return "Circular Tree Visualization";
215        }
216    
217        public String getDescription() {
218            return null;  //To change body of implemented methods use File | Settings | File Templates.
219        }/*
220         @param g
221        */
222    
223        public void setWorkingGraph(GraphModel g) {
224            this.g = g;
225        }
226    
227        public HashMap<VertexModel, Point2D> getNewVertexPlaces() {
228            visitedVertices = new Vector<VertexModel>();
229            vertexPlaces = new HashMap<VertexModel, Point2D>();
230            children = new Vector<VertexModel>();
231            placedVertices = new HashSet<VertexModel>();
232    
233            try {
234                root = findAppropriateRoot(g);
235                unMarkVertices();
236                visitedVertices.add(root);
237                locateAll(visitedVertices, 800, radius);
238                /*BaseVertexProperties properties = new BaseVertexProperties(root.getColor(), root.getMark());
239                properties.obj = new Double(2*Math.PI);
240                root.setProp(properties);
241                locateAllSubTrees(root, 40, 0);*/
242    
243            } catch (NullPointerException e) {
244                System.out.println("Graph is Empty");
245    //            e.printStackTrace();
246            }
247            return vertexPlaces;
248        }
249    
250        public HashMap<EdgeModel, Point2D> getNewEdgeCurveControlPoints() {
251            return null;  //To change body of implemented methods use File | Settings | File Templates.
252        }
253    }