Package org.nanograph.drawing

Source Code of org.nanograph.drawing.NanoGraph

/*
* NanoGraph, a small footprint java graph drawing component
*
*    Copyright 2004 Jeroen van Grondelle
*              2013 Xander Uiterlinden
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.nanograph.drawing;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.nanograph.drawing.background.Background;
import org.nanograph.drawing.docking.DockingStrategy;
import org.nanograph.drawing.docking.IntersectionDockingStrategy;
import org.nanograph.drawing.edgerenderer.ArrowEdgeRenderer;
import org.nanograph.drawing.edgerenderer.EdgeRenderer;
import org.nanograph.drawing.graphicsadapter.GraphicsAdapter;
import org.nanograph.drawing.layout.LayoutAlgorithm;
import org.nanograph.drawing.noderenderer.DefaultNodeRenderer;
import org.nanograph.drawing.noderenderer.NodeRenderer;
import org.nanograph.model.GraphModel;

/**
* The NanoGraph class implements the actual graph drawing for all NanoGraph
* components, by inspecting the GraphModel interface and invoking edge and node
* renderers.
*
* @author Jeroen van Grondelle
*/
public class NanoGraph {

  private GraphModel model = null;

  private List highlightNodeSet = new ArrayList();

  private LayoutAlgorithm layoutAlgorithm = null;

  private Background background = null;

  private NodeRenderer defaultNodeRenderer = new DefaultNodeRenderer();

  private HashMap nodeRenderers = new HashMap();

  private HashMap dockingStrategies = new HashMap();

  private HashMap edgeRenderers = new HashMap();

  private EdgeRenderer defaultEdgeRenderer = new ArrowEdgeRenderer();

  private DockingStrategy defaultDockingStrategy = new IntersectionDockingStrategy();

  private Object selectedEdge = null;

  private boolean renderEdges = true;
 
  private boolean renderEdgesBehindNodes = true;

  /**
   * @param renderEdges
   *            The renderEdges to set.
   */
  public void setRenderEdges(boolean renderEdges) {
    this.renderEdges = renderEdges;
  }

  public NanoGraph() {
  }

  public List getHighlightNodeSet() {
    return highlightNodeSet;
  }

  public void setHighlightNodeSet(List highlightNodeSet) {
    this.highlightNodeSet = highlightNodeSet;
  }

  public Object getSelectedEdge() {
    return selectedEdge;
  }

  public void setSelectedEdge(Object selectedEdge) {
    this.selectedEdge = selectedEdge;
  }

  public void setModel(GraphModel model) {
    this.model = model;
    if (layoutAlgorithm != null) {
      layoutAlgorithm.layout(this);
    }
  }

  public GraphModel getModel() {
    return model;
  }

  public void setLayout(LayoutAlgorithm layout) {
    this.layoutAlgorithm = layout;
    if (model != null && layout != null) {
      layoutAlgorithm.layout(this);
    }
  }

  public void paintGraph(GraphicsAdapter gc) {
    // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    // RenderingHints.VALUE_ANTIALIAS_ON);
    if (model == null) {
      return;
    }
    calculateBounds(gc);

    if (background != null) {
      background.drawBackground(gc, getGraphWidth(), getGraphHeight());
    }
   
    if (renderEdges && renderEdgesBehindNodes) {
      for (int t = 0; t < model.getNodeCount(); t++) {
        paintEdgesForNode(gc, model.getNode(t));
      }
    }

    Object node = null;
    // render nodes
    for (int t = 0; t < model.getNodeCount(); t++) {
      node = model.getNode(t);
      if (highlightNodeSet != null && highlightNodeSet.contains(node)) {
        getNodeRenderer(node).renderSelected(gc, node, model.getLocation(node));
      } else {
        getNodeRenderer(node).render(gc, node, model.getLocation(node));
      }
      if (renderEdges && !renderEdgesBehindNodes) {
        paintEdgesForNode(gc, node);
      }
    }
  }

  private void paintEdgesForNode(GraphicsAdapter gc, Object node) {
    Object destinationNode;
    Object edge;
    Object type;
    Point2D fromLocation;
    Point2D toLocation;
    Point2D dockingPointStart;
    Point2D dockingPointEnd;
    for (int r = 0; r < model.getEdgeTypeCount(node); r++) {
      type = model.getEdgeType(node, r);
      for (int s = 0; s < model.getEdgeCount(node, type); s++) {
        edge = model.getEdge(node, type, s);
        fromLocation = model.getLocation(node);
        destinationNode = model.getDestinationNode(node, type, s);
        toLocation = model.getLocation(destinationNode);
        dockingPointStart = getDockingStrategy(node).getDockingPoint(getNodeRenderer(node).getNodeBounds(gc, node, fromLocation), toLocation);
        dockingPointEnd = getDockingStrategy(destinationNode).getDockingPoint(getNodeRenderer(destinationNode).getNodeBounds(gc, destinationNode, toLocation), model.getLocation(node));
        if (edge.equals(selectedEdge)) {
          getEdgeRenderer(edge).renderSelected(gc, edge, dockingPointStart, dockingPointEnd);
        } else {
          getEdgeRenderer(edge).render(gc, edge, dockingPointStart, dockingPointEnd);
        }
      }
    }
  }

  public void paintOutline(GraphicsAdapter gc) {
    if (model == null) {
      return;
    }
    calculateBounds(gc);

    Object node = null, type = null;

    for (int t = 0; t < model.getNodeCount(); t++) {
      node = model.getNode(t);
      for (int r = 0; r < model.getEdgeTypeCount(node); r++) {
        type = model.getEdgeType(node, r);

        for (int s = 0; s < model.getEdgeCount(node, type); s++) {
          // draw line
          Point2D from = model.getLocation(node);
          Point2D to = model.getLocation(model.getDestinationNode(node, type, s));
          gc.drawLine(from.getX(), from.getY(), to.getX(), to.getY());
        }
      }
    }

    for (int t = 0; t < model.getNodeCount(); t++) {
      node = model.getNode(t);
      Rectangle2D rect = getNodeBounds(node);
      if (rect != null) {
        gc.fillRectangle(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
      }
    }
  }

  // //////////////////////////////
  // renderers

  public void registerNodeRenderer(Class c, NodeRenderer r) {
    nodeRenderers.put(c, r);
  }

  public void registerEdgeRenderer(Class c, EdgeRenderer e) {
    edgeRenderers.put(c, e);
  }

  public void registerDockingStrategy(Class c, DockingStrategy s) {
    dockingStrategies.put(c, s);
  }

  public void removeAllRegisteredDockingStrategies() {
    dockingStrategies.clear();
  }

  private DockingStrategy getDockingStrategy(Object node) {
    if (dockingStrategies.get(node.getClass()) == null)
      return defaultDockingStrategy;
    else
      return (DockingStrategy) dockingStrategies.get(node.getClass());
  }

  private NodeRenderer getNodeRenderer(Object node) {
    if (nodeRenderers.get(node.getClass()) == null)
      return defaultNodeRenderer;
    else
      return (NodeRenderer) nodeRenderers.get(node.getClass());
  }

  private EdgeRenderer getEdgeRenderer(Object edge) {
    EdgeRenderer result = (EdgeRenderer) edgeRenderers.get(edge.getClass());
    return (result != null ? result : defaultEdgeRenderer);
  }

  // ////////////////////////////////////
  // Bounds functions
  Map bounds = new HashMap();

  int width = 0, height = 0;

  /**
   * Refresh all node bounds in the bounds cache
   *
   * @param g
   */
  public void calculateBounds(GraphicsAdapter g) {
    bounds.clear();

    Rectangle2D r = null;
    width = 0;
    height = 0;

    for (int t = 0; t < model.getNodeCount(); t++) {
      // calculate bound
      Object n = model.getNode(t);
      r = getNodeRenderer(n).getNodeBounds(g, n, model.getLocation(n));

      // storfe bound in cache
      bounds.put(n, r);

      // update graph size
      if (r.getMaxX() + 25 > width)
        width = (int) r.getMaxX() + 25;
      if (r.getMaxY() + 25 > height)
        height = (int) r.getMaxY() + 25;
    }
    if (background != null && getBackground().getBounds(g) != null) {
      if (getBackground().getBounds(g).getWidth() > width) {
        width = (int) getBackground().getBounds(g).getWidth();
      }
      if (getBackground().getBounds(g).getHeight() > height) {
        height = (int) getBackground().getBounds(g).getHeight();
      }
    }
  }

  public Rectangle2D getNodeBounds(Object node) {
    Object o = bounds.get(node);
    return o != null ? (Rectangle2D) o : null;
  }

  public Object getNodeForLocation(Point2D p2d) {
    for (int t = model.getNodeCount(); t > 0; t--) {
      Object n = model.getNode(t - 1);
      if (getNodeBounds(n) != null) {
        if (getNodeBounds(n).contains(p2d)) {
          return n;
        }
      }
    }
    return null;
  }

  public Collection getNodesForBounds(Rectangle2D box) {
    Collection result = new HashSet();
    for (int t = 0; t < model.getNodeCount(); t++) {
      Object n = model.getNode(t);

      Rectangle2D nodeBounds = getNodeBounds(n);
      if (nodeBounds != null && box.intersects(nodeBounds)) {
        result.add(n);
      }
    }
    return result;
  }

  public Rectangle2D getBoundsForNodes(Collection nodes) {
    if (nodes.isEmpty())
      return null;
    Iterator iter = nodes.iterator();

    Rectangle2D result = getNodeBounds(iter.next());

    while (iter.hasNext()) {
      Object n = iter.next();
      Rectangle2D boundsForNode = getNodeBounds(n);
      if (boundsForNode != null) {
        result.add(getNodeBounds(n));
      }
    }
    return result;
  }

  public int getGraphWidth() {
    return width;
  }

  public int getGraphHeight() {
    return height;
  }

  // ////////////////////////
  // edge selection
  /**
   * Returns the edge closest to the point
   *
   * @param p2d
   * @return edge closest to p2d
   */
  public Object getEdgeForLocation(Point2D p2d) {
    for (int t = 0; t < model.getNodeCount(); t++) {
      Object fromNode = model.getNode(t);
      Point2D centerOfFrom = getCenterOfNode(fromNode);
      for (int r = 0; r < model.getEdgeTypeCount(fromNode); r++) {
        Object type = model.getEdgeType(fromNode, r);
        for (int s = 0; s < model.getEdgeCount(fromNode, type); s++) {
          Object edge = model.getEdge(fromNode, type, s);
          Object destinationNode = model.getDestinationNode(fromNode, type, s);
          Point2D centerOfTo = getCenterOfNode(destinationNode);
          Rectangle2D nodeBounds = getNodeBounds(fromNode);
          if (nodeBounds != null) {
            Point2D from = getDockingStrategy(fromNode).getDockingPoint(nodeBounds, centerOfTo);
            Point2D to = getDockingStrategy(destinationNode).getDockingPoint(getNodeBounds(destinationNode), centerOfFrom);
            if (distFromEdgeToPoint(from, to, p2d) < 10) {
              return edge;
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * @param theNode
   * @return Point2D of the center of the node
   */
  private Point2D getCenterOfNode(Object theNode) {
    if (theNode != null) {
      Rectangle2D nodeBounds = getNodeBounds(theNode);
      if (nodeBounds != null) {
        double centerXOfFromNode = nodeBounds.getX() + (nodeBounds.getWidth() / 2);
        double centerYOfFromNode = nodeBounds.getY() + (nodeBounds.getHeight() / 2);
        return new Point2D.Double(centerXOfFromNode, centerYOfFromNode);
      }
    }
    return new Point2D.Double(0.0d, 0.0d);
  }

  /**
   * @param from
   *            edge starting point
   * @param to
   *            edge ending point
   * @param p2d
   *            point from which to calculate the distance
   * @return the distance from edge to point
   *
   */
  public double distFromEdgeToPoint(Point2D from, Point2D to, Point2D p2d) {
    double x1 = from.getX();
    double y1 = from.getY();
    double x2 = to.getX();
    double y2 = to.getY();
    double px = p2d.getX();
    double py = p2d.getY();

    if (px < Math.min(x1, x2) - 8 || px > Math.max(x1, x2) + 8 || py < Math.min(y1, y2) - 8 || py > Math.max(y1, y2) + 8) {
      return Double.MAX_VALUE;
    }

    double dist = Double.MAX_VALUE;
    if (x1 - x2 != 0)
      dist = Math.abs((y2 - y1) / (x2 - x1) * (px - x1) + (y1 - py));
    if (y1 - y2 != 0)
      dist = Math.min(dist, Math.abs((x2 - x1) / (y2 - y1) * (py - y1) + (x1 - px)));

    return dist;
  }

  // ////////////////////////
  // getters and setters

  public Background getBackground() {
    return background;
  }

  public void setBackground(Background background) {
    this.background = background;
  }

  public DockingStrategy getDefaultDockingStrategy() {
    return defaultDockingStrategy;
  }

  public void setDefaultDockingStrategy(DockingStrategy defaultDockingStrategy) {
    this.defaultDockingStrategy = defaultDockingStrategy;
  }

  public EdgeRenderer getDefaultEdgeRenderer() {
    return defaultEdgeRenderer;
  }

  public void setDefaultEdgeRenderer(EdgeRenderer defaultEdgeRenderer) {
    this.defaultEdgeRenderer = defaultEdgeRenderer;
  }

  public NodeRenderer getDefaultNodeRenderer() {
    return defaultNodeRenderer;
  }

  public void setDefaultNodeRenderer(NodeRenderer defaultNodeRenderer) {
    this.defaultNodeRenderer = defaultNodeRenderer;
  }

  public Collection getNodes() {
    return bounds.keySet();
  }
 
  public boolean isRenderEdgesBehindNodes() {
    return renderEdgesBehindNodes;
  }

  public void setRenderEdgesBehindNodes(boolean renderEdgesBehindNodes) {
    this.renderEdgesBehindNodes = renderEdgesBehindNodes;
  }
}
TOP

Related Classes of org.nanograph.drawing.NanoGraph

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.