/*
 * Copyright (c) 2005, 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 Mar 8, 2005
 *
 */
package edu.uci.ics.jung.visualization.control;

import java.awt.geom.Point2D;

import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.transform.MutableTransformer;

/** 
 * A scaling control that has a crossover point.
 * When the overall scale of the view and
 * model is less than the crossover point, the scaling is applied
 * to the view's transform and the graph nodes, labels, etc grow
 * smaller. This preserves the overall shape of the graph.
 * When the scale is larger than the crossover, the scaling is
 * applied to the graph layout. The graph spreads out, but the
 * vertices and labels grow no larger than their original size. 
 * 
 * @author Tom Nelson
 */
public class CrossoverScalingControl implements ScalingControl {

    /**
     * Point where scale crosses over from view to layout.
     */
    protected double crossover = 1.0;
    
    /**
     * Sets the crossover point to the specified value.
     */
	public void setCrossover(double crossover) {
	    this.crossover = crossover;
	}

    /**
     * Returns the current crossover value.
     */
    public double getCrossover() {
        return crossover;
    }
    
	/**
     * @see edu.uci.ics.jung.visualization.control.ScalingControl#scale(VisualizationViewer, float, Point2D)
     */
	public void scale(VisualizationViewer vv, float amount, Point2D at) {
	        
	    MutableTransformer layoutTransformer = vv.getLayoutTransformer();
	    MutableTransformer viewTransformer = vv.getViewTransformer();
	    double modelScale = layoutTransformer.getScale();
	    double viewScale = viewTransformer.getScale();
	    double inverseModelScale = Math.sqrt(crossover)/modelScale;
	    double inverseViewScale = Math.sqrt(crossover)/viewScale;
	    double scale = modelScale * viewScale;
	    
	    Point2D transformedAt = vv.inverseViewTransform(at);
	    
        if((scale*amount - crossover)*(scale*amount - crossover) < 0.001) {
            // close to the control point, return both transformers to a scale of 1.0
            layoutTransformer.scale(inverseModelScale, inverseModelScale, transformedAt);
            viewTransformer.scale(inverseViewScale, inverseViewScale, at);
        } else if(scale*amount < crossover) {
            // scale the viewTransformer, return the layoutTransformer to 1.0
	        viewTransformer.scale(amount, amount, at);
	        layoutTransformer.scale(inverseModelScale, inverseModelScale, transformedAt);
	    } else {
            // scale the layoutTransformer, return the viewTransformer to 1.0
	        layoutTransformer.scale(amount, amount, transformedAt);
	        viewTransformer.scale(inverseViewScale, inverseViewScale, at);
	    }
	    vv.repaint();
	}
}
