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 005 package graphlab.plugins.main.core.actions; 006 007 import graphlab.graph.event.GraphEvent; 008 import graphlab.graph.graph.*; 009 import graphlab.graph.ui.GraphRectRegionSelect; 010 import graphlab.platform.core.AbstractAction; 011 import graphlab.platform.core.BlackBoard; 012 import graphlab.plugins.commonplugin.undo.Undoable; 013 import graphlab.plugins.commonplugin.undo.UndoableActionOccuredData; 014 import graphlab.plugins.main.GraphData; 015 import graphlab.plugins.main.core.AlgorithmUtils; 016 017 import java.awt.*; 018 import java.awt.geom.Rectangle2D; 019 import java.util.HashSet; 020 021 /** 022 * A class to transform the seleected vertices using mouse 023 * This class is not completely working yet! 024 * <p/> 025 * Now has conflicts with GraphRectRegionSelect 026 * 027 * @author Azin Azadi 028 */ 029 public class VertexTransformer extends AbstractAction implements PaintHandler<AbstractGraphRenderer>, Undoable { 030 GraphData gd; 031 032 //the moving recangles 033 Rectangle2D.Double up; 034 Rectangle2D.Double down; 035 Rectangle2D.Double left; 036 Rectangle2D.Double right; 037 038 //Center Points of boxes 039 GraphPoint upp, downp, leftp, rightp; 040 public static String IS_TRANSFORMING = "VertexTransformer.isTransforming"; 041 private SubGraph sd; 042 private GraphPoint[] verticesPositionsBackUp; 043 044 double drgStartMouseX, drgStartMouseY; 045 double drgStartWidth, drgStartHeight; 046 double drgFixX, drgFixY; 047 048 /** 049 * the active transforming box , null if it isn't any 050 */ 051 String activeBox; 052 053 public VertexTransformer(BlackBoard blackboard) { 054 super(blackboard); 055 gd = new GraphData(blackboard); 056 listen4Event(GraphEvent.EVENT_KEY); 057 } 058 059 public void performAction(String eventName, Object value) { 060 if (GraphRectRegionSelect.isSelecting) 061 return; 062 063 HashSet<VertexModel> selectedVertices = gd.select.getSelectedVertices(); 064 if (selectedVertices.size() <= 1) 065 return; 066 067 GraphModel g = gd.getGraph(); 068 GraphEvent ge = (GraphEvent) value; 069 070 if (ge.eventType == GraphEvent.DRAGGING_STARTED) { 071 // System.out.println("start drag ***********"); 072 gd.getGraphRenderer().addPostPaintHandler(this); 073 //Gather initial and undo information 074 GraphPoint pos = ge.mousePos; 075 verticesPositionsBackUp = new GraphPoint[g.getVerticesCount()]; 076 for (VertexModel _ : g) { 077 verticesPositionsBackUp[_.getId()] = _.getLocation(); 078 } 079 drgStartMouseX = ge.mousePos.x; 080 drgStartMouseY = ge.mousePos.y; 081 if (up == null)//not initialized yet 082 return; 083 if (up.contains(pos)) { 084 // blackboard.setData(IS_TRANSFORMING, true); 085 activeBox = "up"; 086 drgFixX = leftp.x; 087 drgFixY = downp.y; 088 drgStartWidth = rightp.x - leftp.x; 089 drgStartHeight = -downp.y + upp.y; 090 } 091 if (down.contains(pos)) { 092 // blackboard.setData(IS_TRANSFORMING, true); 093 activeBox = "down"; 094 drgFixX = leftp.x; 095 drgFixY = upp.y; 096 drgStartWidth = rightp.x - leftp.x; 097 drgStartHeight = downp.y - upp.y; 098 } 099 if (left.contains(pos)) { 100 // blackboard.setData(IS_TRANSFORMING, true); 101 activeBox = "left"; 102 drgFixX = rightp.x; 103 drgFixY = upp.y; 104 drgStartWidth = -rightp.x + leftp.x; 105 drgStartHeight = downp.y - upp.y; 106 } 107 if (right.contains(pos)) { 108 activeBox = "right"; 109 drgFixX = leftp.x; 110 drgFixY = upp.y; 111 drgStartWidth = rightp.x - leftp.x; 112 drgStartHeight = downp.y - upp.y; 113 } 114 115 } 116 if (ge.eventType == GraphEvent.DRAGGING) { 117 // System.out.println("drag"); 118 if (activeBox == null) { //if not transforming then exit 119 return; 120 } 121 blackboard.setData(IS_TRANSFORMING, true); 122 123 // System.out.println("active drag"); 124 //process event 125 double dx = 0, dy = 0; 126 if (activeBox.equals("up")) { 127 dy = ge.mousePos.y - drgStartMouseY; 128 } 129 if (activeBox.equals("down")) { 130 dy = ge.mousePos.y - drgStartMouseY; 131 } 132 if (activeBox.equals("left")) { 133 dx = ge.mousePos.x - drgStartMouseX; 134 } 135 if (activeBox.equals("right")) { 136 dx = ge.mousePos.x - drgStartMouseX; 137 } 138 139 //snap 140 //transform vertices 141 // System.out.println(Math.abs((drgStartWidth + dx) - (drgStartHeight + dy))); 142 // System.out.println(Math.abs(drgStartWidth) + dx - Math.abs(drgStartHeight) + dy); 143 int snapAmount = 15; 144 if (abs(abs(drgStartWidth + dx) - abs(drgStartHeight + dy)) < snapAmount) { 145 if (dx == 0) { 146 double d1 = Math.signum(dy) * abs(abs(drgStartWidth) + abs(drgStartHeight)); 147 double d2 = Math.signum(dy) * abs(abs(drgStartHeight) - abs(drgStartWidth)); 148 if (abs(dy - d1) > abs(dy - d2)) { 149 dy = d2; 150 } else { 151 dy = d1; 152 } 153 } else {//dy==0 154 double d1 = Math.signum(dx) * abs(abs(drgStartWidth) + abs(drgStartHeight)); 155 double d2 = Math.signum(dx) * abs(abs(drgStartHeight) - abs(drgStartWidth)); 156 if (abs(dx - d1) > abs(dx - d2)) { 157 dx = d2; 158 } else { 159 dx = d1; 160 } 161 } 162 } 163 164 //transform 165 for (VertexModel v : selectedVertices) { 166 GraphPoint loc = verticesPositionsBackUp[v.getId()]; 167 double vx = loc.x; 168 double vy = loc.y; 169 v.setLocation(new GraphPoint(loc.x + dx * (vx - drgFixX) / drgStartWidth, loc.y + dy * (vy - drgFixY) / drgStartHeight)); 170 } 171 } 172 173 if (ge.eventType == GraphEvent.DROPPED) { 174 // System.out.println("dropped"); 175 //add undo data 176 GraphPoint[] newPos = new GraphPoint[gd.getGraph().getVerticesCount()]; 177 for (VertexModel _ : gd.getGraph()) { 178 newPos[_.getId()] = _.getLocation(); 179 } 180 181 UndoableActionOccuredData uaod = new UndoableActionOccuredData(this); 182 uaod.properties.put("oldPositions", verticesPositionsBackUp); 183 uaod.properties.put("newPositions", newPos); 184 blackboard.setData(UndoableActionOccuredData.EVENT_KEY, uaod); 185 186 blackboard.setData(IS_TRANSFORMING, false); 187 } 188 189 // gd.select.setSelected(sd); 190 } 191 192 private double abs(double dy) { 193 return Math.abs(dy); 194 } 195 196 public void paint(Graphics g, Object destinationComponent, Boolean drawExtras) { 197 HashSet<VertexModel> selectedVertices = gd.select.getSelectedVertices(); 198 if (selectedVertices.size() <= 1) 199 return; 200 201 //just get a backup 202 sd = gd.select.getSelected(); 203 g.setColor(Color.LIGHT_GRAY); 204 Rectangle2D.Double boundingRegion = AlgorithmUtils.getBoundingRegion(selectedVertices); 205 int x = (int) boundingRegion.x; 206 int y = (int) boundingRegion.y; 207 int width = (int) boundingRegion.width; 208 int height = (int) boundingRegion.height; 209 g.drawRoundRect(x, y, width, height, 15, 15); 210 211 int trboxsz = 15; 212 //draw transform boxes 213 upp = new GraphPoint(x + width / 2, y); 214 downp = new GraphPoint(x + width / 2, y + height); 215 leftp = new GraphPoint(x, y + height / 2); 216 rightp = new GraphPoint(x + width, y + height / 2); 217 up = createTransformControlRect(upp, trboxsz); 218 down = createTransformControlRect(downp, trboxsz); 219 left = createTransformControlRect(leftp, trboxsz); 220 right = createTransformControlRect(rightp, trboxsz); 221 222 drawRoundRect(g, up, trboxsz / 3); 223 drawRoundRect(g, down, trboxsz / 3); 224 drawRoundRect(g, left, trboxsz / 3); 225 drawRoundRect(g, right, trboxsz / 3); 226 } 227 228 private Rectangle2D.Double createTransformControlRect(GraphPoint rr, int trboxsz) { 229 return new Rectangle2D.Double(rr.x - trboxsz / 2, rr.y - trboxsz / 2, trboxsz, trboxsz); 230 } 231 232 public static void drawRoundRect(Graphics g, Rectangle2D.Double rect, int arcsize) { 233 g.drawRoundRect((int) rect.x, (int) rect.y, (int) rect.height, (int) rect.width, arcsize, arcsize); 234 235 } 236 237 /** 238 * @return true if the given position is on some of resize boxes according to the graph assigned 239 * to the blackboard, if any of boxes are visible 240 */ 241 public static boolean isPositionOnResizeBoxes(GraphPoint mousPos, BlackBoard b) { 242 Boolean aBoolean = b.getData(IS_TRANSFORMING); 243 if (aBoolean != null && aBoolean) { 244 return true; 245 } 246 247 GraphData gd = new GraphData(b); 248 HashSet<VertexModel> selectedVertices = gd.select.getSelectedVertices(); 249 if (selectedVertices.size() <= 1) 250 return false; 251 252 Rectangle2D.Double boundingRegion = AlgorithmUtils.getBoundingRegion(selectedVertices); 253 int x = (int) boundingRegion.x; 254 int y = (int) boundingRegion.y; 255 int width = (int) boundingRegion.width; 256 int height = (int) boundingRegion.height; 257 258 //the moving recangles 259 Rectangle2D.Double up; 260 Rectangle2D.Double down; 261 Rectangle2D.Double left; 262 Rectangle2D.Double right; 263 264 int trboxsz = 15; 265 //draw transform boxes 266 up = new Rectangle2D.Double(x + width / 2 - trboxsz / 2, y - trboxsz / 2, trboxsz, trboxsz); 267 down = new Rectangle2D.Double(x + width / 2 - trboxsz / 2, y + height - trboxsz / 2, trboxsz, trboxsz); 268 left = new Rectangle2D.Double(x - trboxsz / 2, y + height / 2 - trboxsz / 2, trboxsz, trboxsz); 269 right = new Rectangle2D.Double(x + width - trboxsz / 2, y + height / 2 - trboxsz / 2, trboxsz, trboxsz); 270 271 return up.contains(mousPos) | down.contains(mousPos) | left.contains(mousPos) | right.contains(mousPos); 272 273 } 274 275 public void undo(UndoableActionOccuredData uaod) { 276 GraphPoint verticesPositionsBackUp[] = (GraphPoint[]) uaod.properties.get("oldPositions"); 277 GraphModel g = gd.getGraph(); 278 if (g.getVerticesCount() != verticesPositionsBackUp.length) { 279 System.err.println("Graph has changed, Undo can not be done"); 280 return; 281 } 282 283 int i = 0; 284 for (VertexModel v : g) { 285 v.setLocation(verticesPositionsBackUp[i++]); 286 } 287 288 } 289 290 public void redo(UndoableActionOccuredData uaod) { 291 GraphPoint newPos[] = (GraphPoint[]) uaod.properties.get("newPositions"); 292 GraphModel g = gd.getGraph(); 293 if (g.getVerticesCount() != this.verticesPositionsBackUp.length) { 294 System.err.println("Graph has changed, Undo can not be done"); 295 return; 296 } 297 298 int i = 0; 299 for (VertexModel v : g) { 300 v.setLocation(newPos[i++]); 301 } 302 303 } 304 }