// Hybsweeper.java
// ---------------------------------------------------------------------
// Hybsweeper: A RESOURCE FOR DETECTING HIGH-DENSITY PLATE GRIDDING
// COORDINATES. 2005. BioTechniques. Vol 39, No. 9. 320-324.
//
// GR Lazo, N Lui, YQ Gu, X Kong, D Coleman-Derr, and OD Anderson.
// USDA ARS Western Regional Research Center, 800 Buchanan Street,
// Albany, CA 94710-1105.
//
// Address correspondence to: Gerard R. Lazo (lazo@pw.usda.gov).
// ---------------------------------------------------------------------
// Notes:
// May 2001 NL
//
// Given an image of a filter autorad, this program captures
// the location of a clone on the filter and reports the
// original plate number and well coordinates (row/column).
//
// It loads/displays a user-specified image file.
// To establish the screen dimensions of the filter, the
// user picks reference points (top left corner & bottom
// right corner) to outline the filter, just off the
// spotting area.
//
// Reports can be displayed on screen--a short report for
// just a few signals, a long report for many, many signals.
// Addresses can be listed in the order saved or in plate order.
// Since applets can't write directly to a local file,
// a text area is provided from which the user can
// cut/paste a report of clone addresses for saving to a file.
//
// Users who do not use the ordering protocol of fields 2,6,3 in
// the top row and fields 4,1,5 in the bottom row of the filter
// can set the field numbers in the source code below.
// (See "UPPER_LEFT")
import java.awt.*; // pkg needed for Image class
import java.awt.event.*; // package needed for buttons
import java.applet.*;
import java.util.*; // vectors & array lists
//
public class Hybsweeper extends Applet implements ActionListener, ItemListener,
MouseListener, MouseMotionListener
{
Image autorad; // image of autoradiogram of filter
TextField imageName; // to capture user-input filename
Vector xMatchedSignals; // for x-y coordinates of matching signals
Vector yMatchedSignals; // "
Vector reportStrings; // for plate/well data output to screen
Vector reportByPlate; // " in plate order
Vector outputStrings; // for output to save to file
Vector outputByPlate; // " in plate order
Choice whichFilter; // pop-up list of filter/plate numbers
Choice whichReport; // pop-up list of report choices
Choice whatIntensity; // pop-up list of signal intensity ratings
Frame f;
String location; // for plate location report
String intensity; // signal rating for report
boolean shortPrint=false; // report on plate locations in left column
boolean removeImage=false; // remove image for printing
boolean longPrint=false; // report in bigger area (image area)
boolean inPlateOrder=false; // print report in plate order
boolean drawPoint1=false; // paint point on 4x4 dup pattern / clone array
boolean drawPoint2=false; // "
boolean inXAisle=false; // if selected spot in vertical aisle
boolean p1InXAisle,p2InXAisle;
boolean inYAisle=false; // if selected spot in horizontal aisle
boolean p1InYAisle,p2InYAisle;
boolean doNotSaveAgain; // Don't save same points twice
boolean showHelp=false; // show help frame window
int x1, y1; // top left coordinates
int x2, y2; // bottom right
int x3, y3; // width & length of screen image
double xMultiplier; // to bring x coordinate to 433 scale; 433 / width
double yMultiplier; // to bring y coordinate to 432 scale; 432 / height
int mouseX, mouseY; // screen coordinates for selected spot
int p1MouseX, p1MouseY; // aka mouseX/Y for cyan-colored selected spots
int p2MouseX, p2MouseY; // "
int spotX, spotY; // coordinates for mouseX/Y net of x1 & y1
int spot_433_X, spot_432_Y; // coordinates on a 433x432 grid
int realSpotX, realSpotY; // coordinates on a 192x192 grid
int p1X, p1Y, p2X, p2Y; // aka realSpotX/Y, displayed on 4x4 clone arrays
int xSpot,ySpot; // coordinates for painted spots
int fieldNum, position; // location on filter
int p1FieldNum, p2FieldNum; // "
int p1Position, p2Position; // "
int plateNum, rowNum, colNum; // plate/well locations per calculatePlate()
int p1PlateNum, p2PlateNum; // plate number
int p1RowNum, p2RowNum; // row # on plate
int plateMultiplier=0; // to account for different filters
String p1RowString, p2RowString; // row # on plate (including leading zero)
String p1PlateString, p2PlateString; // plate number (including leading zeros)
char column='0'; // column letter on plate:
char p1Column='0'; // initialized as zero because Netscape displays
char p2Column='0'; // "square" character if ' ' used
char xAisle, p1XAisle, p2XAisle; // x-aisle east(E)/west(W) of 4x4 pattern
char yAisle, p1YAisle, p2YAisle; // y-aisle north(N)/south(S) of 4x4 pattern
int signalCounter=0; // for vector of matchedSignals
int stringCounter=0; // to track strings of plate #s and well coordinates
int yReport=10; // for report of clone addresses
int xReport=10; // "
final static double XSCALE = 433;
final static double YSCALE = 432;
final static double X3_Y3_ADJUSTER = 192.0/193.0;
final static Color CYAN = new Color(150,245,255);
final static Color GREEN = new Color(0,77,30);
final static Color FUCHSIA = new Color(170,0,160); // darker than Color.magenta
final static Color PURPLE = new Color(175,0,235);
final static int SPOT_AISLE = 1; // space between spots
final static int FIELD_AISLE = 2; // space between fields
final static int ADJUSTMENT = 3; // adjust x-y to pick spot at pointer tip
// (otherwise, x-y is southeast/under mouse pointer)
// ADJUST THE FOLLOWING SIX CONSTANTS DEPENDING ON HOW FIELDS ARE
// SET UP ON YOUR FILTERS:
// Default setup
final static int UPPER_LEFT = 2;
final static int UPPER_CENTER = 6;
final static int UPPER_RIGHT = 3;
final static int LOWER_LEFT = 4;
final static int LOWER_CENTER = 1;
final static int LOWER_RIGHT = 5;
/* an alternative setup
final static int UPPER_LEFT = 1;
final static int UPPER_CENTER = 2;
final static int UPPER_RIGHT = 3;
final static int LOWER_LEFT = 4;
final static int LOWER_CENTER = 5;
final static int LOWER_RIGHT = 6;
*/
/*
-------------------------------------------------
| | | |
| | | |
| | | |
| Upper | Upper | Upper |
| Left | Center | Right |
| Field | Field | Field |
| | | |
| | | |
| | | |
-------------------------------------------------
| | | |
| | | |
| | | |
| Lower | Lower | Lower |
| Left | Center | Right |
| Field | Field | Field |
| | | |
| | | |
| | | |
-------------------------------------------------
*/
CheckboxGroup selectOption;
Checkbox setTopLeft, setBottomRight, pickSpot;
Checkbox cList[] = new Checkbox[3]; // pointers to reduce checkbox-related code
Button help; // displays instructions
Button refresh, savePoints; // zero out | save values
Button removeFilter, keepPicking; // remove image | go back to picking spots
Button bList[] = new Button[5]; // to reduce button-related code
// also needed for setEnabled() method
TextArea t; // text area to write report
Font smallFont = new Font("SansSerif", Font.PLAIN, 9);
//*****************************************************************************
public void init()
{
addMouseListener(this); // register applet as mouse event listener
addMouseMotionListener(this);
setLayout(null); // kill layout manager (manually set format)
// setBackground(Color.white); // use default gray background
setFont(smallFont);
Label imageTitle = new Label("Enter image filename", Label.CENTER);
imageTitle.setBounds(152,5,106,11);
add(imageTitle);
imageName = new TextField(12); // get image file using a text field
add(imageName);
imageName.setBounds(155,18,100,28);
imageName.addActionListener(this);
whichFilter = new Choice();
whichFilter.addItem(" 1 | 1-48"); // the 1st item selected by default
whichFilter.addItem(" 2 | 49-96");
whichFilter.addItem(" 3 | 97-144");
whichFilter.addItem(" 4 | 145-192");
whichFilter.addItem(" 5 | 193-240");
whichFilter.addItem(" 6 | 241-288");
whichFilter.addItem(" 7 | 289-336");
whichFilter.addItem(" 8 | 337-384");
whichFilter.addItem(" 9 | 385-432");
whichFilter.addItem("10 | 433-480");
whichFilter.addItem("11 | 481-528");
whichFilter.addItem("12 | 529-576");
whichFilter.addItem("13 | 577-624");
whichFilter.addItem("14 | 625-672");
whichFilter.addItem("15 | 673-720");
whichFilter.addItem("16 | 721-768");
whichFilter.addItem("17 | 769-816");
whichFilter.addItem("18 | 817-864");
whichFilter.addItem("19 | 865-912");
whichFilter.addItem("20 | 913-960");
whichFilter.addItem("21 | 961-1008");
whichFilter.addItem("22 | 1009-1056");
whichFilter.addItem("23 | 1057-1104");
whichFilter.addItem("24 | 1105-1152");
whichFilter.addItem("25 | 1153-1200");
whichFilter.addItem("26 | 1201-1248");
whichFilter.addItem("27 | 1249-1296");
whichFilter.addItem("28 | 1297-1344");
whichFilter.setBounds(155,52,100,20);
add(whichFilter);
whichFilter.addItemListener(this);
// help window
f = new HybHelpFrame("Help Frame Window");
f.setSize(550,560); // pixels wide, pixels high
selectOption = new CheckboxGroup(); // three radio buttons
setTopLeft=new Checkbox("",true,selectOption); // Do buttons w/o label 1st...
setTopLeft.setBounds(165,111,12,12); // location of button
setTopLeft.setBackground(getBackground());
Label s1 = new Label ("Top Left", Label.LEFT); // ...then set label
s1.setBackground(getBackground()); // no visible boundary
s1.setBounds(180,110,65,12); // location of label
setBottomRight=new Checkbox("",false,selectOption);
setBottomRight.setBounds(165,131,12,12);
setBottomRight.setBackground(getBackground());
Label s2 = new Label ("Bottom Right", Label.LEFT);
s2.setBackground(getBackground());
s2.setBounds(180,130,65,12);
pickSpot=new Checkbox("",false,selectOption);
pickSpot.setBounds(165,151,12,12);
pickSpot.setBackground(getBackground());
Label s3 = new Label ("Pick Spot", Label.LEFT);
s3.setBackground(getBackground());
s3.setBounds(180,150,65,12);
add(s1); add(s2); add(s3);
// store references to radio buttons as added
cList[0] = (Checkbox) add(setTopLeft);
cList[1] = (Checkbox) add(setBottomRight);
cList[2] = (Checkbox) add(pickSpot);
for (int i=0; i < 3; i++)
{
cList[i].addItemListener(this); // register to receive item events
}
help = new Button("Help"); // brings up help box
help.setBackground(getBackground());
help.setForeground(GREEN);
help.setBounds(175,83,60,20);
refresh = new Button("Refresh"); // click to zero out values
refresh.setBackground(getBackground()); // button color
refresh.setForeground(PURPLE); // purple backgrd too bright
refresh.setBounds(175,170,60,20);
savePoints = new Button("Save 2 Points"); // record pairs of signals
savePoints.setBackground(getBackground());
savePoints.setForeground(FUCHSIA); // Color.magenta too bright
savePoints.setBounds(156,409,100,20);
whatIntensity = new Choice(); // designate signal intensity
whatIntensity.addItem("No Rating");
whatIntensity.addItem("one..............");
whatIntensity.addItem("two..............");
whatIntensity.addItem("three............");
whatIntensity.addItem("four.............");
whatIntensity.addItem("five.............");
whatIntensity.setBounds(158,434,100,20);
add(whatIntensity);
whatIntensity.addItemListener(this);
whichReport = new Choice();
whichReport.addItem("No Report"); // 1st item selected by default
whichReport.addItem("Order Saved");
whichReport.addItem("Plate Order");
whichReport.addItem(">120, Saved");
whichReport.addItem(">120, Plate");
whichReport.setBounds(158,459,100,20);
add(whichReport);
whichReport.addItemListener(this);
removeFilter = new Button("Remove Image"); // e.g., to print w/o image
removeFilter.setBackground(getBackground());
removeFilter.setBounds(156,483,100,20);
keepPicking = new Button("Pick More Points");// return to picking spots
keepPicking.setBackground(CYAN);
keepPicking.setBounds(156,590,100,20);
bList[0] = (Button) add(refresh);
bList[1] = (Button) add(savePoints);
bList[2] = (Button) add(removeFilter);
bList[3] = (Button) add(keepPicking);
bList[4] = (Button) add(help);
for (int i=0; i < 5; i++)
{
bList[i].addActionListener(this); // register to receive events
}
Label outputTitle = new Label("Cut & paste to save", Label.CENTER);
outputTitle.setBounds(152,508,106,11);
add(outputTitle); // text area label
t = new TextArea(); // to hold output from outputStrings
t.setBounds(158,520,97,65);
add(t);
xMatchedSignals = new Vector(); // dynamic array to hold saved signals (x,y)
yMatchedSignals = new Vector(); // "
reportStrings = new Vector(); // dynamic array to hold plate/well loc's
outputStrings = new Vector(); // "
reportByPlate = new Vector(); // report in plate order
outputByPlate = new Vector(); // "
} // end init
//*******************************************************************************
public void stop()
{
f.setVisible(false); // close help window
}
//*******************************************************************************
public void paint (Graphics g)
{
// refresh data area
t.setText(""); // to prevent duplicate data in text area
g.setColor(getBackground()); // default backgrd color=gray
g.fillRect(0,0,275,getSize().height); // clears left column
g.fill3DRect(155,78,100,117,true); // 3D box around radio buttons
g.setColor(Color.red); // red outlines of radio buttons to cue user
if (x1==0) // "Top Left" ref point hasn't been selected yet
{
g.drawRect(160,106,90,20);
}
else if ((x1>0) && (x2==0)) // highlight "Bottom Right" button
{
g.drawRect(160,126,90,20);
}
else if ((x1>0) && (x2>0) && (x1>x2))// ref points in wrong orientation
{
g.drawRect(160,106,90,20); // highlight 1st two radio buttons
g.drawRect(160,126,90,20);
}
else // highlight "Pick Spot" button
{
g.drawRect(160,146,90,20);
}
if ( (x1 > 0) || (x2 > 0) ) // a reference point has been picked
{
bList[0].setEnabled(true); // enable "Refresh" button
}
else // mouse has yet to be clicked
{
bList[0].setEnabled(false); // disable "Refresh" button
}
g.setColor(Color.white);
g.fillRect(160,212,88,88); // wht border around 4x4 pattern
g.fillRect(160,318,88,88);
g.setColor(getForeground()); // default foregrd color=black
g.drawRect(160,212,88,88); // outline around 4x4 pattern
g.drawRect(160,318,88,88);
g.drawString("Left-click",180,209); // 4x4 duplication pattern labels
g.drawString("Right-click",180,315);
// paint selected spot on upper 4x4 clone array
if (drawPoint1) // Show Point 1 on 4x4 pattern
{
if (p1InXAisle) // Point 1 in VERTICAL aisle between 4x4 squares
{
if (p1XAisle=='E') { xSpot = 240; } // show spot in vertical aisle
if (p1XAisle=='W') { xSpot = 162; }
}
else // Point 1 not in vertical aisle between 4x4s
{
if ((p1X % 4)==1) { xSpot = 168; } // coords for valid spot locations
else if ((p1X % 4)==2) { xSpot = 186; }
else if ((p1X % 4)==3) { xSpot = 204; }
else { xSpot = 222; }
} // end if Point 1 in a vertical aisle
if (p1InYAisle) // Point 1 in a HORIZONTAL aisle between 4x4s
{
if (p1YAisle=='S') { ySpot = 292; } // show spot in horiz aisle on upper grid
if (p1YAisle=='N') { ySpot = 214; }
}
else // Point 1 not in horizontal aisle between 4x4s
{
if ((p1Y % 4)==1) { ySpot = 220; }
else if ((p1Y % 4)==2) { ySpot = 238; }
else if ((p1Y % 4)==3) { ySpot = 256; }
else { ySpot = 274; }
} // end if Point 1 in a horizontal aisle
if ((p1InXAisle) || (p1InYAisle)) // invalid spot in aisle between 4x4s
{
if (!p1InXAisle) { xSpot += 6; } // align x,y
if (!p1InYAisle) { ySpot += 6; }
g.setColor(Color.gray);
g.fillOval(xSpot,ySpot,6,6); // paint grey aisle spot
}
else // a valid spot location on 4x4 grid
{
g.setColor(CYAN);
g.fillOval(xSpot,ySpot,18,18); // paint cyan-colored spot
}
} // end if drawPoint1
// paint selected spot on lower 4x4 pattern
if (drawPoint2) // Show Point 2 on 4x4 pattern
{
if (p2InXAisle) // Point 2 in VERTICAL aisle between 4x4s
{
if (p2XAisle=='E') { xSpot = 240; } // show spot in vertical aisle
if (p2XAisle=='W') { xSpot = 162; }
}
else // Point 2 not in vertical aisle between 4x4s
{
if ((p2X % 4)==1) { xSpot = 168; } // coordinates for valid spot locations
else if ((p2X % 4)==2) { xSpot = 186; }
else if ((p2X % 4)==3) { xSpot = 204; }
else { xSpot = 222; }
} // end if Point 2 in vertical aisle
if (p2InYAisle) // Point 2 in HORIZONTAL aisle between 4x4s
{
if (p2YAisle=='S') { ySpot = 398; } // put spot in horiz aisle on lower grid
if (p2YAisle=='N') { ySpot = 320; }
} // end if Point 2 in horiz aisle
else // Point 2 not in horizontal aisle between 4x4s
{
if ((p2Y % 4)==1) { ySpot = 326; }
else if ((p2Y % 4)==2) { ySpot = 344; }
else if ((p2Y % 4)==3) { ySpot = 362; }
else { ySpot = 380; }
}
if ((p2InXAisle) || (p2InYAisle)) // an invalid spot in aisle between 4x4s
{
if (!p2InXAisle) { xSpot += 6; }
if (!p2InYAisle) { ySpot += 6; }
g.setColor(Color.gray);
g.fillOval(xSpot,ySpot,6,6); // paint dark gray aisle spot
}
else // a valid spot location on 4x4 grid
{
g.setColor(CYAN);
g.fillOval(xSpot,ySpot,18,18); // show cyan-colored spot
}
} // end if drawPoint2
g.setColor(getForeground());
// POINT 1
for (int i=168; i<223; i=i+18) // draws circles for 4x4 dup pattern
{
for (int j=220; j<275; j=j+18)
{
g.drawOval(i,j,18,18);
}
}
g.drawString("1",175,233); // numbers inside circles in 4x4 pattern
g.drawString("2",193,233);
g.drawString("3",211,233);
g.drawString("6",229,233);
g.drawString("4",175,251);
g.drawString("5",193,251);
g.drawString("4",211,251);
g.drawString("7",229,251);
g.drawString("3",175,269);
g.drawString("2",193,269);
g.drawString("1",211,269);
g.drawString("7",229,269);
g.drawString("5",175,287);
g.drawString("6",193,287);
g.drawString("8",211,287);
g.drawString("8",229,287);
// POINT 2
for (int i=168; i<223; i=i+18) // draws circles for 4x4 dup pattern
{
for (int j=326; j<381; j=j+18)
{
g.drawOval(i,j,18,18);
}
}
g.drawString("1",175,339); // numbers for second 4x4 grid
g.drawString("2",193,339);
g.drawString("3",211,339);
g.drawString("6",229,339);
g.drawString("4",175,357);
g.drawString("5",193,357);
g.drawString("4",211,357);
g.drawString("7",229,357);
g.drawString("3",175,375);
g.drawString("2",193,375);
g.drawString("1",211,375);
g.drawString("7",229,375);
g.drawString("5",175,393);
g.drawString("6",193,393);
g.drawString("8",211,393);
g.drawString("8",229,393);
autorad = getImage(getDocumentBase(), imageName.getText()); // gets image file
if (!removeImage) // user has not requested image removal
{
g.drawImage(autorad,275,0,this); // load image
bList[2].setEnabled(true); // enable "Remove Image" button
}
else // image has to be removed
{ // paint white space in image area
g.setColor(Color.white);
g.fillRect(275,0,getSize().width-275,getSize().height);
bList[2].setEnabled(false); // disable "Remove Image" button
}
if ((shortPrint) || (longPrint)) // user requested report
{
bList[3].setEnabled(true); // enable "Pick More Points" button
g.setColor(Color.white); // make report area white
if (shortPrint) // use left column for short report
{
xReport=10;
g.fillRect(0,0,135,getSize().height);
}
else // (longPrint)
{ // use image area for long report
xReport=285;
g.fillRect(275,0,getSize().width-275,getSize().height);
} // end shortPrint/longPrint
g.setColor(getForeground());
g.drawString("IMAGE: "+imageName.getText(),xReport,yReport);
t.append("IMAGE: "+imageName.getText()+"\n"); // write to text area
yReport+=12;
g.drawString((signalCounter+1)/2+" clone pairs saved",xReport,yReport);
t.append((signalCounter+1)/2+" clone pairs saved\n");
yReport+=12;
g.drawString("Plate R C Score",xReport,yReport); // R is plate row (filter column)
t.append("Plate\tRow\tCol\tScore\n"); // C is plate column (filter row)
if (inPlateOrder) // user requested plate-ordered report
{
for (int i=0; i(getSize().height-20)) // move to next column
{
xReport+=120;
yReport=36;
}
} // end for
}
else // user requested saved-order report
{
for (int i=0; i(getSize().height-20)) // move to next column
{
yReport=36;
xReport+=120;
}
}
} // end if inPlateOrder/SavedOrder
yReport=12; // reinitialize y-coord
}
else // if not displaying report...
{
if (!removeImage) // and image is on screen
{
bList[3].setEnabled(false); // disable "Pick More Points" button
}
else // image not there; need to restore
{
bList[3].setEnabled(true); // enable "Pick More Points" button
}
// use the leftmost column to show mock x,y grid
g.setColor(getForeground());
g.drawRect(45,105,38,38); // rect graphic as mock filter
g.drawString(""+x1+","+y1,14,104); // show x,y coords on mock filter
g.drawString(""+x2+","+y2,70,154);
g.drawString("Grid is: ",15,169); // check that grid ~ square
g.drawString(""+x3+" across "+y3+" down",15,179);
if ( clonesMatch() ) // public boolean clonesMatch()
{ // if clones from the same plate/well
g.setColor(FUCHSIA); // boxes turn fuchsia-colored
if (doNotSaveAgain) // if clone pair has just been saved
{
bList[1].setEnabled(false); // disable "Save 2 Points" button
}
else // clone pair just picked, not yet saved
{
bList[1].setEnabled(true); // enable "Save 2 Points" button
}
}
else // clones from different plates/wells
{
bList[1].setEnabled(false); // disable "Save 2 Points" button
}
// display clone stats in two boxes in leftmost column
// POINT 1
g.drawString("Point 1",5,215);
g.drawRect(5,220,105,72); // box - filter/plate data
g.drawString ("X: "+p1X,10,237); // coordinates on filter
g.drawString ("Y: "+p1Y,10,250);
g.drawString("Field: "+p1FieldNum,67,237);
g.drawString("Pos: "+p1Position,67,250);
g.drawLine(5,257,108,257);
g.drawString("Plate: "+p1PlateNum,10,272);// plate number
g.drawString("Row: "+p1Column,67,272); // well row = filter column
g.drawString("Col: "+p1RowNum,67,285); // well coordinates
// POINT 2
g.drawString("Point 2",5,321);
g.drawRect(5,326,105,72); // box - filter/plate data
g.drawString ("X: "+p2X,10,343); // coordinates on filter
g.drawString ("Y: "+p2Y,10,356);
g.drawString("Field: "+p2FieldNum,67,343);
g.drawString("Pos: "+p2Position,67,356);
g.drawLine(5,363,108,363);
g.drawString("Plate: "+p2PlateNum,10,378);// plate number
g.drawString("Row: "+p2Column,67,378); // well coordinates
g.drawString("Col: "+p2RowNum,67,391); // well column = filter row
g.drawString("Clone pairs saved: "+(signalCounter+1)/2,5,410);
g.drawString("To save points, Ctrl-click or --->",5,422);
} //end if (long/shortReport)
if (!removeImage) // user hasn't selected removeImage/longPrint option
{
// paint tentatively-selected points as cyan-colored dots
g.setColor(CYAN);
if (p1MouseX > 0) { g.fillOval(p1MouseX,p1MouseY,4,4); }
if (p2MouseX > 0) { g.fillOval(p2MouseX,p2MouseY,4,4); }
// paint saved points as magenta dots
g.setColor(Color.magenta);
for (int i=0; ix1) && (x1>0) && (x2>0) && (!removeImage)) // ref points picked correctly
{
int xA = (int)(.33333*(x2-x1)); // line dividing fields
int xB = (int)(.66666*(x2-x1));
int yA = (int)(.5*(y2-y1));
g.setColor(PURPLE); // stands out more than getForeground()
g.drawRect(x1,y1,x2-x1,y2-y1); // draw border around filter & fields
g.drawLine((x1+xA),y1,(x1+xA),y2); // vertical lines
g.drawLine((x1+xB),y1,(x1+xB),y2);
g.drawLine(x1,(y1+yA),x2,(y1+yA)); // horizontal line
}
if (showHelp) // show help frame window
{
f.setVisible(true);
showHelp=false; // otherwise, help window won't go away
}
else
{
f.setVisible(false);
}
} // end paint()
//*****************************************************************************
void calculateXY()
{
// need to account for space between squares and fields
// spotted area of filter = 21.65 cm x 21.60 cm = grid 433w X 432h
// where 5 mm is one unit (5 mm x 433 = 2165 mm)
// spot width 10 mm = 2 out of 433 across or 432 down
// 4x4 spot square = 8 out of 433 or 432
// space between squares 5 mm = 1 out of 433 or 432
// aisle between fields 10 mm = 2 out of 433 or 432
// e.g., x3=500, y3=500 (dimensions of filter on monitor)
// 433 div by x3 = multiplier; e.g., 433/500 = .866 (float);
// 432/500=.864
// coordinates of image = 0,0 to 433,432
// but need to adjust for user picking reference point just off the filter
// instead of last spotting row/column (192nd spot in row & column)
// The adjustment is 192.0/193.0.
xMultiplier = XSCALE / (int)(X3_Y3_ADJUSTER*x3); // remove off-filter part
yMultiplier = YSCALE / (int)(X3_Y3_ADJUSTER*y3);
// say x1=2,y1=2 and x2=502,y2=502 (filter reference points)
// say mouseX, mouseY = 3, 502 (coordinate of selected signal)
// need to subtract out x1 & y1 ==> spotX=1, spotY=500
spotX = mouseX - x1;
spotY = mouseY - y1;
// multiply by .866 & .864: (spot_433_X, spot_432_Y) = (.866, 432)
// then round to nearest integer
spot_433_X = (int)((spotX * xMultiplier) + .5); // 1
spot_432_Y = (int)((spotY * yMultiplier) + .5); // 432
// Adjust for spot_433_X & spot_432Y values falling in "aisles":
// (Unfortunately, can't be reduced into a formula)
// x-coordinates for aisle locations - arbitrarily assign selected points that fall
// into aisles to the next adjacent valid x-coordinate
inXAisle=true; // code reducer -- assume selected point in a vertical aisle
xAisle='E'; // code reducer -- assume selected point east of a valid spot
if (spot_433_X == 9) { spot_433_X = 8; }
else if (spot_433_X == 18) { spot_433_X = 19; xAisle='W'; }
else if (spot_433_X == 27) { spot_433_X = 26; }
else if (spot_433_X == 36) { spot_433_X = 37; xAisle='W'; }
else if (spot_433_X == 45) { spot_433_X = 44; }
else if (spot_433_X == 54) { spot_433_X = 55; xAisle='W'; }
else if (spot_433_X == 63) { spot_433_X = 62; }
else if (spot_433_X == 72) { spot_433_X = 73; xAisle='W'; }
else if (spot_433_X == 81) { spot_433_X = 80; }
else if (spot_433_X == 90) { spot_433_X = 91; xAisle='W'; }
else if (spot_433_X == 99) { spot_433_X = 98; }
else if (spot_433_X == 108) { spot_433_X = 109; xAisle='W'; }
else if (spot_433_X == 117) { spot_433_X = 116; }
else if (spot_433_X == 126) { spot_433_X = 127; xAisle='W'; }
else if (spot_433_X == 135) { spot_433_X = 134; }
// field aisle
else if (spot_433_X == 144) { spot_433_X = 143; }
else if (spot_433_X == 145) { spot_433_X = 146; xAisle='W'; }
else if (spot_433_X == 154) { spot_433_X = 153; }
else if (spot_433_X == 163) { spot_433_X = 164; xAisle='W'; }
else if (spot_433_X == 172) { spot_433_X = 171; }
else if (spot_433_X == 181) { spot_433_X = 182; xAisle='W'; }
else if (spot_433_X == 190) { spot_433_X = 189; }
else if (spot_433_X == 199) { spot_433_X = 200; xAisle='W'; }
else if (spot_433_X == 208) { spot_433_X = 207; }
else if (spot_433_X == 217) { spot_433_X = 218; xAisle='W'; }
else if (spot_433_X == 226) { spot_433_X = 225; }
else if (spot_433_X == 235) { spot_433_X = 236; xAisle='W'; }
else if (spot_433_X == 244) { spot_433_X = 243; }
else if (spot_433_X == 253) { spot_433_X = 254; xAisle='W'; }
else if (spot_433_X == 262) { spot_433_X = 261; }
else if (spot_433_X == 271) { spot_433_X = 272; xAisle='W'; }
else if (spot_433_X == 280) { spot_433_X = 279; }
// field aisle
else if (spot_433_X == 289) { spot_433_X = 288; }
else if (spot_433_X == 290) { spot_433_X = 291; xAisle='W'; }
else if (spot_433_X == 299) { spot_433_X = 298; }
else if (spot_433_X == 308) { spot_433_X = 309; xAisle='W'; }
else if (spot_433_X == 317) { spot_433_X = 316; }
else if (spot_433_X == 326) { spot_433_X = 327; xAisle='W'; }
else if (spot_433_X == 335) { spot_433_X = 334; }
else if (spot_433_X == 344) { spot_433_X = 345; xAisle='W'; }
else if (spot_433_X == 353) { spot_433_X = 352; }
else if (spot_433_X == 362) { spot_433_X = 363; xAisle='W'; }
else if (spot_433_X == 371) { spot_433_X = 370; }
else if (spot_433_X == 380) { spot_433_X = 381; xAisle='W'; }
else if (spot_433_X == 389) { spot_433_X = 388; }
else if (spot_433_X == 398) { spot_433_X = 399; xAisle='W'; }
else if (spot_433_X == 407) { spot_433_X = 406; }
else if (spot_433_X == 416) { spot_433_X = 417; xAisle='W'; }
else if (spot_433_X == 425) { spot_433_X = 424; }
else { inXAisle=false; xAisle=' '; } // a valid spot on 4x4 clone array
// y-coordinates
inYAisle=true; // code reducer -- assume selected point in a horizontal aisle
yAisle='S'; // code reducer -- assume selected point south of a valid spot
if (spot_432_Y == 9) { spot_432_Y = 10; yAisle='N'; }
else if (spot_432_Y == 18) { spot_432_Y = 17; }
else if (spot_432_Y == 27) { spot_432_Y = 28; yAisle='N'; }
else if (spot_432_Y == 36) { spot_432_Y = 35; }
else if (spot_432_Y == 45) { spot_432_Y = 46; yAisle='N'; }
else if (spot_432_Y == 54) { spot_432_Y = 53; }
else if (spot_432_Y == 63) { spot_432_Y = 64; yAisle='N'; }
else if (spot_432_Y == 72) { spot_432_Y = 71; }
else if (spot_432_Y == 81) { spot_432_Y = 82; yAisle='N'; }
else if (spot_432_Y == 90) { spot_432_Y = 89; }
else if (spot_432_Y == 99) { spot_432_Y = 100; yAisle='N'; }
else if (spot_432_Y == 108) { spot_432_Y = 107; }
else if (spot_432_Y == 117) { spot_432_Y = 118; yAisle='N'; }
else if (spot_432_Y == 126) { spot_432_Y = 125; }
else if (spot_432_Y == 135) { spot_432_Y = 136; yAisle='N'; }
else if (spot_432_Y == 144) { spot_432_Y = 143; }
else if (spot_432_Y == 153) { spot_432_Y = 154; yAisle='N'; }
else if (spot_432_Y == 162) { spot_432_Y = 161; }
else if (spot_432_Y == 171) { spot_432_Y = 172; yAisle='N'; }
else if (spot_432_Y == 180) { spot_432_Y = 179; }
else if (spot_432_Y == 189) { spot_432_Y = 190; yAisle='N'; }
else if (spot_432_Y == 198) { spot_432_Y = 197; }
else if (spot_432_Y == 207) { spot_432_Y = 208; yAisle='N'; }
//field aisle
else if (spot_432_Y == 216) { spot_432_Y = 215; }
else if (spot_432_Y == 217) { spot_432_Y = 218; yAisle='N'; }
else if (spot_432_Y == 226) { spot_432_Y = 225; }
else if (spot_432_Y == 235) { spot_432_Y = 236; yAisle='N'; }
else if (spot_432_Y == 244) { spot_432_Y = 243; }
else if (spot_432_Y == 253) { spot_432_Y = 254; yAisle='N'; }
else if (spot_432_Y == 262) { spot_432_Y = 261; }
else if (spot_432_Y == 271) { spot_432_Y = 272; yAisle='N'; }
else if (spot_432_Y == 280) { spot_432_Y = 279; }
else if (spot_432_Y == 289) { spot_432_Y = 290; yAisle='N'; }
else if (spot_432_Y == 298) { spot_432_Y = 297; }
else if (spot_432_Y == 307) { spot_432_Y = 308; yAisle='N'; }
else if (spot_432_Y == 316) { spot_432_Y = 315; }
else if (spot_432_Y == 325) { spot_432_Y = 326; yAisle='N'; }
else if (spot_432_Y == 334) { spot_432_Y = 333; }
else if (spot_432_Y == 343) { spot_432_Y = 344; yAisle='N'; }
else if (spot_432_Y == 352) { spot_432_Y = 351; }
else if (spot_432_Y == 361) { spot_432_Y = 362; yAisle='N'; }
else if (spot_432_Y == 370) { spot_432_Y = 369; }
else if (spot_432_Y == 379) { spot_432_Y = 380; yAisle='N'; }
else if (spot_432_Y == 388) { spot_432_Y = 387; }
else if (spot_432_Y == 397) { spot_432_Y = 398; yAisle='N'; }
else if (spot_432_Y == 406) { spot_432_Y = 405; }
else if (spot_432_Y == 415) { spot_432_Y = 416; yAisle='N'; }
else if (spot_432_Y == 424) { spot_432_Y = 423; }
else { inYAisle=false; yAisle=' '; }
// spot_433_X minus _*FIELD_AISLE (space between fields) 3
// minus ___*SPOT_AISLE (space between 16-spot squares) 3
// divided by ~2 = spot location on filter w/192x192 spots
if (spot_433_X > 145) // not field 2 or 4, not columns 1-16
{
if (spot_433_X > 290) // field 3 or 5, columns 33-48
{
if (spot_433_X > 425 ) { spot_433_X -= 45*SPOT_AISLE; }
else if (spot_433_X > 416 ) { spot_433_X -= 44*SPOT_AISLE; }
else if (spot_433_X > 407 ) { spot_433_X -= 43*SPOT_AISLE; }
else if (spot_433_X > 398 ) { spot_433_X -= 42*SPOT_AISLE; }
else if (spot_433_X > 389 ) { spot_433_X -= 41*SPOT_AISLE; }
else if (spot_433_X > 380 ) { spot_433_X -= 40*SPOT_AISLE; }
else if (spot_433_X > 371 ) { spot_433_X -= 39*SPOT_AISLE; }
else if (spot_433_X > 362 ) { spot_433_X -= 38*SPOT_AISLE; }
else if (spot_433_X > 353 ) { spot_433_X -= 37*SPOT_AISLE; }
else if (spot_433_X > 344 ) { spot_433_X -= 36*SPOT_AISLE; }
else if (spot_433_X > 335 ) { spot_433_X -= 35*SPOT_AISLE; }
else if (spot_433_X > 326 ) { spot_433_X -= 34*SPOT_AISLE; }
else if (spot_433_X > 317 ) { spot_433_X -= 33*SPOT_AISLE; }
else if (spot_433_X > 308 ) { spot_433_X -= 32*SPOT_AISLE; }
else if (spot_433_X > 299 ) { spot_433_X -= 31*SPOT_AISLE; }
else { spot_433_X -= 30*SPOT_AISLE; }
spot_433_X -= 2*FIELD_AISLE; // field 3 or 5
}
else // <= 290, field 6 or 1, columns 17-32
{
if (spot_433_X > 280 ) { spot_433_X -= 30*SPOT_AISLE; }
else if (spot_433_X > 271 ) { spot_433_X -= 29*SPOT_AISLE; }
else if (spot_433_X > 262 ) { spot_433_X -= 28*SPOT_AISLE; }
else if (spot_433_X > 253 ) { spot_433_X -= 27*SPOT_AISLE; }
else if (spot_433_X > 244 ) { spot_433_X -= 26*SPOT_AISLE; }
else if (spot_433_X > 235 ) { spot_433_X -= 25*SPOT_AISLE; }
else if (spot_433_X > 226 ) { spot_433_X -= 24*SPOT_AISLE; }
else if (spot_433_X > 217 ) { spot_433_X -= 23*SPOT_AISLE; }
else if (spot_433_X > 208 ) { spot_433_X -= 22*SPOT_AISLE; }
else if (spot_433_X > 199 ) { spot_433_X -= 21*SPOT_AISLE; }
else if (spot_433_X > 190 ) { spot_433_X -= 20*SPOT_AISLE; }
else if (spot_433_X > 181 ) { spot_433_X -= 19*SPOT_AISLE; }
else if (spot_433_X > 172 ) { spot_433_X -= 18*SPOT_AISLE; }
else if (spot_433_X > 163 ) { spot_433_X -= 17*SPOT_AISLE; }
else if (spot_433_X > 154 ) { spot_433_X -= 16*SPOT_AISLE; }
else { spot_433_X -= 15*SPOT_AISLE; }
spot_433_X -= FIELD_AISLE; // field 6 or 1
} // end if spot433x > 290
}
else // <= 145, field 2 or 4, columns 1-16
{
if (spot_433_X > 9) // adjust columns 2 to 16 for aisles
{
if (spot_433_X > 135 ) { spot_433_X -= 15*SPOT_AISLE; }
else if (spot_433_X > 126 ) { spot_433_X -= 14*SPOT_AISLE; }
else if (spot_433_X > 117 ) { spot_433_X -= 13*SPOT_AISLE; }
else if (spot_433_X > 108 ) { spot_433_X -= 12*SPOT_AISLE; }
else if (spot_433_X > 99 ) { spot_433_X -= 11*SPOT_AISLE; }
else if (spot_433_X > 90 ) { spot_433_X -= 10*SPOT_AISLE; }
else if (spot_433_X > 81 ) { spot_433_X -= 9*SPOT_AISLE; }
else if (spot_433_X > 72 ) { spot_433_X -= 8*SPOT_AISLE; }
else if (spot_433_X > 63 ) { spot_433_X -= 7*SPOT_AISLE; }
else if (spot_433_X > 54 ) { spot_433_X -= 6*SPOT_AISLE; }
else if (spot_433_X > 45 ) { spot_433_X -= 5*SPOT_AISLE; }
else if (spot_433_X > 36 ) { spot_433_X -= 4*SPOT_AISLE; }
else if (spot_433_X > 27 ) { spot_433_X -= 3*SPOT_AISLE; }
else if (spot_433_X > 18 ) { spot_433_X -= 2*SPOT_AISLE; }
else { spot_433_X -= SPOT_AISLE; }
} // end if spot433x > 9
} // end if spot433x > 145
realSpotX = (spot_433_X - 1)/2 + 1; // spot on 192x192 grid // 1
// spot_432_Y minus FIELD_AISLE minus __*SPOT_AISLE
// divided by ~2 = spot on 192x192 grid
if (spot_432_Y > 217 ) // field 4, 1, or 5, rows 25-48
{
if (spot_432_Y > 424 ) { spot_432_Y -= 46*SPOT_AISLE; } // 1164
else if (spot_432_Y > 415 ) { spot_432_Y -= 45*SPOT_AISLE; }
else if (spot_432_Y > 406 ) { spot_432_Y -= 44*SPOT_AISLE; }
else if (spot_432_Y > 397 ) { spot_432_Y -= 43*SPOT_AISLE; }
else if (spot_432_Y > 388 ) { spot_432_Y -= 42*SPOT_AISLE; }
else if (spot_432_Y > 379 ) { spot_432_Y -= 41*SPOT_AISLE; }
else if (spot_432_Y > 370 ) { spot_432_Y -= 40*SPOT_AISLE; }
else if (spot_432_Y > 361 ) { spot_432_Y -= 39*SPOT_AISLE; }
else if (spot_432_Y > 352 ) { spot_432_Y -= 38*SPOT_AISLE; }
else if (spot_432_Y > 343 ) { spot_432_Y -= 37*SPOT_AISLE; }
else if (spot_432_Y > 334 ) { spot_432_Y -= 36*SPOT_AISLE; }
else if (spot_432_Y > 325 ) { spot_432_Y -= 35*SPOT_AISLE; }
else if (spot_432_Y > 316 ) { spot_432_Y -= 34*SPOT_AISLE; }
else if (spot_432_Y > 307 ) { spot_432_Y -= 33*SPOT_AISLE; }
else if (spot_432_Y > 298 ) { spot_432_Y -= 32*SPOT_AISLE; }
else if (spot_432_Y > 289 ) { spot_432_Y -= 31*SPOT_AISLE; }
else if (spot_432_Y > 280 ) { spot_432_Y -= 30*SPOT_AISLE; }
else if (spot_432_Y > 271 ) { spot_432_Y -= 29*SPOT_AISLE; }
else if (spot_432_Y > 262 ) { spot_432_Y -= 28*SPOT_AISLE; }
else if (spot_432_Y > 253 ) { spot_432_Y -= 27*SPOT_AISLE; }
else if (spot_432_Y > 244 ) { spot_432_Y -= 26*SPOT_AISLE; }
else if (spot_432_Y > 235 ) { spot_432_Y -= 25*SPOT_AISLE; }
else if (spot_432_Y > 226 ) { spot_432_Y -= 24*SPOT_AISLE; }
else { spot_432_Y -= 23*SPOT_AISLE; }
spot_432_Y -= FIELD_AISLE; // 1152
}
else // field 2, 6, or 3, rows 1-24
{
if (spot_432_Y > 9) // adjust rows 2-24 for aisles
{
if (spot_432_Y > 207 ) { spot_432_Y -= 23*SPOT_AISLE; }
else if (spot_432_Y > 198 ) { spot_432_Y -= 22*SPOT_AISLE; }
else if (spot_432_Y > 189 ) { spot_432_Y -= 21*SPOT_AISLE; }
else if (spot_432_Y > 180 ) { spot_432_Y -= 20*SPOT_AISLE; }
else if (spot_432_Y > 171 ) { spot_432_Y -= 19*SPOT_AISLE; }
else if (spot_432_Y > 162 ) { spot_432_Y -= 18*SPOT_AISLE; }
else if (spot_432_Y > 153 ) { spot_432_Y -= 17*SPOT_AISLE; }
else if (spot_432_Y > 144 ) { spot_432_Y -= 16*SPOT_AISLE; }
else if (spot_432_Y > 135 ) { spot_432_Y -= 15*SPOT_AISLE; }
else if (spot_432_Y > 126 ) { spot_432_Y -= 14*SPOT_AISLE; }
else if (spot_432_Y > 117 ) { spot_432_Y -= 13*SPOT_AISLE; }
else if (spot_432_Y > 108 ) { spot_432_Y -= 12*SPOT_AISLE; }
else if (spot_432_Y > 99 ) { spot_432_Y -= 11*SPOT_AISLE; }
else if (spot_432_Y > 90 ) { spot_432_Y -= 10*SPOT_AISLE; }
else if (spot_432_Y > 81 ) { spot_432_Y -= 9*SPOT_AISLE; }
else if (spot_432_Y > 72 ) { spot_432_Y -= 8*SPOT_AISLE; }
else if (spot_432_Y > 63 ) { spot_432_Y -= 7*SPOT_AISLE; }
else if (spot_432_Y > 54 ) { spot_432_Y -= 6*SPOT_AISLE; }
else if (spot_432_Y > 45 ) { spot_432_Y -= 5*SPOT_AISLE; }
else if (spot_432_Y > 36 ) { spot_432_Y -= 4*SPOT_AISLE; }
else if (spot_432_Y > 27 ) { spot_432_Y -= 3*SPOT_AISLE; }
else if (spot_432_Y > 18 ) { spot_432_Y -= 2*SPOT_AISLE; }
else { spot_432_Y -= SPOT_AISLE; }
} // end if spot432y > 9
} // end if spot432y > 217
realSpotY = (spot_432_Y - 1)/2 + 1; // spot on 192x192 grid
} // end calculateXY
//*****************************************************************************
void calculatePlate() // after x-y on 192x192 grid derived from calculateXY()
{
// FIELD SAMPLE x,y=164,93
// x 1-64 and y 1-96 field 2
// x 1-64 and y >96 field 4
if (realSpotX < 65) // x=1
{
// if (realSpotY < 97) { fieldNum = 2; }
// else { fieldNum = 4; } // y=192 therefore field 4
if (realSpotY < 97) { fieldNum = UPPER_LEFT; }
else { fieldNum = LOWER_LEFT; } // y=192 therefore field 4
}
// x 65-128 and y 1-96 field 6
// x 65-128 and y > 96 field 1
else if (realSpotX < 129)
{
// if (realSpotY < 97) { fieldNum = 6; }
// else { fieldNum = 1; }
if (realSpotY < 97) { fieldNum = UPPER_CENTER; }
else { fieldNum = LOWER_CENTER; }
}
// x 129-192 and y 1-96 field 3
// x 129-192 and y >96 field 5
else
{
// if (realSpotY < 97) { fieldNum = 3; }
// else { fieldNum = 5; }
if (realSpotY < 97) { fieldNum = UPPER_RIGHT; }
else { fieldNum = LOWER_RIGHT; }
}
// COLUMN LOCATION ON PLATE
// if field 3/5, subtract 128 from filter column
// if field 6/1, subtract 64
// minus 1, divided by 4 is field column; if = 0, then column P
// minus 1, divided by 4 = 1, then column O
// minus 1, divided by 4 = 2, then column N...
// minus 1, divided by 4 = 15, then column A
// if ( (fieldNum == 3) || (fieldNum == 5) )
if ( (fieldNum == UPPER_RIGHT) || (fieldNum == LOWER_RIGHT) )
{
colNum = (realSpotX - 129) / 4;
}
// else if ( (fieldNum == 6) || (fieldNum == 1) )
else if ( (fieldNum == UPPER_CENTER) || (fieldNum == LOWER_CENTER) )
{
colNum = (realSpotX - 65) / 4;
}
else
{
colNum = (realSpotX - 1) / 4;
}
if (colNum == 0) { column = 'P'; } // col=P for 1,192
else if (colNum == 1) { column = 'O'; }
else if (colNum == 2) { column = 'N'; }
else if (colNum == 3) { column = 'M'; }
else if (colNum == 4) { column = 'L'; }
else if (colNum == 5) { column = 'K'; }
else if (colNum == 6) { column = 'J'; }
else if (colNum == 7) { column = 'I'; }
else if (colNum == 8) { column = 'H'; }
else if (colNum == 9) { column = 'G'; }
else if (colNum == 10) { column = 'F'; }
else if (colNum == 11) { column = 'E'; }
else if (colNum == 12) { column = 'D'; }
else if (colNum == 13) { column = 'C'; }
else if (colNum == 14) { column = 'B'; }
else { column = 'A'; }
// ROW LOCATION ON PLATE
// if field 4, 1, or 5, subtract 96 from filter row
// minus 1, divided by 4 is field row; if = 0, then row 1...
// minus 1, divided by 4 = 23, then row 24
// e.g., y values of 93-96 & 189-192 from well in row 24 on plate
// if ( (fieldNum == 4) || (fieldNum == 5) || (fieldNum == 1) )
if ( (fieldNum == LOWER_LEFT) ||
(fieldNum == LOWER_RIGHT) ||
(fieldNum == LOWER_CENTER) )
{
rowNum = 1 + ((realSpotY - 97)/4); // rowNum=1+(95/4)=24
}
else // field 2, 6, or 3
{
rowNum = 1 + ((realSpotY - 1)/4);
}
// WHICH OF PLATES 1 - 48?
//
// x mod 4 = 1 & y mod 4 =1, then pos 1
// x mod 4 = 1 & y mod 4 =2, then pos 4
// x mod 4 = 1 & y mod 4 =3, then pos 3
// x mod 4 = 1 & y mod 4 =0, then pos 5
// x mod 4 = 2 & y mod 4 =1, then pos 2...
// x mod 4 = 3 & y mod 4 =2, then pos 4...
// x mod 4 = 0 & y mod 4 =3, then pos 7...
// x mod 4 = 0 & y mod 4 =0, then pos 8
if (realSpotX % 4 == 1) // first column in 4x4 clone array
{
if (realSpotY % 4 == 1) { position = 1; }
else if (realSpotY % 4 == 2) { position = 4; }
else if (realSpotY % 4 == 3) { position = 3; }
else { position = 5; } // 192%4=0 so 5
}
else if (realSpotX % 4 == 2) // second column in 4x4 array
{
if (realSpotY % 4 == 1) { position = 2; }
else if (realSpotY % 4 == 2) { position = 5; }
else if (realSpotY % 4 == 3) { position = 2; }
else { position = 6; }
}
else if (realSpotX % 4 == 3) // third column in 4x4 array
{
if (realSpotY % 4 == 1) { position = 3; }
else if (realSpotY % 4 == 2) { position = 4; }
else if (realSpotY % 4 == 3) { position = 1; }
else { position = 8; }
}
else // realSpotX % 4 == 0, the fourth column in 4x4 array
{
if (realSpotY % 4 == 1) { position = 6; }
else if (realSpotY % 4 == 2) { position = 7; }
else if (realSpotY % 4 == 3) { position = 7; }
else { position = 8; }
}
// GET PLATE NUMBER using field & position
// if field 2 pos 1, then plate 2
// if field 2 pos 2, then plate 8...
// if field 2 pos 8, then plate 44
// if field 6 pos 1, then plate 6
plateNum = ( plateMultiplier * 48 ) + (( position - 1 ) * 6 + fieldNum );
// plateNum=(5-1)*6+4=28
} // end calculatePlate()
//*****************************************************************************
public boolean clonesMatch()
{
if ( (p1PlateNum!=0) && // calculations done
(p1PlateNum==p2PlateNum) && // same plate
(p1RowNum==p2RowNum) && // same clone address - row
(p1Column==p2Column) && // & column
(!p1InXAisle) && (!p2InXAisle) && // spot not in aisle
(!p1InYAisle) && (!p2InYAisle) &&
(((p1X==p2X)&&(p1Y!=p2Y)) || // not the exact same spot
((p1X!=p2X)&&(p1Y==p2Y)) ||
((p1X!=p2X)&&(p1Y!=p2Y))) )
{
return true;
}
return false;
} // end clonesMatch()
//*****************************************************************************
public void sortClones()
{
reportByPlate.removeAllElements(); // refresh vectors of previous
outputByPlate.removeAllElements(); // in-plate-order reports
// make copies of the in-saved-order reports
reportByPlate = (Vector)(reportStrings.clone());
outputByPlate = (Vector)(outputStrings.clone());
// Unable to use Arrays.sort as java.util.Arrays couldn't be accessed
// (a security issue); therefore, for-loops were used to do the sorting:
int outerCount; // index for outer for loop
int innerCount;
int lowerNumberIndex; // index for lower "string" in comparison
String tmp; // holding place for string
// Go thru array, find lowest-value string, put at head of line,
// go thru all array elements except first one, find lowest value, put in 2nd spot...
for (outerCount = 0; outerCount < stringCounter-1; outerCount++)
{
lowerNumberIndex = outerCount; // initial assumption
for (innerCount = outerCount + 1; innerCount < stringCounter; innerCount++)
{
// if current string > the next string, it should follow the next string
if ( ((String)(reportByPlate.elementAt(lowerNumberIndex))).compareTo((String)(reportByPlate.elementAt(innerCount))) > 0)
{
lowerNumberIndex = innerCount;// make the next string's index the "lower string index"
} // end if
} // end for (innerCount)
// switch the strings (-->sort report for output to screen)
tmp = (String)(reportByPlate.elementAt(outerCount));
reportByPlate.setElementAt(reportByPlate.elementAt(lowerNumberIndex),outerCount);
reportByPlate.setElementAt(tmp,lowerNumberIndex);
// (-->sort report for output to "Cut/Save" text area)
tmp = (String)(outputByPlate.elementAt(outerCount));
outputByPlate.setElementAt(outputByPlate.elementAt(lowerNumberIndex),outerCount);
outputByPlate.setElementAt(tmp,lowerNumberIndex);
} // end for (outerCount)
} // end sortClones()
//*****************************************************************************
public void saveClones()
{
// POINT 1
xMatchedSignals.addElement((new Integer(p1MouseX))); // cyan/fuchsia dots
yMatchedSignals.addElement((new Integer(p1MouseY)));
signalCounter++;
// POINT 2
xMatchedSignals.addElement((new Integer(p2MouseX)));
yMatchedSignals.addElement((new Integer(p2MouseY)));
signalCounter++;
// save plate/well data (NB: filter column is plate row; filter row is plate column)
location = p1PlateString+" "+p1Column+" "+p1RowString+" "+intensity;
reportStrings.insertElementAt(location,stringCounter); // screen output
// need 2nd vector because "tabs" have strange screen output:
location = p1PlateString+"\t"+p1Column+"\t"+p1RowString+"\t"+intensity;
outputStrings.insertElementAt(location,stringCounter++); // text area output
drawPoint1=false; // once points have been saved,
drawPoint2=false; // clear cyan circles from 4x4 dup pattern
shortPrint=false; // need left column for spot data
longPrint=false; // need image area to hold image
removeImage=false; // keep the image on screen
doNotSaveAgain=true; // once points saved, do not save again
} // end saveClones()
//*****************************************************************************
// Need following so update() doesn't clear screen of previous output (e.g., x1y1)
public void update(Graphics g)
{
paint(g);
}
//****************************************************************************
public void itemStateChanged(ItemEvent ie) // radio button or choice list
{ // --> repaint
longPrint=false; // code reducer - assume long report not required
shortPrint=false; // code reducer - assume short report not required
inPlateOrder=false; // code reducer - assume in-plate-order report not required
if ( whichReport.getSelectedItem().equals("Order Saved") )
{
shortPrint=true; // print short report in left column
// removeImage can be true/false
}
else if ( whichReport.getSelectedItem().equals("Plate Order") )
{
shortPrint=true;
sortClones();
inPlateOrder=true; // print short in-plate-order report
// removeImage can be true/false
}
else if ( whichReport.getSelectedItem().equals(">120, Saved") )
{
longPrint=true; // print long report in image area
removeImage=true;
}
else if ( whichReport.getSelectedItem().equals(">120, Plate") )
{
longPrint=true;
removeImage=true;
sortClones();
inPlateOrder=true; // print long in-plate-order report
}
else // no report requested
{
removeImage=false;
}
if ( whichFilter.getSelectedItem().equals(" 1 | 1-48")) { plateMultiplier = 0; } // the 1st item selected by default
else if ( whichFilter.getSelectedItem().equals(" 2 | 49-96")) { plateMultiplier = 1; }
else if ( whichFilter.getSelectedItem().equals(" 3 | 97-144")) { plateMultiplier = 2; }
else if ( whichFilter.getSelectedItem().equals(" 4 | 145-192")) { plateMultiplier = 3; }
else if ( whichFilter.getSelectedItem().equals(" 5 | 193-240")) { plateMultiplier = 4; }
else if ( whichFilter.getSelectedItem().equals(" 6 | 241-288")) { plateMultiplier = 5; }
else if ( whichFilter.getSelectedItem().equals(" 7 | 289-336")) { plateMultiplier = 6; }
else if ( whichFilter.getSelectedItem().equals(" 8 | 337-384")) { plateMultiplier = 7; }
else if ( whichFilter.getSelectedItem().equals(" 9 | 385-432")) { plateMultiplier = 8; }
else if ( whichFilter.getSelectedItem().equals("10 | 433-480")) { plateMultiplier = 9; }
else if ( whichFilter.getSelectedItem().equals("11 | 481-528")) { plateMultiplier = 10; }
else if ( whichFilter.getSelectedItem().equals("12 | 529-576")) { plateMultiplier = 11; }
else if ( whichFilter.getSelectedItem().equals("13 | 577-624")) { plateMultiplier = 12; }
else if ( whichFilter.getSelectedItem().equals("14 | 625-672")) { plateMultiplier = 13; }
else if ( whichFilter.getSelectedItem().equals("15 | 673-720")) { plateMultiplier = 14; }
else if ( whichFilter.getSelectedItem().equals("16 | 721-768")) { plateMultiplier = 15; }
else if ( whichFilter.getSelectedItem().equals("17 | 769-816")) { plateMultiplier = 16; }
else if ( whichFilter.getSelectedItem().equals("18 | 817-864")) { plateMultiplier = 17; }
else if ( whichFilter.getSelectedItem().equals("19 | 865-912")) { plateMultiplier = 18; }
else if ( whichFilter.getSelectedItem().equals("20 | 913-960")) { plateMultiplier = 19; }
else if ( whichFilter.getSelectedItem().equals("21 | 961-1008")) { plateMultiplier = 20; }
else if ( whichFilter.getSelectedItem().equals("22 | 1009-1056")) { plateMultiplier = 21; }
else if ( whichFilter.getSelectedItem().equals("23 | 1057-1104")) { plateMultiplier = 22; }
else if ( whichFilter.getSelectedItem().equals("24 | 1105-1152")) { plateMultiplier = 23; }
else if ( whichFilter.getSelectedItem().equals("25 | 1153-1200")) { plateMultiplier = 24; }
else if ( whichFilter.getSelectedItem().equals("26 | 1201-1248")) { plateMultiplier = 25; }
else if ( whichFilter.getSelectedItem().equals("27 | 1249-1296")) { plateMultiplier = 26; }
else
{
if ( whichFilter.getSelectedItem().equals("28 | 1297-1344")) { plateMultiplier = 27; }
}
if ( whatIntensity.getSelectedItem().equals("No Rating")) { intensity = ""; } // default
else if ( whatIntensity.getSelectedItem().equals("one..............")) { intensity = "one"; }
else if ( whatIntensity.getSelectedItem().equals("two..............")) { intensity = "two"; }
else if ( whatIntensity.getSelectedItem().equals("three............")) { intensity = "three"; }
else if ( whatIntensity.getSelectedItem().equals("four.............")) { intensity = "four"; }
else { intensity = "five"; }
repaint();
} // end itemStateChanged
//****************************************************************************
public void mouseClicked(MouseEvent me)
{
shortPrint=false; // erase report in left column
if ( cList[0].getState() || cList[1].getState() ) // ref pts
{
if ( cList[0].getState() ) // "Top Left" button selected
{
x1=me.getX() - ADJUSTMENT; // choose point at mouse ptr tip
y1=me.getY() - ADJUSTMENT;
}
else // "Lower Right" button selected
{
x2=me.getX() - ADJUSTMENT;
y2=me.getY() - ADJUSTMENT;
}
if ( ((x2-x1) > 0) && // if both ref pts have been picked
(x1 != 0) && // and in correct relative orientation
(x2 != 0) )
{
// x3=x2-x1 filter width, y3=y2-y1 filter height
x3 = x2-x1; // calculate filter's screen dimensions
y3 = y2-y1;
}
}
else // "Pick Spot" button selected
{
mouseX=me.getX() - ADJUSTMENT; // adj causes selected spot to
mouseY=me.getY() - ADJUSTMENT; // display at mouse pointer tip
calculateXY(); // calc spot's coordinates on filter
calculatePlate(); // calc spot's plate number & well address
// once mouse clicked after 2 points saved-->OK to enable "Save 2 Points" button
doNotSaveAgain=false;
if (me.isControlDown()) // control key held down
{
if (clonesMatch()) // public boolean clonesMatch()
{
saveClones(); // public void saveClones()
}
}
else if (me.isMetaDown()) // if right button clicked,
{ // record data for Point 2
p2Position=position;
p2MouseX=mouseX;
p2MouseY=mouseY;
p2X=realSpotX;
p2Y=realSpotY;
p2PlateNum=plateNum;
p2RowNum=rowNum;
// convert to strings and add leading zero(s) if appropriate
// plate numbers
if (p2PlateNum < 10) { p2PlateString = "000"+String.valueOf(p2PlateNum); }
else if (p2PlateNum < 100) { p2PlateString = "00"+String.valueOf(p2PlateNum); }
else if (p2PlateNum < 1000) { p2PlateString = "0"+String.valueOf(p2PlateNum); }
else { p2PlateString = String.valueOf(p2PlateNum); }
// row numbers
if (p2RowNum < 10) { p2RowString = "0"+String.valueOf(p2RowNum); }
else { p2RowString = String.valueOf(p2RowNum); }
p2Column=column;
p2FieldNum=fieldNum;
drawPoint2=true;
p2InXAisle=inXAisle;
p2InYAisle=inYAisle;
p2YAisle=yAisle;
p2XAisle=xAisle;
}
else // if left button clicked,
{ // record data for Point 1
p1Position=position;
p1MouseX=mouseX;
p1MouseY=mouseY;
p1X=realSpotX;
p1Y=realSpotY;
p1PlateNum=plateNum;
p1RowNum=rowNum;
// convert to strings and add leading zeros as appropriate
// plate numbers
if (p1PlateNum < 10) { p1PlateString = "000"+String.valueOf(p1PlateNum); }
else if (p1PlateNum < 100) { p1PlateString = "00"+String.valueOf(p1PlateNum); }
else if (p1PlateNum < 1000) { p1PlateString = "0"+String.valueOf(p1PlateNum); }
else { p1PlateString = String.valueOf(p1PlateNum); }
// row numbers
if (p1RowNum < 10) { p1RowString = "0"+String.valueOf(p1RowNum); }
else { p1RowString = String.valueOf(p1RowNum); }
p1Column=column;
p1FieldNum=fieldNum;
drawPoint1=true;
p1InXAisle=inXAisle;
p1InYAisle=inYAisle;
p1YAisle=yAisle;
p1XAisle=xAisle;
} // end if Ctrl-key down or left click or right click
} // end if radio button
repaint();
} // end mouseClicked
//****************************************************************************
public void mouseEntered(MouseEvent me) {} // empty implementation instead of
public void mouseExited(MouseEvent me) {} // using MouseAdapter class
public void mousePressed(MouseEvent me) {}
public void mouseReleased(MouseEvent me) {}
public void mouseDragged(MouseEvent me) {}
public void mouseMoved(MouseEvent me) {}
//****************************************************************************
public void actionPerformed(ActionEvent ae)
{
if (ae.getActionCommand().equals("Help"))
{
showHelp=true;
}
else if (ae.getActionCommand().equals("Refresh"))
{
x1=0; x2=0; y1=0; y2=0; x3=0; y3=0;
mouseX=0; p1MouseX=0; p2MouseX=0;
mouseY=0; p1MouseY=0; p2MouseY=0;
spotX=0; spotY=0;
xMultiplier=0; yMultiplier=0;
spot_433_X=0; spot_432_Y=0;
realSpotX=0; p1X=0; p2X=0;
realSpotY=0; p1Y=0; p2Y=0;
xSpot=0; ySpot=0;
plateNum=0; p1PlateNum=0; p2PlateNum=0;
p1PlateString=null; p2PlateString=null;
rowNum=0; p1RowNum=0; p2RowNum=0;
p1RowString=null; p2RowString=null;
plateMultiplier=0;
// colNum=' ';
colNum=0;
column='0'; p1Column='0'; p2Column='0'; // ' '->odd character in Netscape
position=0; p1Position=0; p2Position=0;
fieldNum=0; p1FieldNum=0; p2FieldNum=0;
inPlateOrder=false;
shortPrint=false; longPrint=false;
removeImage=false;
drawPoint1=false; drawPoint2=false;
inXAisle=false; p1InXAisle=false; p2InXAisle=false;
inYAisle=false; p1InYAisle=false; p2InYAisle=false;
showHelp=false;
xAisle=' '; p1XAisle=' '; p2XAisle=' ';
yAisle=' '; p1YAisle=' '; p2YAisle=' ';
xMatchedSignals.removeAllElements();
yMatchedSignals.removeAllElements();
reportStrings.removeAllElements();
outputStrings.removeAllElements();
reportByPlate.removeAllElements();
outputByPlate.removeAllElements();
stringCounter=0;
signalCounter=0;
t.setText("");
whichReport.select("No Report");
whichFilter.select(" 1 | 1-48");
whatIntensity.select("No Rating");
// imageName.setText(""); // (better just have user enter/change file name)
}
else if (ae.getActionCommand().equals("Save 2 Points"))
{
saveClones(); // public void saveClones()
}
else if (ae.getActionCommand().equals("Remove Image"))
{
removeImage=true; // if, e.g., to print screen w/o image
}
else
{
if (ae.getActionCommand().equals("Pick More Points"))
{
longPrint=false; // take away reports
shortPrint=false;
removeImage=false; // bring back image
whichReport.select("No Report");
}
}
repaint();
} // end actionPerformed()
} // end class Hybsweeper
//*****************************************************************************
//****************************************************************************
class HybHelpFrame extends Frame
{
HybHelpFrame(String title) // constructor
{
super(title); // call Frame's constructor
//create an object to handle window events
HybWindowAdapter adapter = new HybWindowAdapter(this);
//register it to receive those events
addWindowListener(adapter);
} // end constructor
public void paint (Graphics g) // text displayed in help box
{
g.drawString("LOADING THE IMAGE:",10,40);
g.drawString("Enter file name of image (must be *.gif or *.jpg) in text field.",10,52);
g.drawString("File must be in the same directory as, or a subdirectory of, that for the applet's",10,64);
g.drawString("html/class files. Examples: image1.gif, subdir_of_images/image1.gif",10,76);
g.drawString("FILTER & PLATE NUMBERS: Select filter number and plate number range.",10,96);
g.drawString("TOP LEFT & BOTTOM RIGHT: (reference points to account for different image sizes)",10,116);
g.drawString("Select \"Top Left\" radio button, then click on upper left-hand corner of spotted area.",10,128);
g.drawString("Select \"Bottom Right\" radio button, then click on bottom right-hand corner.",10,140);
g.drawString("Repeat as necessary until the outline appears just outside of the spotted area.",10,152);
g.drawString("PICK SPOT:",10,172);
g.drawString("Select third radio button and begin picking pairs of hybridization signals.",10,184);
g.drawString("Use right and left buttons on mouse (in any order) to select two spots in a pair.",10,196);
g.drawString("Hint: use 4x4 duplication diagrams as an aid to clicking in right place.",10,208);
g.drawString("REFRESH: Removes reference points and all saved plate/well locations.",10,228);
g.drawString("SAVE 2 POINTS:",10,248);
g.drawString("When two spots \"match\" (have same position number), use \"Save 2 Points\" button to",10,260);
g.drawString("save plate number and well coordinates for that clone.",10,272);
g.drawString("Alternatively, you can Ctrl-click (either Ctrl-right-click or Ctrl-left-click anywhere)",10,284);
g.drawString("to save plate/well data.",10,296);
g.drawString("INTENSITY:",10,316);
g.drawString("If needed, rate the intensity of the signal selected--scale is 1 to 5.",10,328);
g.drawString("REPORT:",10,348);
g.drawString("When you have finished picking and saving points, use pop-up menu to select report:",10,360);
g.drawString(" - Order Saved: Short report of plate/well locations in the order they were saved",10,372);
g.drawString(" - Plate Order: Short report of plate/well locations ordered by plate number",10,384);
g.drawString(" - >120, Saved Order &",10,396);
g.drawString(" - >120, Plate Order: Long report--if more than 120 clone pairs have been saved",10,408);
g.drawString("REMOVE IMAGE provides option of removing image from screen for the short reports.",10,428);
g.drawString("CUT & PASTE TO SAVE:",10,448);
g.drawString("Since applets cannot write to local files, you can save plate/well locations by cutting",10,460);
g.drawString("and pasting from this text area (highlight by clicking in front of first character,",10,472);
g.drawString("scrolling down, then Shift-clicking after last character).",10,484);
g.drawString("PICK MORE POINTS:",10,504);
g.drawString("To reload image and continue selecting any remaining hybridization signals.",10,516);
} // end paint
} // end class HybHelpFrame
//*****************************************************************************
//****************************************************************************
class HybWindowAdapter extends WindowAdapter // need this class so frame will close
{
HybHelpFrame helpFrame;
public HybWindowAdapter(HybHelpFrame helpFrame)
{
this.helpFrame = helpFrame;
}
public void windowClosing(WindowEvent we)
{
helpFrame.setVisible(false); // removes window from screen when closed
}
} // end class HybWindowAdapter
//*****************************************************************************
// END OF PROGRAM
//*****************************************************************************
// ---------------------------------------------------------------------
// This software is a "United States Government Work" under the terms
// of the United States Copyright Act. It was written as part of
// official duties performed by a United States Government employee(s)
// and thus cannot be copyrighted. This software is freely available
// to the public for use. The United States Department of Agriculture
// and the U.S. Government have not placed any restriction on its use
// or reproduction.
// ---------------------------------------------------------------------