// 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; /** * Selects a rectangular screen region. The sides of the rectangle * are parallel to the x and y-axes. * * @author Charles Loomis * @author Mark Donszelmann * @version $Id: RectangularSelectionPanel.java 8584 2006-08-10 23:06:37Z duns $ */ public class RectangularSelectionPanel extends AbstractRegionSelectionPanel { /** * Creates a RectangularSelectionPanel. */ public RectangularSelectionPanel() { super(); } /** * Returns the number of control points for the rectangle (4). * * @return 4, the control points at the corner of the rectangle */ public int getNumberOfControlPoints() { return 4; } public Cursor getControlPointCursor(int index) { if (index >= 0) { int k = (index+2) % 4; return compassCursor("Resize", xCtrlPts[index] - xCtrlPts[k], yCtrlPts[index] - yCtrlPts[k], 4, true); } return FreeHepImage.getCursor("RectangularCursor"); } /** * Initialize the control points based on the given starting point * (x,y). * * @param x x-coordinate (in pixels) of the starting point * @param y y-coordinate (in pixels) fo the starting point */ public void initializeControlPoints(int x, int y) { activeCtrlPt = 2; 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); // Update the active control point. xCtrlPts[activeCtrlPt] = x; yCtrlPts[activeCtrlPt] = y; // Get the opposite control point. int oppCtrlPt = (activeCtrlPt+2)%nCtrlPts; int xOpp = xCtrlPts[oppCtrlPt]; int yOpp = yCtrlPts[oppCtrlPt]; // Now choose the next control point so that we maintain a // clockwise order to the points. int otherCtrlPt = ((x<xOpp && y>yOpp)||(x>xOpp && y<yOpp)) ? 1 : 3; otherCtrlPt = (activeCtrlPt+otherCtrlPt)%4; // Set the other two control points. xCtrlPts[otherCtrlPt] = x; yCtrlPts[otherCtrlPt] = yOpp; otherCtrlPt = (otherCtrlPt+2)%nCtrlPts; xCtrlPts[otherCtrlPt] = xOpp; yCtrlPts[otherCtrlPt] = y; 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 the the image. g2d.setStroke(thickStroke); g.setColor(Color.black); g.drawPolygon(xCtrlPts, yCtrlPts, nCtrlPts); g2d.setStroke(thinStroke); g.setColor(Color.white); g.drawPolygon(xCtrlPts, yCtrlPts, nCtrlPts); 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 rectangular * selection. * * @return AffineTransform which describes the selected region */ public AffineTransform makeAffineTransform() { int second = 0; int third = 0; // Find first the upper, left-hand point. int first = 0; int savedValue = xCtrlPts[0]*xCtrlPts[0]+yCtrlPts[0]*yCtrlPts[0]; for (int i=1; i<4; i++) { int value = xCtrlPts[i]*xCtrlPts[i]+yCtrlPts[i]*yCtrlPts[i]; if (value<savedValue) { savedValue = value; first = i; } } // Calculate the adjacent partner and the opposite corner. second = (first+1)%4; third = (first+2)%4; // Just call the utility function of the parent now. return makeTransform((double) xCtrlPts[first], (double) yCtrlPts[first], (double) xCtrlPts[second], (double) yCtrlPts[second], (double) xCtrlPts[third], (double) yCtrlPts[third]); } /** * Determine if the selection is valid. Return false if the area * is zero. */ public boolean isValidSelection() { return (visible) && (xCtrlPts[0]!=xCtrlPts[2] || yCtrlPts[0]!=yCtrlPts[2]); } }