edu.uci.ics.jung.algorithms.layout3d.AbstractLayout.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.algorithms.layout3d.AbstractLayout.java

Source

/*
 * Copyright (c) 2003, the JUNG Project and the Regents of the University of
 * California All rights reserved.
 * 
 * This software is open-source under the BSD license; see either "license.txt"
 * or http://jung.sourceforge.net/license.txt for a description.
 * 
 * Created on Jul 7, 2003
 * 
 */
package edu.uci.ics.jung.algorithms.layout3d;

import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.media.j3d.BoundingSphere;
import javax.vecmath.Point3f;

import org.apache.commons.collections15.Transformer;
import org.apache.commons.collections15.map.LazyMap;

import edu.uci.ics.jung.graph.Graph;

/**
 * Implements some of the dirty work of writing a layout algorithm, allowing
 * the user to express their major intent more simply. When writing a <tt>Layout</tt>,
 * there are many shared tasks: handling tracking locked nodes, applying
 * filters, and tracing nearby vertices. This package automates all of those.
 * 
 * @author Danyel Fisher, Scott White
 * @param <V>
 */
public abstract class AbstractLayout<V, E> implements Layout<V, E> {

    /**
     * a set of vertices that should not move in relation to the
     * other vertices
     */
    private Set<V> dontmove = new HashSet<V>();

    private BoundingSphere size;
    private Graph<V, E> graph;

    protected Map<V, Point3f> locations = LazyMap.decorate(new HashMap<V, Point3f>(),
            new Transformer<V, Point3f>() {
                public Point3f transform(V arg0) {
                    return new Point3f();
                }
            });

    /**
     * Constructor. Initializes the current size to be 100x100, both the graph
     * and the showing graph to the argument, and creates the <tt>dontmove</tt>
     * set.
     * 
     * @param g
     */
    protected AbstractLayout(Graph<V, E> graph) {
        this.graph = graph;
    }

    protected AbstractLayout(Graph<V, E> graph, Transformer<V, Point3f> initializer) {
        this.graph = graph;
        this.locations = LazyMap.decorate(new HashMap<V, Point3f>(), initializer);
    }

    protected AbstractLayout(Graph<V, E> graph, BoundingSphere size) {
        this.graph = graph;
        this.size = size;
    }

    protected AbstractLayout(Graph<V, E> graph, Transformer<V, Point3f> initializer, BoundingSphere size) {
        this.graph = graph;
        this.locations = LazyMap.decorate(new HashMap<V, Point3f>(), initializer);
        this.size = size;
    }

    public void setGraph(Graph<V, E> graph) {
        this.graph = graph;
        if (size != null && graph != null) {
            initialize();
        }
    }

    /**
     * When a visualization is resized, it presumably wants to fix the
     * locations of the vertices and possibly to reinitialize its data. The
     * current method calls <tt>initializeLocations</tt> followed by <tt>initialize_local</tt>.
     * TODO: A better implementation wouldn't destroy the current information,
     * but would either scale the current visualization, or move the nodes
     * toward the new center.
     */
    public void setSize(BoundingSphere size) {

        if (size != null && graph != null) {

            BoundingSphere oldSize = this.size;
            this.size = size;
            initialize();

            if (oldSize != null) {
                adjustLocations(oldSize, size);
            }
        }
    }

    private void adjustLocations(BoundingSphere oldSize, BoundingSphere size) {

        float oldWidth = 0;
        float oldHeight = 0;
        float oldDepth = 0;
        float width = 0;
        float height = 0;
        float depth = 0;

        oldWidth = oldHeight = oldDepth = (float) (2 * oldSize.getRadius());
        width = height = depth = (float) (2 * size.getRadius());

        float xOffset = (oldWidth - width) / 2;
        float yOffset = (oldHeight - height) / 2;
        float zOffset = (oldDepth - depth) / 2;

        // now, move each vertex to be at the new screen center
        while (true) {
            try {
                for (V v : getGraph().getVertices()) {
                    offsetVertex(v, xOffset, yOffset, zOffset);
                }
                break;
            } catch (ConcurrentModificationException cme) {
            }
        }
    }

    public boolean isLocked(V v) {
        return dontmove.contains(v);
    }

    public Collection<V> getVertices() {
        return getGraph().getVertices();
    }

    /**
     * Initializer, calls <tt>intialize_local</tt> and <tt>initializeLocations</tt>
     * to start construction process.
     */
    public abstract void initialize();

    public void setInitializer(Transformer<V, Point3f> initializer) {
        this.locations = LazyMap.decorate(new HashMap<V, Point3f>(locations), initializer);
    }

    /**
     * Returns the current size of the visualization space, accoring to the
     * last call to resize().
     * 
     * @return the current size of the screen
     */
    public BoundingSphere getSize() {
        return size;
    }

    /**
     * Returns the Coordinates object that stores the vertex' x and y location.
     * 
     * @param v
     *            A Vertex that is a part of the Graph being visualized.
     * @return A Coordinates object with x and y locations.
     */
    private Point3f getCoordinates(V v) {
        return locations.get(v);
    }

    public Point3f transform(V v) {
        return getCoordinates(v);
    }

    /**
     * Returns the x coordinate of the vertex from the Coordinates object.
     * in most cases you will be better off calling getLocation(Vertex v);
     * @see edu.uci.ics.jung.visualization.layout.Layout#getX(edu.uci.ics.jung.graph.Vertex)
     */
    public double getX(V v) {
        assert getCoordinates(v) != null : "Cannot getX for an unmapped vertex " + v;
        return getCoordinates(v).getX();
    }

    /**
     * Returns the y coordinate of the vertex from the Coordinates object.
     * In most cases you will be better off calling getLocation(Vertex v)
     * @see edu.uci.ics.jung.visualization.layout.Layout#getX(edu.uci.ics.jung.graph.Vertex)
     */
    public double getY(V v) {
        assert getCoordinates(v) != null : "Cannot getY for an unmapped vertex " + v;
        return getCoordinates(v).getY();
    }

    /**
     * @param v a Vertex of interest
     * @return the location point of the supplied vertex
     */
    //   public Point3f getLocation(V v) {
    //       return getCoordinates(v);
    //   }

    /**
     * @param v
     * @param xOffset
     * @param yOffset
     */
    protected void offsetVertex(V v, float xOffset, float yOffset, float zOffset) {
        Point3f c = getCoordinates(v);
        c.set(c.getX() + xOffset, c.getY() + yOffset, c.getZ() + zOffset);
        setLocation(v, c);
    }

    /**
     * Accessor for the graph that represets all vertices.
     * 
     * @return the graph that contains all vertices.
     */
    public Graph<V, E> getGraph() {
        return graph;
    }

    /**
     * Forcibly moves a vertex to the (x,y) location by setting its x and y
     * locations to the inputted location. Does not add the vertex to the
     * "dontmove" list, and (in the default implementation) does not make any
     * adjustments to the rest of the graph.
     */
    public void setLocation(V picked, float x, float y, float z) {
        Point3f coord = getCoordinates(picked);
        coord.set(x, y, z);
    }

    public void setLocation(V picked, Point3f p) {
        Point3f coord = getCoordinates(picked);
        coord.set(p);
    }

    /**
     * Adds the vertex to the DontMove list
     */
    public void lock(V v, boolean state) {
        if (state == true)
            dontmove.add(v);
        else
            dontmove.remove(v);
    }

    public void lock(boolean lock) {
        for (V v : graph.getVertices()) {
            lock(v, lock);
        }
    }
}