// Slab1D.java // Implements a configurable 1D cloud model. The cloud extends a unit // distance from 0 to 1. The data is given in optical depths per unit // length. import java.awt.*; import java.util.*; public class Slab1D extends Cloud { public int Dimension() { return(1); } public Slab1D(double od) { int i; data=new DataSet2D(20,10); data.SetSortOrder(DataSet2D.SORT_Y); for(i=0; i<20; i++) { data.AddElement(new Point2D(od,(double)(i)/19.0)); } } // 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(0)<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))); return(ret); } else { tau-=(density1+density2)*0.01; ret=next; } if(!IsInCloud(ret)) return(ret); } return(ret); } public double OpticalDepth() { int i; double ret=0; for(i=0; i<20; i++) { try { ret+=data.GetElement(i).x; } catch(DataSet.DataException e) {} } return(ret/20.0); } private double OpticalDensity(RTVector r) { double ret; try { ret=data.Interpolate(r.Get(0)); } catch(DataSet2D.InterpolationException e) { return(0.0); } return(ret); } public boolean IsInCloud(RTVector r) { if((r.Get(0)>0.0) && (r.Get(0)<=1.0)) return(true); return(false); } public boolean IsBelowCloud(RTVector r) { if(r.Get(0)<=0.0) return(true); return(false); } public RTVector RandomStartLocation(RTVector dir) { RTVector ret=new RTVector(dir.Dimension()); ret.Set(0,1.0); return(ret); } public void DrawCloud(Panel p) { Graphics g=p.getGraphics(); int j; int edge1,edge2; float white; edge1=0; for(j=18; j>=0; j--) { edge2=p.size().height*(19-j)/19; try { white=(float)(1.0-Math.exp(-data.GetElement(j).x/20.0)); g.setColor(new Color(white,white,1.0f)); g.fillRect(0,edge1,p.size().width,edge2); edge1=edge2; } catch(DataSet.DataException e) {} } } public void DrawPath(Panel p,Vector v) { int i,x1,y1,x2,y2; RTVector rtv; Graphics g=p.getGraphics(); g.setColor(Color.yellow); for(i=1; ip.size().width) x1-=p.size().width; y1=(int)((1.0-rtv.Get(0))*p.size().height); rtv=(RTVector)v.elementAt(i); x2=i; while(x2>p.size().width) x2-=p.size().width; y2=(int)((1.0-rtv.Get(0))*p.size().height); g.drawLine(x1,y1,x2,y2); } } public DataSet2D GetData(int which) { if(which!=0) return(null); return(data); } // For the 1D Slab the data is just the density as a function of height. private DataSet2D data; }