/* * TouchGraph LLC. Apache-Style Software License * * * Copyright (c) 2001-2002 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 LLC (http://www.touchgraph.com/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "TouchGraph" or "TouchGraph LLC" 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 alex@touchgraph.com. * * 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.*; /** RotateScroll. Allows one to rotate the graph by clicking+dragging * The rotate lens won't work properly unless it's the top lens, because it * does not account for distortion from above lenses. Methods for getting * lenses above the current one need to be added to TGLensSet to solve this problem. * * @author Alexander Shapiro * @version 1.21 $Id: RotateScroll.java,v 1.1.1.1 2007/01/07 07:58:19 andrew Exp $ */ public class RotateScroll implements GraphListener { RotateLens rotateLens; double rotateAngle; RotateDragUI rotateDragUI; private DScrollBar rotateSB; boolean adjustmentIsInternal; private TGPanel tgPanel; // ............ /** Constructor with TGPanel <tt>tgp</tt>. */ public RotateScroll(TGPanel tgp) { tgPanel=tgp; rotateAngle=0; rotateLens=new RotateLens(); rotateDragUI = new RotateDragUI(); rotateSB = new DScrollBar(JScrollBar.HORIZONTAL, 0, 4, -314, 318); rotateSB.addAdjustmentListener(new rotateAdjustmentListener()); adjustmentIsInternal=false; tgPanel.addGraphListener(this); } public RotateLens getLens() { return rotateLens; } public JScrollBar getRotateSB() { return rotateSB; } public RotateDragUI getRotateDragUI() { return rotateDragUI; } public int getRotationAngle() { double orientedValue = rotateSB.getValue()-rotateSB.getMinimum(); double range = rotateSB.getMaximum()-rotateSB.getMinimum()-rotateSB.getVisibleAmount(); return (int) ((orientedValue/range)*359); } public void setRotationAngle(int angle) { double range = rotateSB.getMaximum()-rotateSB.getMinimum()-rotateSB.getVisibleAmount(); rotateSB.setValue((int) (angle/359.0 * range+0.5)+rotateSB.getMinimum()); } public void graphMoved() {} //From GraphListener interface public void graphReset() { rotateAngle=0; rotateSB.setValue(0); } //From GraphListener interface private class rotateAdjustmentListener implements AdjustmentListener { public void adjustmentValueChanged(AdjustmentEvent e) { if(!adjustmentIsInternal) { rotateAngle = rotateSB.getDValue()/100.0; tgPanel.repaintAfterMove(); } } } class DScrollBar extends JScrollBar { private double doubleValue; DScrollBar(int orient, int val, int vis, int min, int max){ super(orient, val, vis, min, max); doubleValue=val; } public void setValue(int v) { doubleValue = v; super.setValue(v); } public void setIValue(int v) { super.setValue(v); } public void setDValue(double v) { doubleValue = Math.max(getMinimum(),Math.min(getMaximum(),v)); setIValue((int) v); } public double getDValue() { return doubleValue;} } double computeAngle( double x, double y ) { double angle=Math.atan(y/x); if (x==0) //There is probably a better way of hangling boundary conditions, but whatever if(y>0) angle=Math.PI/2; else angle=-Math.PI/2; if (x<0) angle+=Math.PI; return angle; } class RotateLens extends TGAbstractLens { protected void applyLens(TGPoint2D p) { double currentAngle=computeAngle(p.x,p.y); double dist=Math.sqrt((p.x*p.x)+(p.y*p.y)); p.x=dist*Math.cos(currentAngle+rotateAngle); p.y=dist*Math.sin(currentAngle+rotateAngle); } protected void undoLens(TGPoint2D p) { double currentAngle=computeAngle(p.x,p.y); double dist=Math.sqrt((p.x*p.x)+(p.y*p.y)); p.x=dist*Math.cos(currentAngle-rotateAngle); p.y=dist*Math.sin(currentAngle-rotateAngle); } } public void incrementRotateAngle(double inc) { rotateAngle+=inc; if (rotateAngle>Math.PI) rotateAngle-=Math.PI*2; if (rotateAngle<-Math.PI) rotateAngle+=Math.PI*2; adjustmentIsInternal=true; rotateSB.setDValue(rotateAngle*100); adjustmentIsInternal=false; } class RotateDragUI extends TGAbstractDragUI { // Will work best if rotate lens is top lens RotateDragUI() { super(RotateScroll.this.tgPanel); } double lastAngle; double getMouseAngle(double x, double y) { return computeAngle(x-this.tgPanel.getDrawCenter().x, y-this.tgPanel.getDrawCenter().y); } public void preActivate() {} public void preDeactivate() {} public void mousePressed( MouseEvent e ) { lastAngle = getMouseAngle(e.getX(), e.getY()); } public void mouseReleased( MouseEvent e ) {} public void mouseDragged( MouseEvent e ) { double currentAngle = getMouseAngle(e.getX(), e.getY()); incrementRotateAngle(currentAngle-lastAngle); lastAngle=currentAngle; this.tgPanel.repaintAfterMove(); } } } // end com.touchgraph.graphlayout.interaction.RotateScroll