// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea // Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/ package graphtea.graph.old; import graphtea.graph.graph.Edge; import graphtea.graph.graph.GPoint; import graphtea.graph.graph.GraphModel; import graphtea.graph.graph.Vertex; import graphtea.platform.lang.ArrayX; import graphtea.platform.lang.FromStringProvider; import graphtea.platform.preferences.GraphPreferences; import graphtea.platform.preferences.UserDefinedEligiblity; import graphtea.platform.preferences.lastsettings.StorableOnExit; import graphtea.platform.preferences.lastsettings.UserModifiableProperty; import java.awt.*; import java.util.HashMap; import java.util.Vector; public class ArrowHandler implements StorableOnExit, UserDefinedEligiblity, FromStringProvider<Arrow> { //I thinked and decided to choose the base arrows to be Polygons. i think it will be enough for the most needs, but it can't handle more complex needs, like arrows that are images. @UserModifiableProperty(displayName = "Default Arrwo Size for Edges") public static Integer arrowSize = 10; /** * draws the arrow of the edge on the graphics * * @param zoomFactor the zoom factor of Graph Model */ public static void paint(Graphics _g, GraphModel gr, Edge e, double zoomFactor) { // new ArrowHandler(); Arrow arrow = e.getArrow(); Graphics2D g = (Graphics2D) _g; double angle = 0d; if (!gr.isEdgesCurved()) angle = e.getAngle(); else { GPoint src = e.source.getLocation(); // it is the center of the vertex GPoint trg = e.target.getLocation(); GPoint ctrlPnt = e.getCurveControlPoint(); double edgecenterx = (src.x + trg.x) / 2; int ctrlPntViewX = (int) (edgecenterx + ctrlPnt.x); double edgecentery = (src.y + trg.y) / 2; int ctrlPntViewY = (int) (edgecentery + ctrlPnt.y); GPoint targetLoc = e.target.getLocation(); angle = Math.atan2((4 * ctrlPntViewY - src.y - trg.y) / 2 - targetLoc.y, (4 * ctrlPntViewX - src.x - trg.x) / 2 - targetLoc.x); if (angle < 0) { // atan2 returns getAngle in phase -pi to pi, which means // we have to convert the answer into 0 to 2pi range. angle += 2 * Math.PI; } } Vertex v2 = e.target; GPoint v2ShapeSize = v2.getSize(); int w = (int) v2ShapeSize.getX(); int h = (int) v2ShapeSize.getY(); double t = Math.atan2(w * Math.sin(angle), h * Math.cos(angle)); GPoint loc = e.target.getLocation(); int x2 = (int) ((zoomFactor * loc.x) + ((w / 2) * Math.cos(t))); int y2 = (int) ((zoomFactor * loc.y) + ((h / 2) * Math.sin(t))); // g.drawLine((int)loc.x-30, (int)loc.y-30, (int)loc.x+30, (int)loc.y+30); g.translate(x2 + 1, y2 + 1); g.rotate(angle + Math.PI); arrow.paintArrow(g, arrowSize, arrowSize); g.rotate(-angle - Math.PI); g.translate(-x2 - 1, -y2 - 1); } public static PolygonArrow defaultArrow; static { //create and add default arrows int xPoints[] = {0, -15, -15}; int yPoints[] = {0, -15 / 2, 15 / 2}; defaultArrow = new PolygonArrow(new Polygon(xPoints, yPoints, 3), "Default"); PolygonArrow ar1 = new PolygonArrow(new Polygon(new int[]{0, -8, -8}, new int[]{0, -4, 4}, 3), "Small"); PolygonArrow ar4 = new PolygonArrow(new Polygon(new int[]{0, -15, -10, -15}, new int[]{0, -7, 0, 7}, 4), "Narrow"); PolygonArrow ar2 = new PolygonArrow(new Polygon(new int[]{0, -15, -5, -15}, new int[]{0, -7, 0, 7}, 4), "Very Narrow"); PolygonArrow ar3 = new PolygonArrow(new Polygon(new int[]{0, -15, -30, -15}, new int[]{0, -7, 0, 7}, 4), "Box"); knownArrows = new Vector<>(); registerArrow(defaultArrow); registerArrow(ar1); registerArrow(ar2); registerArrow(ar3); registerArrow(ar4); } public static Vector<Arrow> knownArrows; public static void registerArrow(Arrow arrow) { knownArrows.add(arrow); } public GraphPreferences GraphPrefFactory() { return new GraphPreferences(this.getClass().getSimpleName(), this, "Graph Drawings"); } public HashMap<Object, ArrayX> defineEligibleValuesForSettings(HashMap<Object, ArrayX> objectValues) { ArrayX t = new ArrayX(new Integer(3)); t.addValidValue(new Integer(10)); t.addValidValue(new Integer(20)); t.addValidValue(new Integer(30)); // t.addValidValue(15); try { objectValues.put(this.getClass().getField("arrowSize"), t); } catch (NoSuchFieldException e) { e.printStackTrace(); } return objectValues; } public Arrow fromString(String toString) { for (Arrow s : knownArrows) { if (s.getName().equals(toString)) { return s; } } return null; } }