/*
* TouchGraph Software License
*
*
* Copyright (c) 2001 Alexander Shapiro. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by
* TouchGraph (http://www.touchgraph.com/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "TouchGraph" must not be used to endorse or promote
* products derived from this software without prior written
* permission. For written permission, please contact
* alex@touchgraph.com
*
* 5. Products derived from this software may not be called "TouchGraph",
* nor may "TouchGraph" appear in their name, without prior written
* permission of TouchGraph.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* =====================================================================
*
*/
package com.touchgraph.graphlayout.interaction;
import com.touchgraph.graphlayout.*;
import java.awt.event.*;
import javax.swing.*;
/** HyperScroll. Responsible for producing that neat hyperbolic effect.
* (Which isn't really hyperbolic, but just non-linear).
* Demonstrates the usefulness of Lenses.
*
* @author Alexander Shapiro
* @version 1.06
*/
public class HyperScroll implements GraphListener {
private JScrollBar hyperSB;
private TGPanel tgPanel;
HyperLens hyperLens;
double inverseArray[]=new double[200]; //Helps calculate the inverse of the Hyperbolic function
double width; //Initially was intended to change the function of the lens depending on screen size,
//but now functions as a constant.
public HyperScroll(TGPanel tgp) {
tgPanel=tgp;
hyperSB = new JScrollBar(JScrollBar.HORIZONTAL, 0, 8, 0, 108);
hyperSB.addAdjustmentListener(new hyperAdjustmentListener());
hyperLens = new HyperLens();
width= 2000;//tgPanel.getSize().width/2;
updateInverseArray();
tgPanel.addGraphListener(this);
}
public JScrollBar getHyperSB() { return hyperSB; }
public HyperLens getLens() { return hyperLens; }
public void graphMoved() {} //From GraphListener interface
public void graphReset() { hyperSB.setValue(0); } //From GraphListener interface
private class hyperAdjustmentListener implements AdjustmentListener {
public void adjustmentValueChanged(AdjustmentEvent e) {
updateInverseArray();
tgPanel.repaintAfterMove();
}
}
double rawHyperDist (double dist) { //The hyperbolic transform
if(hyperSB.getValue()==0) return dist;
double hyperV=hyperSB.getValue();
return Math.log(dist/(Math.pow(1.5,(70-hyperV)/40)*80) +1);
/*
double hyperD = Math.sqrt(dist+(10.1-Math.sqrt(hyperV)))-Math.sqrt(10.1-Math.sqrt(hyperV));
*/
}
double hyperDist (double dist) {
double hyperV=hyperSB.getValue();
//Points that are 250 away from the center stay fixed.
double hyperD= rawHyperDist(dist)/rawHyperDist(250)*250;
double fade=hyperV;
double fadeAdjust=100;
hyperD=hyperD*fade/fadeAdjust+dist*(fadeAdjust-fade)/fadeAdjust;
return hyperD;
}
void updateInverseArray(){
double x;
for(int i=0;i<200;i++) {
x=width*i/200; //Points within a radius of 'width' will have exact inverses.
inverseArray[i]=hyperDist(x);
}
};
int findInd(int min, int max, double dist) {
int mid=(min+max)/2;
if (inverseArray[mid]<dist)
if (max-mid==1) return max;
else return findInd(mid,max,dist);
else
if (mid-min==1) return mid;
else return findInd(min,mid,dist);
}
double invHyperDist (double dist) { //The inverse of hyperDist
if (dist==0) return 0;
int i;
if (inverseArray[199]<dist) i=199;
else i=findInd(0,199,dist);
double x2=inverseArray[i];
double x1=inverseArray[i-1];
double j= (dist-x1)/(x2-x1);
return(((double) i+j-1)/200.0*width);
}
class HyperLens extends TGAbstractLens {
protected void applyLens(TGPoint2D p) {
double dist=Math.sqrt(p.x*p.x+p.y*p.y);
if(dist>0) {
p.x=p.x/dist*hyperDist(dist);
p.y=p.y/dist*hyperDist(dist);
}
else { p.x =0; p.y=0;}
}
protected void undoLens(TGPoint2D p) {
double dist=Math.sqrt(p.x*p.x+p.y*p.y);
if(dist>0) {
p.x=p.x/dist*invHyperDist(dist);
p.y=p.y/dist*invHyperDist(dist);
}
else { p.x =0; p.y=0;}
}
}
//Things can't get much more complex then this, if you don't use an inverse function
/*
class HyperLens extends TGAbstractLens {
protected void applyLens(TGPoint2D p) {
if(p.x!=0)
p.x=p.x/Math.sqrt(Math.abs(p.x))*Math.sqrt(tgPanel.getSize().width/2);
if(p.y!=0)
p.y=p.y/Math.sqrt(Math.abs(p.y))*Math.sqrt(tgPanel.getSize().height/2);
}
protected void undoLens(TGPoint2D p) {
p.x=(p.x/Math.sqrt(tgPanel.getSize().width/2));
p.x=p.x*Math.abs(p.x);
p.y=(p.y/Math.sqrt(tgPanel.getSize().height/2));
p.y=p.y*Math.abs(p.y);
}
}
*/
} // end com.touchgraph.graphlayout.interaction.HyperScroll