/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display2d; import java.awt.Color; import java.awt.Graphics; import java.awt.Shape; import java.util.Random; import org.opensourcephysics.display.DrawingPanel; import org.opensourcephysics.display.Measurable; /** * A TriangularBinaryLattice is an array where each array element has a value * of 0 or 1. * * @author Joshua Gould * @author Wolfgang Christian * @created May 13, 2003 * @version 1.0 */ public class TriangularBinaryLattice implements Measurable { byte[] packedData; int nrow, ncol; boolean visible = true; double xmin, ymin, xmax, ymax; double xminLattice, yminLattice, xmaxLattice, ymaxLattice; Color zeroColor = Color.red, oneColor = Color.blue; final static double SQRT3_OVER2 = Math.sqrt(3)/2.0; final static int BITS_PER_BYTE = 8; final static int radius = 3; final static int diameter = radius*2; /** * Constructs a binary lattice with the given size. * * @param _nrow the number of rows * @param _ncol the number of columns */ public TriangularBinaryLattice(int _nrow, int _ncol) { nrow = _nrow; ncol = _ncol; int len = ((ncol+(BITS_PER_BYTE-1))/BITS_PER_BYTE)*nrow; // each row starts on a byte boundary packedData = new byte[len]; // default colors are red and blue // col in x direction, row in y direction xminLattice=xmin = 0; xmaxLattice=xmax = ncol-0.5; ymin = nrow*SQRT3_OVER2-SQRT3_OVER2; if(ymin==0) { ymin = SQRT3_OVER2; // FIXME } yminLattice=ymin; ymaxLattice=ymax = 0; // zero is on top } /** * Resize the lattice. * @param _nx number of x sites * @param _ny number of y sites */ public void resizeLattice(int _nrow, int _ncol) { nrow = _nrow; ncol = _ncol; int len = ((ncol+(BITS_PER_BYTE-1))/BITS_PER_BYTE)*nrow; // each row starts on a byte boundary packedData = new byte[len]; // default colors are red and blue // col in x direction, row in y direction xminLattice=xmin = 0; xmaxLattice=xmax = ncol-0.5; ymin = nrow*SQRT3_OVER2-SQRT3_OVER2; if(ymin==0) { ymin = SQRT3_OVER2; // FIXME } yminLattice=ymin; ymaxLattice=ymax = 0; // zero is on top } public void setVisible (boolean _vis) { this.visible = _vis; } public boolean isMeasured() { return true; } public double getXMin() { return xmin; } public double getYMin() { return ymin; } public double getXMax() { return xmax; } public double getYMax() { return ymax; } /** Randomizes the lattice values. */ public void randomize() { Random random = new Random(); random.nextBytes(packedData); } /** * Randomizes the lattice values with the specified probability. A probability * of 1 indicates that all cells will be occupied. * * @param probability the probability of a site being occupied, between 0.0 * and 1.0. */ public void randomize(double probability) { if((probability<0)||(probability>1)) { throw new IllegalArgumentException("Probability must be between 0 and 1"); //$NON-NLS-1$ } Random random = new Random(); for(int i = 0, size = packedData.length; i<size; i++) { byte packedcell = 0; for(int j = BITS_PER_BYTE; j>0; j--) { int mask = 0x80>>>(j-1); // start with 0x10000000 and shift right, 0x80 = 128 double d = random.nextDouble(); // generates number between 0 inclusive and 1 exclusive if(d>=probability) { // set jth bit to 0 packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { // set jth bit to 1 packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } } packedData[i] = packedcell; } } /** * Draws the lattice. * * @param panel * @param g */ public void draw(DrawingPanel panel, Graphics g) { if(!visible) { return; } // drawableDelegate.draw(panel, g); Shape oldClip = g.getClip(); g.setClip(null); double xScale=(xmax-xmin)/(xmaxLattice-xminLattice); double yScale=-(ymax-ymin)/(ymaxLattice-yminLattice); int row = 0; int column = 0; for(int i = 0, size = packedData.length; i<size; i++) { byte packedCell = packedData[i]; for(int j = BITS_PER_BYTE; (j>0)&&(column<ncol); j--) { byte val = (byte) (packedCell>>>(j-1)); int one_or_zero = (val&1); if(one_or_zero==0) { g.setColor(zeroColor); } else { g.setColor(oneColor); } // each row is sqrt(3)/2 offset from previous row if((row%2)==1) { double x=(column+0.5)*xScale+xmin; double y=row*SQRT3_OVER2*yScale+ymin; g.fillOval(panel.xToPix(x)-radius, panel.yToPix(y)-radius, diameter, diameter); // shift to right by 0.5 } else { double x=column*xScale+xmin; double y=row*SQRT3_OVER2*yScale+ymin; g.fillOval(panel.xToPix(x)-radius, panel.yToPix(y)-radius, diameter, diameter); } if(column==(ncol-1)) { column = 0; row++; break; } column++; } } g.setClip(oldClip); } /** * Scales this lattice to the given values in world units. * * @param xmin * @param xmax * @param ymin * @param ymax */ public void setMinMax(double xmin, double xmax, double ymin, double ymax) { this.xmin = xmin; this.xmax = xmax; this.ymin = ymin; this.ymax = ymax; } /** * Sets a block of cells to new values. A cell is set to 1 if the value is >0; * the cell is set to zero otherwise * * @param row_offset * @param col_offset * @param val the array of values */ public void setBlock(int row_offset, int col_offset, int val[][]) { if((row_offset<0)||(row_offset+val.length>nrow)) { throw new IllegalArgumentException("Row index out of range in binary lattice setBlock."); //$NON-NLS-1$ } if((col_offset<0)||(col_offset+val[0].length>ncol)) { throw new IllegalArgumentException("Column index out of range in binary lattice setBlock."); //$NON-NLS-1$ } for(int rindex = row_offset, nr = val.length+row_offset; rindex<nr; rindex++) { for(int cindex = col_offset, nc = val[0].length+col_offset; cindex<nc; cindex++) { int arrayIndex = rindex*((ncol+7)/8)+cindex/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(cindex%8); // start with 0x10000000 and shift right if(val[rindex-row_offset][cindex-col_offset]<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } } } /** * Sets a block of cells to new values. A cell is set to 1 if the value is >0; * the cell is set to zero otherwise * * @param row_offset * @param col_offset * @param val the array of values */ public void setBlock(int row_offset, int col_offset, byte val[][]) { if((row_offset<0)||(row_offset+val.length>nrow)) { throw new IllegalArgumentException("Row index out of range in binary lattice setBlock."); //$NON-NLS-1$ } if((col_offset<0)||(col_offset+val[0].length>ncol)) { throw new IllegalArgumentException("Column index out of range in binary lattice setBlock."); //$NON-NLS-1$ } for(int rindex = row_offset, nr = val.length+row_offset; rindex<nr; rindex++) { for(int cindex = col_offset, nc = val[0].length+col_offset; cindex<nc; cindex++) { int arrayIndex = rindex*((ncol+7)/8)+cindex/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(cindex%8); // start with 0x10000000 and shift right if(val[rindex-row_offset][cindex-col_offset]<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } } } /** * Sets a column of cells to new values. A cell is set to 1 if the value is > * 0; the cell is set to zero otherwise * * @param row_offset * @param col * @param val the array of values */ public void setCol(int row_offset, int col, int val[]) { if((row_offset<0)||(row_offset+val.length>nrow)) { throw new IllegalArgumentException("Row index out of range in binary lattice setCol."); //$NON-NLS-1$ } if((col<0)||(col>=ncol)) { throw new IllegalArgumentException("Column index out of range in binary lattice setCol."); //$NON-NLS-1$ } for(int rindex = row_offset, nr = val.length+row_offset; rindex<nr; rindex++) { int arrayIndex = rindex*((ncol+7)/8)+col/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(col%8); // start with 0x10000000 and shift right if(val[rindex-row_offset]<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } } /** * Sets a column of cells to new values. A cell is set to 1 if the value is > * 0; the cell is set to zero otherwise * * @param row_offset * @param col * @param val the array of values */ public void setCol(int row_offset, int col, byte val[]) { if((row_offset<0)||(row_offset+val.length>nrow)) { throw new IllegalArgumentException("Row index out of range in binary lattice setCol."); //$NON-NLS-1$ } if((col<0)||(col>=ncol)) { throw new IllegalArgumentException("Column index out of range in binary lattice setCol."); //$NON-NLS-1$ } for(int rindex = row_offset, nr = val.length+row_offset; rindex<nr; rindex++) { int arrayIndex = rindex*((ncol+7)/8)+col/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(col%8); // start with 0x10000000 and shift right if(val[rindex-row_offset]<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } } /** * Sets a row of cells to new values starting at the given column. A cell is * set to 1 if the value is >0; the cell is set to zero otherwise * * @param row * @param col_offset the colum offset * @param val the value */ public void setRow(int row, int col_offset, int val[]) { if((row<0)||(row>=nrow)) { throw new IllegalArgumentException("Row index out of range in binary lattice setRow."); //$NON-NLS-1$ } if((col_offset<0)||(col_offset+val.length>ncol)) { throw new IllegalArgumentException("Column index out of range in binary lattice setRow."); //$NON-NLS-1$ } for(int cindex = col_offset, nc = val.length+col_offset; cindex<nc; cindex++) { int arrayIndex = row*((ncol+7)/8)+cindex/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(cindex%8); // start with 0x10000000 and shift right if(val[cindex-col_offset]<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } } /** * Sets a row of cells to new values starting at the given column. A cell is * set to 1 if the value is >0; the cell is set to zero otherwise * * @param row * @param col_offset the colum offset * @param val the value */ public void setRow(int row, int col_offset, byte val[]) { if((row<0)||(row>=nrow)) { throw new IllegalArgumentException("Row index out of range in binary lattice setRow."); //$NON-NLS-1$ } if((col_offset<0)||(col_offset+val.length>ncol)) { throw new IllegalArgumentException("Column index out of range in binary lattice setRow."); //$NON-NLS-1$ } for(int cindex = col_offset, nc = val.length+col_offset; cindex<nc; cindex++) { int arrayIndex = row*((ncol+7)/8)+cindex/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(cindex%8); // start with 0x10000000 and shift right if(val[cindex-col_offset]<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } } /** * Sets a lattice cell to a new value. A cell should take on a value of 0 or * 1. * * @param _row * @param _col * @param val */ public void setCell(int _row, int _col, int val) { if((_row<0)||(_row>=nrow)||(_col<0)||(_col>=ncol)) { throw new IllegalArgumentException("Cell row or column index out of range. row="+_row+" col="+_col); //$NON-NLS-1$ //$NON-NLS-2$ } int arrayIndex = _row*((ncol+7)/8)+_col/8; // each row starts on a byte boundary byte packedcell = packedData[arrayIndex]; int mask = 0x80>>>(_col%8); // start with 0x10000000 and shift right if(val<=0) { packedcell = (byte) (packedcell&~mask); // AND bitwise with mask complement will clear index bit } else { packedcell = (byte) (packedcell|mask); // OR bitwise with mask operation will set index bit } packedData[arrayIndex] = packedcell; } /** * Gets a lattice cell value. Cell values are zero or one. * * @param _row * @param _col * @return the cell value. */ public byte getCell(int _row, int _col) { byte packedcell = packedData[_row*((ncol+7)/8)+_col/8]; // each row starts on a byte boundary int mask = 0x80>>>(_col%8); // start with 0x10000000 and shift right if((packedcell&mask)>0) { return 1; } return 0; } /** * Sets the color palette. The color at the 0th index of the array is set to * the zero color. * * @param colors */ public void setColorPalette(Color[] colors) { if(colors.length!=2) { throw new IllegalArgumentException("Array must have length of 2"); //$NON-NLS-1$ } zeroColor = colors[0]; oneColor = colors[1]; } /** * Sets the color for a single index. * * @param i the value to set the color for. * @param color */ public void setIndexedColor(int i, Color color) { if(i==0) { zeroColor = color; } else { oneColor = color; } } public String toString() { StringBuffer sb = new StringBuffer(nrow*ncol+nrow); //int row = 0; int column = 0; for(int i = 0, size = packedData.length; i<size; i++) { byte packedCell = packedData[i]; for(int j = BITS_PER_BYTE; (j>0)&&(column<ncol); j--) { byte val = (byte) (packedCell>>>(j-1)); int one_or_zero = (val&1); if(one_or_zero==0) { sb.append("0"); //$NON-NLS-1$ } else { sb.append("1"); //$NON-NLS-1$ } if(column==(ncol-1)) { if(i!=(size-1)) { sb.append("\n"); //$NON-NLS-1$ } column = 0; // row++; break; } column++; } } return sb.toString(); } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software 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; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */