// Fractal2D.java // Implements a fractal 2D cloud. import java.awt.*; import java.util.*; public class Fractal2D extends Cloud { public Fractal2D(double od) { int i; data=new DataSet2D(3,3); data.SetSortOrder(DataSet2D.SORT_Y); for(i=0; i<3; i++) { data.AddElement(new Point2D(od,(double)i/2.0)); } match_data=new double[3]; for(i=0; i<3; i++) match_data[i]=0.0; od_grid=new double[GRID_SIZE][GRID_SIZE]; MakeFractalGrid(); } public int Dimension() { return(2); } // The only requirement to use this ScatterAt function is that when the // last component of the vector is zero you are out of the cloud. public RTVector ScatterAt(RTVector r,RTVector dir) { RTVector ret=new RTVector(r),next; double tau,p; double density1,density2; dir.Normalize(); // First calculate an optical depth to use. p=Math.random(); if(p<1e-3) { if(dir.Get(ret.Dimension()-1)<0.0) { ret.Set(ret.Dimension()-1,0.0); } else { ret.Set(ret.Dimension()-1,1.01); } return(ret); } tau=-Math.log(p); // Now figure out where that is in the cloud. while(tau>0.0) { density1=this.OpticalDensity(ret); next=ret.Add(dir.Scale(0.01)); density2=this.OpticalDensity(next); if(tau<(density1+density2)*0.01) { ret=ret.Add(dir.Scale(0.01*tau/((density1+density2)*0.01))); if((!IsInCloud(ret)) && (dir.Get(ret.Dimension()-1)<0.0)) { ret.Set(ret.Dimension()-1,0.0); } return(ret); } else { tau-=(density1+density2)*0.01; ret=next; } if(!IsInCloud(ret)) { if(dir.Get(ret.Dimension()-1)<0.0) ret.Set(ret.Dimension()-1,0.0); return(ret); } } return(ret); } public double OpticalDepth() { int i; double ret=0; for(i=0; i=GRID_SIZE) xbin=GRID_SIZE-1; if(xbin<0) xbin=0; ybin=(int)(r.Get(1)*GRID_SIZE); if(ybin>=GRID_SIZE) ybin=GRID_SIZE-1; if(ybin<0) ybin=0; return(od_grid[ybin][xbin]); } public boolean IsInCloud(RTVector r) { return((r.Get(1)<=1.0) && (r.Get(1)>0.0) && (r.Get(0)<=1.0) && (r.Get(0)>0.0)); } public boolean IsBelowCloud(RTVector r) { return(r.Get(1)<=0.0); } public RTVector RandomStartLocation(RTVector dir) { RTVector ret=new RTVector(2); ret.Set(0,0.5); ret.Set(1,1.0); return(ret); } public void DrawCloud(Panel p) { Graphics g=p.getGraphics(); int i,j,x1,y1,x2,y2; float white; MakeFractalGrid(); x1=0; for(i=0; i0) return(null); return(data); } private void MakeFractalGrid() { int i,j; boolean flag=false; double offset; for(i=0; i<3; i++) { try { if(data.GetElement(i).x!=match_data[i]) flag=true; match_data[i]=data.GetElement(i).x; } catch(DataSet.DataException e) {} } if(flag) { od_grid[0][0]=match_data[0]; od_grid[GRID_SIZE-1][0]=match_data[0]; od_grid[0][GRID_SIZE-1]=match_data[2]; od_grid[GRID_SIZE-1][GRID_SIZE-1]=match_data[2]; od_grid[GRID_SIZE/2][GRID_SIZE/2]=match_data[1]; offset=(match_data[0]+match_data[1]+match_data[2])/2.0; od_grid[GRID_SIZE/2][0]=(od_grid[0][0]+od_grid[GRID_SIZE-1][0])/2.0+offset*(Math.random()-0.5); od_grid[GRID_SIZE/2][GRID_SIZE-1]=(od_grid[0][GRID_SIZE-1]+od_grid[GRID_SIZE-1][GRID_SIZE-1])/2.0+offset*(Math.random()-0.5); od_grid[0][GRID_SIZE/2]=(od_grid[0][0]+od_grid[0][GRID_SIZE-1])/2.0+offset*(Math.random()-0.5); od_grid[GRID_SIZE-1][GRID_SIZE/2]=(od_grid[GRID_SIZE-1][0]+od_grid[GRID_SIZE-1][GRID_SIZE-1])/2.0+offset*(Math.random()-0.5); RecursiveGridFill(0,0,GRID_SIZE/2,GRID_SIZE/2,offset/2); RecursiveGridFill(0,GRID_SIZE/2,GRID_SIZE/2,GRID_SIZE-1,offset/2); RecursiveGridFill(GRID_SIZE/2,0,GRID_SIZE-1,GRID_SIZE/2,offset/2); RecursiveGridFill(GRID_SIZE/2,GRID_SIZE/2,GRID_SIZE-1,GRID_SIZE-1,offset/2); for(i=0; i=x2-1) return; od_grid[midx][midy]=(od_grid[x1][y1]+od_grid[x2][y2]+od_grid[x1][y2]+od_grid[x2][y1])/4.0+offset*(Math.random()-0.5); od_grid[midx][y1]=(od_grid[x1][y1]+od_grid[x2][y1])/2.0+offset*(Math.random()-0.5); od_grid[midx][y2]=(od_grid[x1][y2]+od_grid[x2][y2])/2.0+offset*(Math.random()-0.5); od_grid[x1][midy]=(od_grid[x1][y1]+od_grid[x1][y2])/2.0+offset*(Math.random()-0.5); od_grid[x2][midy]=(od_grid[x2][y1]+od_grid[x2][y2])/2.0+offset*(Math.random()-0.5); RecursiveGridFill(x1,y1,midx,midy,offset/2.0); RecursiveGridFill(x1,midy,midx,y2,offset/2.0); RecursiveGridFill(midx,y1,x2,midy,offset/2.0); RecursiveGridFill(midx,midy,x2,y2,offset/2.0); } private DataSet2D data; private double match_data[]; private final int GRID_SIZE=33; private double od_grid[][]; }