/*
* StretchLayout.java
*
* Created on November 24, 2008, 12:21 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
/**
*
* @author akumar03
*/
package edu.tufts.vue.layout;
import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import tufts.vue.*;
import edu.tufts.vue.dataset.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Point2D;
import java.awt.geom.Line2D;
public class StretchLayout extends Layout {
/** Creates a new instance of StretchLayout */
public StretchLayout() {
}
public void layout(LWSelection selection) {
// compute the bounding rectangle of selection
int X_PADDING = 40; // applied only on top and left
int Y_PADDING = 20;
int MAX_X_MOVE =80;
int MAX_Y_MOVE = 40;
double MAX_SHIFT = 1.2;
double SHIFT_RANGE = 1.5;
double EXPAND = 1.25; // expands the ellipse by a factor of 1.1
Rectangle2D boundingRect = selection.getBounds();
double maxX = boundingRect.getMaxX();
double maxY = boundingRect.getMaxY();
double minX = boundingRect.getMinX();
double minY = boundingRect.getMinY();
final double centerX = boundingRect.getCenterX();
final double centerY = boundingRect.getCenterY();
double xRange = Math.abs(maxX-minX)/2;
double yRange = Math.abs(maxY-minY)/2;
// determine the axis a & b of the ellipse that bounds the rectangle
double angleTopLeft = Math.atan((centerY-minY)/(centerX-minX));
double a = xRange;
double b = yRange;
double ptEllipseX = centerX - a*Math.cos(angleTopLeft);
double ptEllipseY = centerY - b*Math.sin(angleTopLeft);
double distPt = Point2D.distance(ptEllipseX,ptEllipseY,centerX,centerY);
double distTopLeft = Point2D.distance(minX,minY,centerX,centerY);
double ratio = distTopLeft/distPt;
double outerA = a*ratio*EXPAND;
double outerB = b*ratio*EXPAND;
// System.out.println("ELLIPSE: a:"+a+" b: "+b+" xRrange:" + xRange+" yRange:"+yRange+" ratio:"+ratio);
// System.out.printf("center: %.2f,%.2f\n",centerX,centerY);
// move all nodes around the selection
Iterator<LWComponent> i = VUE.getActiveMap().getAllDescendents(LWContainer.ChildKind.PROPER).iterator();
while (i.hasNext()) {
LWComponent c = i.next();
if (c.isManagedLocation())
continue;
if(!selection.contains(c) && c instanceof LWNode) {
// if node is within the selection move it to the bounding box
Point2D location = c.getLocation();
double newX = location.getX();
double newY = location.getY();
double y = location.getY();
double x =location.getX();
double angle = Math.atan2(centerY-y,x-centerX);
if(boundingRect.contains(location)) {
newX = centerX-X_PADDING+outerA*Math.cos(angle);
newY = centerY-Y_PADDING-outerB*Math.sin(angle);
// System.out.println("Setting new location for: "+c.getLabel()+" angle:"+Math.toDegrees(angle));
// System.out.printf("x:%3.2f,y:%3.2f,newX:%3.2f,newY:%3.2f\n",x,y,newX,newY);
} else {
double xInnerEllipse = centerX+a*Math.cos(angle);
double yInnerEllipse = centerY-b*Math.sin(angle);
double xOuterEllipse = centerX+outerA*Math.cos(angle);
double yOuterEllipse = centerY-outerB*Math.sin(angle);
double distInner = Point2D.distance(centerX,centerY,xInnerEllipse,yInnerEllipse);
double distOuter = Point2D.distance(centerX,centerY,xOuterEllipse,yOuterEllipse);
double distPoint = Point2D.distance(centerX,centerY,x,y);
if(distPoint < SHIFT_RANGE*distOuter) {
double factor = MAX_SHIFT+ (distPoint-distInner)*(SHIFT_RANGE-MAX_SHIFT)/(SHIFT_RANGE*distOuter-distInner);
double newA = outerA*factor;
double newB = outerB*factor;
newX = centerX-X_PADDING+newA*Math.cos(angle);
newY = centerY-Y_PADDING-newB*Math.sin(angle);
}
}
c.setLocation(newX,newY);
}
}
}
public LWMap createMap(Dataset ds,String mapName) throws Exception {
LWMap map = new LWMap(mapName);
return map;
}
}