// Charles A. Loomis, Jr., and University of California, Santa Cruz,
// Copyright (c) 2000
package org.freehep.swing.graphics;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.Arrays;
import org.freehep.swing.images.FreeHepImage;
/**
* A panel which selects a "square" region on the screen. The
* definition of "square" is that this region will retain the relative
* scaling of the x and y-axes.
*
* @author Charles Loomis
* @author Mark Donszelmann
* @version $Id: SquareSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */
public class SquareSelectionPanel
extends AbstractRegionSelectionPanel {
/**
* Creates a SquareSelectionPanel. */
public SquareSelectionPanel() {
super();
}
/**
* Return the number of control points,5---the four corners and
* one point in the center of the square.
*
* @return 5 the number of control points */
public int getNumberOfControlPoints() {
return 5;
}
/**
* Returns the NE, SE, NW and SW cursors for the four different
* directions and SquareCursor as the default
*/
public Cursor getControlPointCursor(int index) {
switch (index) {
case NO_CONTROL_POINT: return FreeHepImage.getCursor("SquareCursor");
case 4: return FreeHepImage.getCursor("0_MoveCursor", 16, 16);
default:
return compassCursor("Resize", xCtrlPts[index] - xCtrlPts[4],
yCtrlPts[index] - yCtrlPts[4], 4, true);
}
}
/**
* Initialize the control points based on the starting point
* (x,y).
*
* @param x x-coordinate of starting point
* @param y y-coordinate of starting point */
public void initializeControlPoints(int x, int y) {
activeCtrlPt = 0;
Arrays.fill(xCtrlPts,x);
Arrays.fill(yCtrlPts,y);
}
/**
* Move the active control point to the point (x,y).
*
* @param x x-coordinate of the new point
* @param y y-coordinate of the new point */
public void updateActiveControlPoint(int x, int y) {
// Bring the location within bounds.
x = forceXCoordinateWithinBounds(x);
y = forceYCoordinateWithinBounds(y);
if (activeCtrlPt==4) {
// Get the change in the center point.
int dx = x - xCtrlPts[4];
int dy = y - yCtrlPts[4];
// Change all control points by this amount.
for (int i=0; i<nCtrlPts; i++) {
xCtrlPts[i] += dx;
yCtrlPts[i] += dy;
}
} else {
// Get the distance from center point.
int dx = x - xCtrlPts[4];
int dy = y - yCtrlPts[4];
// Get the sign of the delta-x and delta-y.
int signx = (dx<0) ? -1 : 1;
int signy = (dy<0) ? -1 : 1;
// Calculate the nearest point which keeps the aspect ratio.
dx = Math.abs(dx);
dy = Math.abs(dy);
double ratio =
((double) getHeight())/((double) getWidth());
int xside = (int) ((((double) dx)+ratio*((double) dy))/
(1.+ratio*ratio));
int yside = xside*getHeight()/getWidth();
xCtrlPts[activeCtrlPt] = xCtrlPts[4]+signx*xside;
yCtrlPts[activeCtrlPt] = yCtrlPts[4]+signy*yside;
xCtrlPts[(activeCtrlPt+1)%4] = xCtrlPts[4]-signx*xside;
yCtrlPts[(activeCtrlPt+1)%4] = yCtrlPts[4]+signy*yside;
xCtrlPts[(activeCtrlPt+2)%4] = xCtrlPts[4]-signx*xside;
yCtrlPts[(activeCtrlPt+2)%4] = yCtrlPts[4]-signy*yside;
xCtrlPts[(activeCtrlPt+3)%4] = xCtrlPts[4]+signx*xside;
yCtrlPts[(activeCtrlPt+3)%4] = yCtrlPts[4]-signy*yside;
}
repaintPanel();
}
public void paintComponent(Graphics g) {
// Allow parent to draw any custom painting.
super.paintComponent(g);
// If the selection region is visible, paint it.
if (visible) {
// Make a 2D graphics context.
Graphics2D g2d = (Graphics2D) g;
// Draw a rectangle on top of the image.
g2d.setStroke(thickStroke);
g.setColor(Color.black);
g.drawPolygon(xCtrlPts, yCtrlPts, 4);
if (visibleGuides) {
g.drawLine(xCtrlPts[0], yCtrlPts[0],
xCtrlPts[2], yCtrlPts[2]);
g.drawLine(xCtrlPts[1], yCtrlPts[1],
xCtrlPts[3], yCtrlPts[3]);
}
g2d.setStroke(thinStroke);
g.setColor(Color.white);
g.drawPolygon(xCtrlPts, yCtrlPts, 4);
if (visibleGuides) {
g.drawLine(xCtrlPts[0], yCtrlPts[0],
xCtrlPts[2], yCtrlPts[2]);
g.drawLine(xCtrlPts[1], yCtrlPts[1],
xCtrlPts[3], yCtrlPts[3]);
}
if (activeCtrlPt >= 0) {
// Draw the active control point.
g.setColor(Color.black);
g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize-1,
yCtrlPts[activeCtrlPt]-ctrlPtSize-1,
2*ctrlPtSize+3, 2*ctrlPtSize+3);
g.setColor(Color.white);
g.fillRect(xCtrlPts[activeCtrlPt]-ctrlPtSize,
yCtrlPts[activeCtrlPt]-ctrlPtSize,
2*ctrlPtSize+1, 2*ctrlPtSize+1);
}
}
}
/**
* Make the affine transform which corresponds to this "square"
* selection.
*
* @return AffineTransform which describes the selected region */
public AffineTransform makeAffineTransform() {
// Do a bit of calculation to maintain the aspect ratio.
double dx = Math.abs(xCtrlPts[0]-xCtrlPts[4]);
double dy = (dx*getHeight())/getWidth();
double x0 = xCtrlPts[4]-dx;
double y0 = yCtrlPts[4]-dy;
double x1 = xCtrlPts[4]+dx;
double y1 = yCtrlPts[4]-dy;
double x2 = xCtrlPts[4]+dx;
double y2 = yCtrlPts[4]+dy;
// Now call the utility function of the parent.
return makeTransform(x0,y0,x1,y1,x2,y2);
}
/**
* Determine if the selection is valid; regions of zero area are
* considered invalid.
*
* @return flag indicating whether the region is valid */
public boolean isValidSelection() {
return (visible) && (xCtrlPts[0]!=xCtrlPts[2] ||
yCtrlPts[0]!=yCtrlPts[2]);
}
}