com.rapidminer.gui.graphs.ShapeBasedTreeLayout.java Source code

Java tutorial

Introduction

Here is the source code for com.rapidminer.gui.graphs.ShapeBasedTreeLayout.java

Source

/**
 * Copyright (C) 2001-2015 by RapidMiner and the contributors
 *
 * Complete list of developers available at our web site:
 *
 *      http://rapidminer.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 */
package com.rapidminer.gui.graphs;

import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Tree;

import java.awt.Dimension;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

/**
 * This layout algorithm takes the shapes of the trees into account and performs a non-overlapping
 * layout.
 * 
 * @author Ingo Mierswa
 */
public class ShapeBasedTreeLayout<V, E> implements Layout<V, E> {

    private static final int DEFAULT_WIDTH = 70;

    private static final int DEFAULT_HEIGHT = 70;

    private static final int MARGIN = 5;

    private Dimension size = new Dimension(600, 600);

    private Forest<V, E> graph;

    protected Map<V, Point2D> locations = LazyMap.decorate(new HashMap<V, Point2D>(),
            new Transformer<V, Point2D>() {

                @Override
                public Point2D transform(V arg0) {
                    return new Point2D.Double();
                }
            });

    public List<V> getAtomics(V p) {
        List<V> v = new ArrayList<V>();
        getAtomics(p, v);
        return v;
    }

    private void getAtomics(V p, List<V> v) {
        for (V c : graph.getSuccessors(p)) {
            if (graph.getSuccessors(c).size() == 0) {
                v.add(c);
            } else {
                getAtomics(c, v);
            }
        }
    }

    private Collection<V> roots;

    private Transformer<V, Shape> shapeTransformer;

    public ShapeBasedTreeLayout(Forest<V, E> g, Transformer<V, Shape> shapeTransformer) {
        this.graph = g;
        this.roots = getRoots(g);
        this.shapeTransformer = shapeTransformer;
        calculateLocations();
    }

    private Collection<V> getRoots(Forest<V, E> forest) {
        Set<V> roots = new HashSet<V>();
        for (Tree<V, E> tree : forest.getTrees()) {
            roots.add(tree.getRoot());
        }
        return roots;
    }

    public Dimension getCurrentSize() {
        return size;
    }

    private void calculateLocations() {
        double xOffset = 100;
        double yOffset = 30;

        if (roots.size() > 0 && graph != null) {
            for (V v : roots) {
                calculateLocations(v, xOffset, yOffset);
                double currentWidth = calculateWidth(v);
                xOffset += currentWidth;
                xOffset += MARGIN;
            }
        }
    }

    void calculateLocations(V v, double xOffset, double yOffset) {
        double currentWidth = calculateWidth(v);

        setPosition(v, xOffset + currentWidth / 2, yOffset);

        // handle children
        yOffset += DEFAULT_HEIGHT;

        int childrenNum = graph.getSuccessors(v).size();
        if (childrenNum != 0) {
            boolean first = true;
            for (V element : graph.getSuccessors(v)) {
                if (!first) {
                    xOffset += MARGIN;
                }

                calculateLocations(element, xOffset, yOffset);

                double totalChildrenWidth = calculateWidth(element);
                xOffset += totalChildrenWidth;

                first = false;
            }
        }
    }

    private double calculateWidth(V v) {
        double childrenWidthSum = 0;
        int childrenNum = graph.getSuccessors(v).size();
        if (childrenNum != 0) {
            boolean first = true;
            for (V element : graph.getSuccessors(v)) {
                if (!first) {
                    childrenWidthSum += MARGIN;
                }
                childrenWidthSum += calculateWidth(element);
                first = false;
            }
        }

        double width = DEFAULT_WIDTH;
        if (this.shapeTransformer != null) {
            Shape shape = this.shapeTransformer.transform(v);
            if (shape != null) {
                width = shape.getBounds().getWidth();
            }
        }
        double size = Math.max(width, childrenWidthSum);
        size = Math.max(0, size);
        return size;
    }

    @Override
    public void setSize(Dimension size) {
        this.size = size;
        calculateLocations();
    }

    private void setPosition(V vertex, double x, double y) {
        locations.get(vertex).setLocation(new Point2D.Double(x, y));
    }

    @Override
    public Graph<V, E> getGraph() {
        return graph;
    }

    @Override
    public Dimension getSize() {
        return size;
    }

    @Override
    public void initialize() {
    }

    @Override
    public boolean isLocked(V v) {
        return false;
    }

    @Override
    public void lock(V v, boolean state) {
    }

    @Override
    public void reset() {
    }

    @Override
    public void setGraph(Graph<V, E> graph) {
        if (graph instanceof Forest) {
            this.graph = (Forest<V, E>) graph;
            calculateLocations();
        } else {
            throw new IllegalArgumentException("graph must be a Forest");
        }
    }

    @Override
    public void setInitializer(Transformer<V, Point2D> initializer) {
    }

    public Point2D getCenter() {
        return new Point2D.Double(size.getWidth() / 2, size.getHeight() / 2);
    }

    @Override
    public void setLocation(V v, Point2D location) {
        locations.get(v).setLocation(location);
    }

    @Override
    public Point2D transform(V v) {
        return locations.get(v);
    }
}