1 package de.fzi.wim.guibase.graphview.lens;
2
3 import java.awt.geom.Point2D;
4
5 /***
6 * An implementation of the lens that provides hyperbolic view. This class has been initially implemented within
7 * the <a href="http://www.touchgraph.com/">TouchGraph</a> library.
8 */
9 public class HyperbolicLens extends AbstractLens {
10 /*** The distortion factor of the hyperbolic lens. */
11 protected double m_distortionFactor;
12 /*** The table of the values of the inverse hyperbolic function. */
13 protected double[] m_inverseHyperbolicFunction=new double[200];
14
15 /***
16 * Creates a lens for hyperbolic view.
17 */
18 public HyperbolicLens() {
19 setDistortionFactor(0.0);
20 }
21 /***
22 * Returns the current distortion factor.
23 *
24 * @return the current distortion factory
25 */
26 public double getDistortionFactor() {
27 return m_distortionFactor;
28 }
29 /***
30 * Sets the new distortion factor.
31 *
32 * @param distortionFactor the new distortion factor
33 */
34 public void setDistortionFactor(double distortionFactor) {
35 m_distortionFactor=distortionFactor;
36 for (int i=0;i<m_inverseHyperbolicFunction.length;i++)
37 m_inverseHyperbolicFunction[i]=hyperDistance(10.0*i);
38 fireLensUpdated();
39 }
40 /***
41 * Computes the raw hyperbolic distance.
42 *
43 * @param distance the distance
44 * @return the raw hyperbolic distance
45 */
46 protected double rawHyperDistance(double distance) {
47 return Math.log(distance/(Math.pow(1.5,(70-m_distortionFactor)/40)*80) +1);
48 }
49 /***
50 * Computes the hyperbolic distance. Points that are more than 250 units away from the center stay fixed.
51 *
52 * @param distance the distance
53 * @return the raw hyperbolic distance
54 */
55 protected double hyperDistance(double distance) {
56 return rawHyperDistance(distance)/rawHyperDistance(250.0)*250.0*m_distortionFactor/100.0+distance*(100.0-m_distortionFactor)/100.0;
57 }
58 /***
59 * Computes the inverse of the hyperbolic distance.
60 *
61 * @param distance the distance
62 * @return the inverse hyperbolic distance
63 */
64 protected double invHyperDistance(double distance) {
65 int i;
66 if (m_inverseHyperbolicFunction[199]<distance)
67 i=199;
68 else
69 i=findIndex(0,199,distance);
70 double x2=m_inverseHyperbolicFunction[i];
71 double x1=m_inverseHyperbolicFunction[i-1];
72 double j=(distance-x1)/(x2-x1);
73 return ((double)i+j-1)*10.0;
74 }
75 /***
76 * Locates the index of the element in the inverse array using the binary search algorithm.
77 *
78 * @param min the minimum index
79 * @param max the maximum index
80 * @param distance the value being sought
81 * @return the index in the array
82 */
83 protected int findIndex(int min,int max,double distance) {
84 int mid=(min+max)/2;
85 if (m_inverseHyperbolicFunction[mid]<distance)
86 if (max-mid==1)
87 return max;
88 else
89 return findIndex(mid,max,distance);
90 else
91 if (mid-min==1)
92 return mid;
93 else
94 return findIndex(min,mid,distance);
95 }
96 /***
97 * Applies the lens to the point and modifies it according to the lens equations.
98 *
99 * @param point the point that will be modified
100 */
101 public void applyLens(Point2D point) {
102 double x=point.getX();
103 double y=point.getY();
104 if (x!=0.0 || y!=0.0) {
105 double distance=Math.sqrt(x*x+y*y);
106 point.setLocation(x/distance*hyperDistance(distance),y/distance*hyperDistance(distance));
107 }
108 }
109 /***
110 * Undoes the lens effect on the point.
111 *
112 * @param point the point that will be modified
113 */
114 public void undoLens(Point2D point) {
115 double x=point.getX();
116 double y=point.getY();
117 if (x!=0.0 || y!=0.0) {
118 double distance=Math.sqrt(x*x+y*y);
119 point.setLocation(x/distance*invHyperDistance(distance),y/distance*invHyperDistance(distance));
120 }
121 }
122 }