All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uci.ics.jung.visualization.control.RotatingGraphMousePlugin Maven / Gradle / Ivy

/*
 * Copyright (c) 2005, The JUNG Authors
 *
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either
 * "license.txt" or
 * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 * Created on Mar 8, 2005
 *
 */
package edu.uci.ics.jung.visualization.control;

import edu.uci.ics.jung.visualization.MultiLayerTransformer.Layer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.transform.MutableTransformer;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Collections;

/**
 * RotatingGraphMouse provides the abiity to rotate the graph using the mouse. By default, it is
 * activated by mouse button one drag with the shift key pressed. The modifiers can be overridden so
 * that a different mouse/key combination activates the rotation
 *
 * @author Tom Nelson
 */
public class RotatingGraphMousePlugin extends AbstractGraphMousePlugin
    implements MouseListener, MouseMotionListener {

  /** create an instance with default modifier values */
  public RotatingGraphMousePlugin() {
    this(MouseEvent.BUTTON1_MASK | MouseEvent.SHIFT_MASK);
  }

  /**
   * create an instance with passed zoom in/out values
   *
   * @param modifiers the event modifiers to trigger rotation
   */
  public RotatingGraphMousePlugin(int modifiers) {
    super(modifiers);
    Dimension cd = Toolkit.getDefaultToolkit().getBestCursorSize(16, 16);
    BufferedImage cursorImage = new BufferedImage(cd.width, cd.height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = cursorImage.createGraphics();
    g.addRenderingHints(
        Collections.singletonMap(
            RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
    g.setColor(new Color(0, 0, 0, 0));
    g.fillRect(0, 0, 16, 16);

    int left = 0;
    int top = 0;
    int right = 15;
    int bottom = 15;

    g.setColor(Color.white);
    g.setStroke(new BasicStroke(3));
    // top bent line
    g.drawLine(left + 2, top + 6, right / 2 + 1, top);
    g.drawLine(right / 2 + 1, top, right - 2, top + 5);
    // bottom bent line
    g.drawLine(left + 2, bottom - 6, right / 2, bottom);
    g.drawLine(right / 2, bottom, right - 2, bottom - 6);
    // top arrow
    g.drawLine(left + 2, top + 6, left + 5, top + 6);
    g.drawLine(left + 2, top + 6, left + 2, top + 3);
    // bottom arrow
    g.drawLine(right - 2, bottom - 6, right - 6, bottom - 6);
    g.drawLine(right - 2, bottom - 6, right - 2, bottom - 3);

    g.setColor(Color.black);
    g.setStroke(new BasicStroke(1));
    // top bent line
    g.drawLine(left + 2, top + 6, right / 2 + 1, top);
    g.drawLine(right / 2 + 1, top, right - 2, top + 5);
    // bottom bent line
    g.drawLine(left + 2, bottom - 6, right / 2, bottom);
    g.drawLine(right / 2, bottom, right - 2, bottom - 6);
    // top arrow
    g.drawLine(left + 2, top + 6, left + 5, top + 6);
    g.drawLine(left + 2, top + 6, left + 2, top + 3);
    // bottom arrow
    g.drawLine(right - 2, bottom - 6, right - 6, bottom - 6);
    g.drawLine(right - 2, bottom - 6, right - 2, bottom - 3);

    g.dispose();

    cursor =
        Toolkit.getDefaultToolkit().createCustomCursor(cursorImage, new Point(), "RotateCursor");
  }

  /**
   * save the 'down' point and check the modifiers. If the modifiers are accepted, set the cursor to
   * the 'hand' cursor
   *
   * @param e the event
   */
  public void mousePressed(MouseEvent e) {
    VisualizationViewer vv = (VisualizationViewer) e.getSource();
    boolean accepted = checkModifiers(e);
    down = e.getPoint();
    if (accepted) {
      vv.setCursor(cursor);
    }
  }

  /** unset the down point and change the cursor back to the default */
  public void mouseReleased(MouseEvent e) {
    VisualizationViewer vv = (VisualizationViewer) e.getSource();
    down = null;
    vv.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  }

  /** check the modifiers. If accepted, use the mouse drag motion to rotate the graph */
  public void mouseDragged(MouseEvent e) {
    if (down == null) {
      return;
    }
    VisualizationViewer vv = (VisualizationViewer) e.getSource();
    boolean accepted = checkModifiers(e);
    if (accepted) {
      MutableTransformer modelTransformer =
          vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT);
      // rotate
      vv.setCursor(cursor);

      Point2D center = vv.getCenter();
      Point2D q = down;
      Point2D p = e.getPoint();
      Point2D v1 = new Point2D.Double(center.getX() - p.getX(), center.getY() - p.getY());
      Point2D v2 = new Point2D.Double(center.getX() - q.getX(), center.getY() - q.getY());
      double theta = angleBetween(v1, v2);
      modelTransformer.rotate(
          theta,
          vv.getRenderContext().getMultiLayerTransformer().inverseTransform(Layer.VIEW, center));
      down.x = e.getX();
      down.y = e.getY();

      e.consume();
    }
  }

  /**
   * Returns the angle between two vectors from the origin to points v1 and v2.
   *
   * @param v1 the first point
   * @param v2 the second point
   * @return the angle between two vectors from the origin through points v1 and v2
   */
  protected double angleBetween(Point2D v1, Point2D v2) {
    double x1 = v1.getX();
    double y1 = v1.getY();
    double x2 = v2.getX();
    double y2 = v2.getY();
    // cross product for direction
    double cross = x1 * y2 - x2 * y1;
    int cw = 1;
    if (cross > 0) {
      cw = -1;
    }
    // dot product for angle
    double angle =
        cw
            * Math.acos(
                (x1 * x2 + y1 * y2)
                    / (Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2)));
    if (Double.isNaN(angle)) {
      angle = 0;
    }
    return angle;
  }

  public void mouseClicked(MouseEvent e) {}

  public void mouseEntered(MouseEvent e) {}

  public void mouseExited(MouseEvent e) {}

  public void mouseMoved(MouseEvent e) {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy