1 /*
2 * TouchGraph Software License
3 *
4 *
5 * Copyright (c) 2001 Alexander Shapiro. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by
22 * TouchGraph (http://www.touchgraph.com/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The name "TouchGraph" must not be used to endorse or promote
27 * products derived from this software without prior written
28 * permission. For written permission, please contact
29 * alex@touchgraph.com
30 *
31 * 5. Products derived from this software may not be called "TouchGraph",
32 * nor may "TouchGraph" appear in their name, without prior written
33 * permission of TouchGraph.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE
39 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
44 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
45 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 * =====================================================================
47 *
48 */
49
50 package com.touchgraph.graphlayout.interaction;
51
52 import java.awt.event.*;
53
54 import javax.swing.JScrollBar;
55
56 import com.touchgraph.graphlayout.*;
57
58 /*** HyperScroll. Responsible for producing that neat hyperbolic effect.
59 * (Which isn't really hyperbolic, but just non-linear).
60 * Demonstrates the usefulness of Lenses.
61 *
62 * @author Alexander Shapiro
63 * @version 1.06
64 */
65 public class HyperScroll implements GraphListener {
66
67 private JScrollBar hyperSB;
68 private TGPanel tgPanel;
69 HyperLens hyperLens;
70 double inverseArray[]=new double[200]; //Helps calculate the inverse of the Hyperbolic function
71 double width; //Initially was intended to change the function of the lens depending on screen size,
72 //but now functions as a constant.
73
74 public HyperScroll(TGPanel tgp) {
75 tgPanel=tgp;
76 hyperSB = new JScrollBar(JScrollBar.HORIZONTAL, 0, 8, 0, 108);
77 hyperSB.addAdjustmentListener(new hyperAdjustmentListener());
78
79 hyperLens = new HyperLens();
80 width= 2000;//tgPanel.getSize().width/2;
81 updateInverseArray();
82
83 tgPanel.addGraphListener(this);
84 }
85
86 public JScrollBar getHyperSB() { return hyperSB; }
87
88 public HyperLens getLens() { return hyperLens; }
89
90 public void graphMoved() {} //From GraphListener interface
91 public void graphReset() { hyperSB.setValue(0); } //From GraphListener interface
92
93 private class hyperAdjustmentListener implements AdjustmentListener {
94 public void adjustmentValueChanged(AdjustmentEvent e) {
95 updateInverseArray();
96 tgPanel.repaintAfterMove();
97 }
98 }
99
100 double rawHyperDist (double dist) { //The hyperbolic transform
101 if(hyperSB.getValue()==0) return dist;
102 double hyperV=hyperSB.getValue();
103 return Math.log(dist/(Math.pow(1.5,(70-hyperV)/40)*80) +1);
104 /*
105 double hyperD = Math.sqrt(dist+(10.1-Math.sqrt(hyperV)))-Math.sqrt(10.1-Math.sqrt(hyperV));
106 */
107
108 }
109
110 double hyperDist (double dist) {
111
112 double hyperV=hyperSB.getValue();
113 //Points that are 250 away from the center stay fixed.
114 double hyperD= rawHyperDist(dist)/rawHyperDist(250)*250;
115 double fade=hyperV;
116 double fadeAdjust=100;
117 hyperD=hyperD*fade/fadeAdjust+dist*(fadeAdjust-fade)/fadeAdjust;
118 return hyperD;
119
120 }
121
122 void updateInverseArray(){
123 double x;
124 for(int i=0;i<200;i++) {
125 x=width*i/200; //Points within a radius of 'width' will have exact inverses.
126 inverseArray[i]=hyperDist(x);
127 }
128 };
129
130 int findInd(int min, int max, double dist) {
131 int mid=(min+max)/2;
132 if (inverseArray[mid]<dist)
133 if (max-mid==1) return max;
134 else return findInd(mid,max,dist);
135 else
136 if (mid-min==1) return mid;
137 else return findInd(min,mid,dist);
138 }
139
140 double invHyperDist (double dist) { //The inverse of hyperDist
141
142 if (dist==0) return 0;
143 int i;
144 if (inverseArray[199]<dist) i=199;
145 else i=findInd(0,199,dist);
146 double x2=inverseArray[i];
147 double x1=inverseArray[i-1];
148 double j= (dist-x1)/(x2-x1);
149 return(((double) i+j-1)/200.0*width);
150 }
151
152
153 class HyperLens extends TGAbstractLens {
154 protected void applyLens(TGPoint2D p) {
155 double dist=Math.sqrt(p.x*p.x+p.y*p.y);
156 if(dist>0) {
157 p.x=p.x/dist*hyperDist(dist);
158 p.y=p.y/dist*hyperDist(dist);
159 }
160 else { p.x =0; p.y=0;}
161 }
162
163 protected void undoLens(TGPoint2D p) {
164 double dist=Math.sqrt(p.x*p.x+p.y*p.y);
165 if(dist>0) {
166 p.x=p.x/dist*invHyperDist(dist);
167 p.y=p.y/dist*invHyperDist(dist);
168 }
169 else { p.x =0; p.y=0;}
170 }
171 }
172
173 //Things can't get much more complex then this, if you don't use an inverse function
174 /*
175 class HyperLens extends TGAbstractLens {
176 protected void applyLens(TGPoint2D p) {
177 if(p.x!=0)
178 p.x=p.x/Math.sqrt(Math.abs(p.x))*Math.sqrt(tgPanel.getSize().width/2);
179 if(p.y!=0)
180 p.y=p.y/Math.sqrt(Math.abs(p.y))*Math.sqrt(tgPanel.getSize().height/2);
181 }
182
183 protected void undoLens(TGPoint2D p) {
184
185 p.x=(p.x/Math.sqrt(tgPanel.getSize().width/2));
186 p.x=p.x*Math.abs(p.x);
187 p.y=(p.y/Math.sqrt(tgPanel.getSize().height/2));
188 p.y=p.y*Math.abs(p.y);
189 }
190 }
191 */
192
193 } // end com.touchgraph.graphlayout.interaction.HyperScroll