254 lines
8.8 KiB
Java
254 lines
8.8 KiB
Java
/*
|
|
* lilgpSetup Utility for generating lilgp parameter files
|
|
* version 1.0
|
|
* 12-May-97
|
|
*
|
|
* Copyright (C) 1997 Michigan State University
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General
|
|
* Public License as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to:
|
|
*
|
|
* Free Software Foundation, Inc.
|
|
* 59 Temple Place - Suite 330
|
|
* Boston, MA
|
|
* 02111-1307
|
|
* USA.
|
|
*
|
|
* Ryan Shoemaker shoema16@cps.msu.edu
|
|
* Dr. Bill Punch punch@cps.msu.edu
|
|
*
|
|
* Computer Science Department
|
|
* A-714 Wells Hall
|
|
* Michigan State University
|
|
* East Lansing, Michigan 48824
|
|
* USA
|
|
*
|
|
*/
|
|
|
|
import java.awt.*;
|
|
|
|
/**
|
|
* This class is responsible for generating a visual representation
|
|
* of the sub-population exchanges. It uses double buffering and all
|
|
* that other cool stuff.....
|
|
*
|
|
* @see SubPopFrame
|
|
*/
|
|
public class SubPopGraph extends Panel {
|
|
private SubPopFrame my_spf;
|
|
private int num_pops;
|
|
private int num_exchanges;
|
|
private Point[] popCenters;
|
|
|
|
private Image offScreenImage;
|
|
private Graphics offScreen;
|
|
|
|
public static final int graphWidth = 500;
|
|
public static final int graphHeight = 500;
|
|
|
|
// radius isn't really the circle's radius. It is the
|
|
// width and hight of the bounding box around the
|
|
// circle, so the radius is actually half of whatever
|
|
// value you put here.
|
|
public static final int radius = 50;
|
|
|
|
public Exchange[] exchanges;
|
|
|
|
/**
|
|
* Initialize instance variables and resize the panel
|
|
*
|
|
* @param spf a reference to the SubPopFrame that created me
|
|
* @param n the number of sub populations
|
|
*/
|
|
public SubPopGraph(SubPopFrame spf, int n) {
|
|
my_spf = spf;
|
|
num_pops = n;
|
|
resize(graphWidth, graphHeight);
|
|
}
|
|
|
|
/**
|
|
* After accepting a new set of exchanges, redraw the sub pop graph
|
|
*
|
|
* @param exArray an array of <tt>Exchange</tt> objects
|
|
*/
|
|
public void refreshGraph(Exchange[] exArray) {
|
|
exchanges = exArray;
|
|
num_exchanges = exArray.length;
|
|
paint(getGraphics());
|
|
}
|
|
|
|
/**
|
|
* The method that actually does all of the drawing. It paints the
|
|
* background, then the exchange links, the link arrowheads, and
|
|
* finally the sub pops.
|
|
*
|
|
* @param g the graphics object
|
|
*/
|
|
public void backgroundPaint(Graphics g) {
|
|
Rectangle clip = new Rectangle(0, 0, size().width, size().height);
|
|
|
|
g.setColor(new Color((float)0.40, (float).75, (float)0.40));
|
|
g.fill3DRect(0, 0, graphWidth, graphHeight, true);
|
|
|
|
// calculate the coordinates of the center of each subpop
|
|
int Xcent = graphWidth/2;
|
|
int Ycent = graphHeight/2;
|
|
int theta = (int)(360.0/num_pops);
|
|
int angle = 90;
|
|
|
|
popCenters = new Point[num_pops];
|
|
|
|
for (int i=0; i < num_pops; i++, angle+=theta) {
|
|
popCenters[i] = new Point(Xcent - (int)(175*Math.cos(angle*Math.PI/180.0)),
|
|
Ycent - (int)(175*Math.sin(angle*Math.PI/180.0)));
|
|
}
|
|
|
|
// Draw the exchange arrows
|
|
for (int i = 0; i < num_exchanges; i++) {
|
|
// have to subtract one since sub-pops are not zero indexed
|
|
int fromPop = Integer.parseInt(exchanges[i].fromPop) - 1;
|
|
int toPop = Integer.parseInt(exchanges[i].toPop) - 1;
|
|
|
|
int x0 = popCenters[fromPop].x;
|
|
int y0 = popCenters[fromPop].y;
|
|
int x1 = popCenters[toPop].x;
|
|
int y1 = popCenters[toPop].y;
|
|
|
|
g.setColor(Color.black);
|
|
|
|
// draw a thick line
|
|
g.drawLine(x0, y0, x1, y1);
|
|
g.drawLine(x0, y0+1, x1, y1+1);
|
|
g.drawLine(x0+1, y0, x1+1, y1);
|
|
g.drawLine(x0, y0-1, x1, y1-1);
|
|
g.drawLine(x0-1, y0, x1-1, y1);
|
|
|
|
// draw the arrow head
|
|
int length = (int)( Math.sqrt( (Math.pow((x0 - x1), 2)) +
|
|
(Math.pow((y0 - y1), 2)) ) );
|
|
double w0 = (double)(radius / 2) / (double)length;
|
|
double w1 = (double)(length - (radius / 2)) / (double)length;
|
|
double w2 = (double)radius / (double)length;
|
|
double w3 = (double)(length - radius) / (double)length;
|
|
|
|
int tipX = (int)(w0 * x0) + (int)(w1 * x1);
|
|
int tipY = (int)(w0 * y0) + (int)(w1 * y1);
|
|
int baseX = (int)(w2 * x0) + (int)(w3 * x1);
|
|
int baseY = (int)(w2 * y0) + (int)(w3 * y1);
|
|
|
|
double headAngle = 25.0 * Math.PI / 180.0;
|
|
int arrowLength = (int)( Math.sqrt( (Math.pow((tipX - baseX), 2)) +
|
|
(Math.pow((tipY - baseY), 2)) ) );
|
|
|
|
double baseAngle = Math.atan( (double)(tipY - baseY) / (double)(tipX - baseX) );
|
|
int cosPart = (int)( arrowLength * Math.cos(baseAngle - headAngle) );
|
|
int sinPart = (int)( arrowLength * Math.sin(baseAngle - headAngle) );
|
|
int dx = tipX - baseX;
|
|
int dy = tipY - baseY;
|
|
int topX, botX, topY, botY;
|
|
if (dx >= 0) {
|
|
topX = (int)( tipX - ( arrowLength * Math.cos(baseAngle - headAngle) ) );
|
|
botX = (int)( tipX - ( arrowLength * Math.cos(baseAngle + headAngle) ) );
|
|
topY = (int)( tipY - ( arrowLength * Math.sin(baseAngle - headAngle) ) );
|
|
botY = (int)( tipY - ( arrowLength * Math.sin(baseAngle + headAngle) ) );
|
|
}
|
|
else {
|
|
topX = (int)( tipX + ( arrowLength * Math.cos(baseAngle - headAngle) ) );
|
|
botX = (int)( tipX + ( arrowLength * Math.cos(baseAngle + headAngle) ) );
|
|
topY = (int)( tipY + ( arrowLength * Math.sin(baseAngle - headAngle) ) );
|
|
botY = (int)( tipY + ( arrowLength * Math.sin(baseAngle + headAngle) ) );
|
|
}
|
|
|
|
Polygon p = new Polygon();
|
|
p.addPoint(tipX, tipY);
|
|
p.addPoint(topX, topY);
|
|
p.addPoint(botX, botY);
|
|
p.addPoint(tipX, tipY);
|
|
g.fillPolygon(p);
|
|
}
|
|
|
|
// Draw the subpops
|
|
//int Xcent = graphWidth/2;
|
|
//int Ycent = graphHeight/2;
|
|
/*int*/ theta = (int)(360.0/num_pops);
|
|
/*int*/ angle = 90;
|
|
FontMetrics fm = getFontMetrics(getFont());
|
|
|
|
//popCenters = new Point[num_pops];
|
|
|
|
for (int i=0; i < num_pops; i++, angle+=theta) {
|
|
//int popX = Xcent - (radius/2) - (int)(175*Math.cos(angle*Math.PI/180.0));
|
|
//int popY = Ycent - (radius/2) - (int)(175*Math.sin(angle*Math.PI/180.0));
|
|
int popX = popCenters[i].x - (radius/2);
|
|
int popY = popCenters[i].y - (radius/2);
|
|
|
|
//popCenters[i] = new Point(popX + (radius/2), popY + (radius/2));
|
|
|
|
g.setColor(Color.yellow);
|
|
g.fillOval(popX+1, popY+1, radius-1, radius-1);
|
|
g.setColor(Color.black);
|
|
g.drawOval(popX, popY, radius, radius);
|
|
g.drawOval(popX+1, popY+1, radius-1, radius-1);
|
|
|
|
g.setColor(Color.black);
|
|
// have to add 1 to i since sub-pops are not zero indexed
|
|
String label = new String(String.valueOf(i+1));
|
|
g.drawString(label, (popX+radius/2)-(fm.stringWidth(label)/2),
|
|
(popY+radius/2)+(fm.getHeight()/2));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The overridden paint method responsible for figuring out if
|
|
* we are double-buffered or not and then dispatching the drawing
|
|
*
|
|
* @param g the graphics object
|
|
*/
|
|
public void paint(Graphics g) {
|
|
// create the offscreen image if it doesn't already exist
|
|
if (offScreenImage == null)
|
|
{
|
|
offScreenImage = createImage (graphWidth, graphHeight);
|
|
offScreen = offScreenImage.getGraphics ();
|
|
}
|
|
|
|
// if the offscreen image exists then use it to double buffer,
|
|
// otherwise, paint on the currently visible graphics object.
|
|
if (offScreen != null) {
|
|
backgroundPaint(offScreen);
|
|
g.drawImage(offScreenImage, 0, 0, this);
|
|
}
|
|
else {
|
|
backgroundPaint(g);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate the minimum size of the panel
|
|
*
|
|
* @return the dimensions of the graph
|
|
*/
|
|
public Dimension minimumSize() {
|
|
return (new Dimension(graphWidth, graphHeight));
|
|
}
|
|
|
|
/**
|
|
* Calculate the preferred size of the panel
|
|
*
|
|
* @return the minimum size of the panel
|
|
*/
|
|
public Dimension preferredSize() {
|
|
return minimumSize();
|
|
}
|
|
}
|
|
|