/********************************************************* Instances of the Configuration class are complete descriptions of the system at a given time. *********************************************************/ import java.util.Random; public class Configuration { // Size of triangulation int xsize,ysize; // Data to store the configuration Vec3[][] x; Vec3[][] na; Vec3[][] nb; // Random number generator Random random; // Workspace for localBending Vec3[][] localna; Vec3[][] localnb; // One fixed point to remove zeroth order mode int xfixed,yfixed; // Used to draw private int idraw,jdraw,kdraw; private int[][] facesx, facesy; // ** this bit will only work with square triangulations ** // ** used to work out hexagon to display ** private int halfSize; // Constants static float sqrt2=(float)Math.sqrt(2.0); static float invSqrt2=(float)(1.0/Math.sqrt(2.0)); static float sqrt3over2=(float)(Math.sqrt(3.0)/2.0); static float invSqrt3over2=(float)(2.0/Math.sqrt(3.0)); Configuration(int xxsize, int yysize) { int i,j; xsize=xxsize; ysize=yysize; xfixed=xsize/2; yfixed=ysize/2; // create a new configuration object x=new Vec3[xsize][ysize]; na=new Vec3[xsize][ysize]; // could just be size-1 big nb=new Vec3[xsize][ysize]; // could just be size-1 big for (i=0;i (double)random.nextFloat() ) { localUpdate(i,j,trial); accepted++; } } } measure(); return(accepted); } private void localUpdate(int i, int j, Vec3 trial) { /* This doesn't worry about i=xsize or j=ysize as we expect the na and nb arrays to be oversize */ int ii, jj; x[i][j].setValue(trial); if ((ii=i-1)>=0) { if ((jj=j-1)>=0) { na[ii][jj]=localna[0][0]; nb[ii][jj]=localnb[0][0]; } na[ii][j]=localna[0][1]; } if ((jj=j-1)>=0) { nb[i][jj]=localnb[1][0]; } na[i][j]=localna[1][1]; nb[i][j]=localnb[1][1]; } /** Calculates Gaussian stretching energy of the form |x-x'|^2 for all nearest neighbours x' around x at (i,j). Free boundary conditions, ie. no boundary energy. */ private float localGaussian(int i, int j, Vec3 centrePoint) { int ii,jj; float energy; energy=(float)0.0; if ((ii=i-1)>=0) { energy=Vec3.distSqd(centrePoint,x[ii][j]); if ((jj=j-1)>=0) { energy=energy+Vec3.distSqd(centrePoint,x[ii][jj]); } } if ((jj=j-1)>=0) { energy=energy+Vec3.distSqd(centrePoint,x[i][jj]); } if ((jj=j+1)=0) { if ((jj=j-1)>=0) { localnb[0][0].normal(centrePoint,x[ii][j],x[ii][jj]); localna[0][0].normal(centrePoint,x[ii][jj],x[i][jj]); } else { localnb[0][0].setZero(); localna[0][0].setZero(); } if ((jj=j+1)=0) { localnb[1][0].normal(centrePoint,x[i][jj],x[ii][j]); } else { localnb[1][0].setZero(); } } /* Now use normals to calculate bending energy */ /* Stage 1: between six triangles around centrePoint. All normals that don't exist are set to zero so we can just calculate blindly. */ energy=Vec3.dot(localna[0][0],localnb[0][0])+ Vec3.dot(localnb[0][0],localna[0][1])+ Vec3.dot(localna[0][1],localnb[1][1])+ Vec3.dot(localnb[1][1],localna[1][1])+ Vec3.dot(localna[1][1],localnb[1][0])+ Vec3.dot(localnb[1][0],localna[0][0]); /* Stage 2: outward from six triangles around centrePoint. Here we must think about which of the far normals exist. However, if the far normal exists then the one for the triangle touching centrePoint must also exist. */ if (((ii=i-2)>=0) && ((jj=j-1)>=0)) { energy=energy+Vec3.dot(na[ii][jj],localnb[0][0]); } if (((ii=i-1)>=0) && (j=0)) { energy=energy+Vec3.dot(na[i][jj],localnb[1][0]); } if (((ii=i-1)>=0) && ((jj=j-2)>=0)) { energy=energy+Vec3.dot(nb[ii][jj],localna[0][0]); } return(energy); } public void measure() { float energy; energy=globalGaussian(); System.out.println(" "+String.valueOf(energy)); } /** Calculates Gaussian stretching energy of the form |x-x'|^2 for all nearest neighbour pairs x and x'. Free boundary conditions, ie. no boundary energy. */ private float globalGaussian() { int i,j,ii,jj; float energy; energy=(float)0.0; for (i=0;iwidth pixels by height pixels. * The method nextFace() is used to get each face in turn. */ public void newPaint(int width, int height) { int i,j,xoffset, yoffset; float a,b,scale; halfSize=ysize/(int)2; // reset drawing counters idraw=xsize-2; jdraw=ysize-2; kdraw=-1; // work out how to scale picture a=(float)width/((float)(xsize+ysize/2)); b=(float)height/(float)ysize; if (anewPaint(...) method this method is used to update the face[6] array with the coordinates of the next face to be drawn (three x and three y ordinates). The return value is true if coordinates are returned, false otherwise indicating that all faces have been read. */ public boolean nextFace(int[] facex, int[] facey) { do { kdraw++; if (kdraw==2) { idraw--; if (idraw==0) { idraw=xsize-2; jdraw--; if (jdraw==0) return(false); } kdraw=0; } } while ( ((idraw-jdraw)<-halfSize) || (((idraw-jdraw)==-halfSize) && (kdraw==1)) || ((idraw-jdraw)>halfSize) || (((idraw-jdraw)==halfSize) && (kdraw==0)) ); facex[0]=facesx[idraw][jdraw]; facey[0]=facesy[idraw][jdraw]; facex[3]=facex[0]; facey[3]=facey[0]; facex[1]=facesx[idraw+1][jdraw+1]; facey[1]=facesy[idraw+1][jdraw+1]; if (kdraw==0) { // faces b facex[2]=facesx[idraw+1][jdraw]; facey[2]=facesy[idraw+1][jdraw]; } else { // faces a facex[2]=facesx[idraw][jdraw+1]; facey[2]=facesy[idraw][jdraw+1]; } return(true); } }