View Javadoc

1   /*
2    * TouchGraph LLC. Apache-Style Software License
3    *
4    *
5    * Copyright (c) 2001-2002 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 LLC (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 names "TouchGraph" or "TouchGraph LLC" must not be used to endorse 
27   *    or promote 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 alex@touchgraph.com.
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  /*** RotateScroll.  Allows one to rotate the graph by clicking+dragging
59    * The rotate lens won't work properly unless it's the top lens, because it
60    * does not account for distortion from above lenses.  Methods for getting
61    * lenses above the current one need to be added to TGLensSet to solve this problem.
62    *
63    * @author   Alexander Shapiro
64    * @version  1.21  $Id: RotateScroll.java,v 1.1.1.1 2004/02/06 08:44:07 keesj Exp $
65    */
66  public class RotateScroll implements GraphListener {
67  
68      RotateLens rotateLens;
69      double rotateAngle;
70      RotateDragUI rotateDragUI;
71      private DScrollBar rotateSB;
72      boolean adjustmentIsInternal;
73      private TGPanel tgPanel;
74  
75    // ............
76  
77      /*** Constructor with TGPanel <tt>tgp</tt>.
78        */
79      public RotateScroll(TGPanel tgp) {
80          tgPanel=tgp;
81          rotateAngle=0;
82          rotateLens=new RotateLens();
83           rotateDragUI = new RotateDragUI();
84           rotateSB = new DScrollBar(JScrollBar.HORIZONTAL, 0, 4, -314, 318);
85           rotateSB.addAdjustmentListener(new rotateAdjustmentListener());
86           adjustmentIsInternal=false;
87           tgPanel.addGraphListener(this);
88      }
89  
90      public RotateLens getLens() { return rotateLens; }
91  
92      public JScrollBar getRotateSB() { return rotateSB; }
93  
94      public RotateDragUI getRotateDragUI() { return rotateDragUI; }
95  
96      public int getRotationAngle() {
97          double orientedValue = rotateSB.getValue()-rotateSB.getMinimum();
98          double range = rotateSB.getMaximum()-rotateSB.getMinimum()-rotateSB.getVisibleAmount();
99          return (int) ((orientedValue/range)*359);
100     }
101 
102     public void setRotationAngle(int angle) {
103         double range = rotateSB.getMaximum()-rotateSB.getMinimum()-rotateSB.getVisibleAmount();
104         rotateSB.setValue((int) (angle/359.0 * range+0.5)+rotateSB.getMinimum());
105     }
106 
107     public void graphMoved() {} //From GraphListener interface
108 
109     public void graphReset() { rotateAngle=0; rotateSB.setValue(0); } //From GraphListener interface
110 
111     private class rotateAdjustmentListener implements AdjustmentListener {
112         public void adjustmentValueChanged(AdjustmentEvent e) {
113             if(!adjustmentIsInternal) {
114                 rotateAngle = rotateSB.getDValue()/100.0;
115                 tgPanel.repaintAfterMove();
116             }
117         }
118     }
119 
120     class DScrollBar extends JScrollBar {
121         private double doubleValue;
122 
123         DScrollBar(int orient, int val, int vis, int min, int max){
124             super(orient, val, vis, min, max);
125             doubleValue=val;
126         }
127         public void setValue(int v) { doubleValue = v; super.setValue(v); }
128         public void setIValue(int v) { super.setValue(v); }
129         public void setDValue(double v) {
130             doubleValue = Math.max(getMinimum(),Math.min(getMaximum(),v));
131             setIValue((int) v);
132         }
133         public double getDValue() { return doubleValue;}
134     }
135 
136 
137     double computeAngle( double x, double y ) {
138         double angle=Math.atan(y/x);
139 
140         if (x==0)  //There is probably a better way of hangling boundary conditions, but whatever
141             if(y>0) angle=Math.PI/2;
142             else angle=-Math.PI/2;
143 
144         if (x<0) angle+=Math.PI;
145 
146         return angle;
147     }
148 
149     class RotateLens extends TGAbstractLens {
150         protected void applyLens(TGPoint2D p) {
151             double currentAngle=computeAngle(p.x,p.y);
152             double dist=Math.sqrt((p.x*p.x)+(p.y*p.y));
153 
154             p.x=dist*Math.cos(currentAngle+rotateAngle);
155             p.y=dist*Math.sin(currentAngle+rotateAngle);
156         }
157 
158         protected void undoLens(TGPoint2D p) {
159             double currentAngle=computeAngle(p.x,p.y);
160             double dist=Math.sqrt((p.x*p.x)+(p.y*p.y));
161 
162             p.x=dist*Math.cos(currentAngle-rotateAngle);
163             p.y=dist*Math.sin(currentAngle-rotateAngle);
164         }
165     }
166 
167     public void incrementRotateAngle(double inc) {
168         rotateAngle+=inc;
169         if (rotateAngle>Math.PI) rotateAngle-=Math.PI*2;
170         if (rotateAngle<-Math.PI) rotateAngle+=Math.PI*2;
171         adjustmentIsInternal=true;
172             rotateSB.setDValue(rotateAngle*100);
173         adjustmentIsInternal=false;
174     }
175 
176     class RotateDragUI extends TGAbstractDragUI { // Will work best if rotate lens is top lens
177 
178         RotateDragUI() {
179             super(RotateScroll.this.tgPanel);
180         }
181 
182         double lastAngle;
183 
184         double getMouseAngle(double x, double y) {
185             return computeAngle(x-this.tgPanel.getDrawCenter().x,
186                                 y-this.tgPanel.getDrawCenter().y);
187         }
188 
189         public void preActivate() {}
190         public void preDeactivate() {}
191 
192         public void mousePressed( MouseEvent e ) {
193             lastAngle = getMouseAngle(e.getX(), e.getY());
194         }
195 
196         public void mouseReleased( MouseEvent e ) {}
197 
198         public void mouseDragged( MouseEvent e ) {
199             double currentAngle = getMouseAngle(e.getX(), e.getY());
200             incrementRotateAngle(currentAngle-lastAngle);
201             lastAngle=currentAngle;
202             this.tgPanel.repaintAfterMove();
203         }
204     }
205 
206 } // end com.touchgraph.graphlayout.interaction.RotateScroll