// Ripple.java (c) 2001 by Paul Falstad, www.falstad.com
import java.io.InputStream;
import java.awt.*;
import java.applet.Applet;
import java.applet.AudioClip;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.File;
import java.net.URL;
import java.util.Random;
import java.util.Arrays;
import java.awt.image.*;
import java.lang.Math;
import java.awt.event.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
class RippleCanvas extends Canvas {
RippleFrame pg;
RippleCanvas(RippleFrame p) {
pg = p;
}
public Dimension getPreferredSize() {
return new Dimension(300,400);
}
public void update(Graphics g) {
pg.updateRipple(g);
}
public void paint(Graphics g) {
pg.updateRipple(g);
}
};
class RippleLayout implements LayoutManager {
public RippleLayout() {}
public void addLayoutComponent(String name, Component c) {}
public void removeLayoutComponent(Component c) {}
public Dimension preferredLayoutSize(Container target) {
return new Dimension(500, 500);
}
public Dimension minimumLayoutSize(Container target) {
return new Dimension(100,100);
}
public void layoutContainer(Container target) {
Insets insets = target.insets();
int targetw = target.size().width - insets.left - insets.right;
int cw = targetw* 7/10;
if (target.getComponentCount() == 1)
cw = targetw;
int targeth = target.size().height - (insets.top+insets.bottom);
target.getComponent(0).move(insets.left, insets.top);
target.getComponent(0).resize(cw, targeth);
int barwidth = targetw - cw;
cw += insets.left;
int i;
int h = insets.top;
for (i = 1; i < target.getComponentCount(); i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = m.getPreferredSize();
if (m instanceof Scrollbar)
d.width = barwidth;
if (m instanceof Choice && d.width > barwidth)
d.width = barwidth;
if (m instanceof Label) {
h += d.height/5;
d.width = barwidth;
}
m.move(cw, h);
m.resize(d.width, d.height);
h += d.height;
}
}
}
};
public class Ripple extends Applet implements ComponentListener {
static RippleFrame ogf;
void destroyFrame() {
if (ogf != null)
ogf.dispose();
ogf = null;
repaint();
}
boolean started = false;
public void init() {
addComponentListener(this);
}
public static void main(String args[]) {
ogf = new RippleFrame(null);
ogf.init();
}
void showFrame() {
if (ogf == null) {
started = true;
ogf = new RippleFrame(this);
ogf.init();
repaint();
}
}
public void paint(Graphics g) {
String s = "Applet is open in a separate window.";
if (!started)
s = "Applet is starting.";
else if (ogf == null)
s = "Applet is finished.";
else if (ogf.useFrame)
ogf.triggerShow();
g.drawString(s, 10, 30);
}
public void componentHidden(ComponentEvent e){}
public void componentMoved(ComponentEvent e){}
public void componentShown(ComponentEvent e) { showFrame(); }
public void componentResized(ComponentEvent e) {}
public void destroy() {
if (ogf != null)
ogf.dispose();
ogf = null;
repaint();
}
};
class RippleFrame extends Frame
implements ComponentListener, ActionListener, AdjustmentListener,
MouseMotionListener, MouseListener, ItemListener {
Thread engine = null;
Dimension winSize;
Image dbimage;
Random random;
int gridSizeX;
int gridSizeY;
int gridSizeXY;
int gw;
int windowWidth = 50;
int windowHeight = 50;
int windowOffsetX = 0;
int windowOffsetY = 0;
int windowBottom = 0;
int windowRight = 0;
public static final int sourceRadius = 7;
public static final double freqMult = .0233333;
public String getAppletInfo() {
return "Ripple by Paul Falstad";
}
Container main;
Button blankButton;
Button blankWallsButton;
Button borderButton;
Button exportButton;
Checkbox stoppedCheck;
Checkbox fixedEndsCheck;
Checkbox view3dCheck;
Choice modeChooser;
Choice sourceChooser;
Choice setupChooser;
Choice colorChooser;
Vector setupList;
Setup setup;
Scrollbar dampingBar;
Scrollbar speedBar;
Scrollbar freqBar;
Scrollbar resBar;
Scrollbar brightnessBar;
Scrollbar auxBar;
Label auxLabel;
double dampcoef;
double freqTimeZero;
double movingSourcePos = 0;
double brightMult = 1;
static final double pi = 3.14159265358979323846;
float func[];
float funci[];
float damp[];
boolean walls[];
boolean exceptional[];
int medium[];
OscSource sources[];
static final int MODE_SETFUNC = 0;
static final int MODE_WALLS = 1;
static final int MODE_MEDIUM = 2;
static final int MODE_FUNCHOLD = 3;
int dragX, dragY, dragStartX = -1, dragStartY;
int selectedSource = -1;
int sourceIndex;
int freqBarValue;
boolean dragging;
boolean dragClear;
boolean dragSet;
public boolean useFrame;
boolean showControls;
double t;
MemoryImageSource imageSource;
int pixels[];
int sourceCount = -1;
boolean sourcePlane = false;
boolean sourceMoving = false;
boolean increaseResolution = false;
boolean adjustResolution = true;
int sourceFreqCount = -1;
int sourceWaveform = SWF_SIN;
int auxFunction;
long startTime;
Color wallColor, posColor, negColor, zeroColor,
medColor, posMedColor, negMedColor, sourceColor;
Color schemeColors[][];
Method timerMethod;
int timerDiv;
ImportDialog impDialog;
static final int mediumMax = 191;
static final double mediumMaxIndex = .5;
static final int SWF_SIN = 0;
static final int SWF_SQUARE = 1;
static final int SWF_PULSE = 2;
static final int AUX_NONE = 0;
static final int AUX_PHASE = 1;
static final int AUX_FREQ = 2;
static final int AUX_SPEED = 3;
static final int SRC_NONE = 0;
static final int SRC_1S1F = 1;
static final int SRC_2S1F = 3;
static final int SRC_2S2F = 4;
static final int SRC_4S1F = 6;
static final int SRC_1S1F_PULSE = 8;
static final int SRC_1S1F_MOVING = 9;
static final int SRC_1S1F_PLANE = 10;
static final int SRC_2S1F_PLANE = 12;
static final int SRC_1S1F_PLANE_PULSE = 14;
static final int SRC_1S1F_PLANE_PHASE = 15;
static final int SRC_6S1F = 16;
static final int SRC_8S1F = 17;
static final int SRC_10S1F = 18;
static final int SRC_12S1F = 19;
static final int SRC_16S1F = 20;
static final int SRC_20S1F = 21;
int getrand(int x) {
int q = random.nextInt();
if (q < 0) q = -q;
return q % x;
}
RippleCanvas cv;
Ripple applet;
RippleFrame(Ripple a) {
super("Ripple Tank Applet v1.7f");
applet = a;
useFrame = true;
showControls = true;
adjustResolution = true;
}
boolean useBufferedImage = false;
public void init() {
try {
if (applet != null) {
String param = applet.getParameter("useFrame");
if (param != null && param.equalsIgnoreCase("false"))
useFrame = false;
param = applet.getParameter("showControls");
if (param != null && param.equalsIgnoreCase("false"))
showControls = false;
}
} catch (Exception e) { e.printStackTrace(); }
if (useFrame)
main = this;
else
main = applet;
setupList = new Vector();
Setup s = new SingleSourceSetup();
while (s != null) {
setupList.addElement(s);
s = s.createNext();
}
String os = System.getProperty("os.name");
int res = 110;
String jv = System.getProperty("java.class.version");
double jvf = new Double(jv).doubleValue();
if (jvf >= 48)
useBufferedImage = true;
try {
Class sysclass = Class.forName("java.lang.System");
timerMethod = sysclass.getMethod("nanoTime", null);
timerDiv = 1000000;
if (timerMethod == null) {
timerMethod = sysclass.getMethod("currentTimeMillis", null);
timerDiv = 1;
}
} catch (Exception ee) {
ee.printStackTrace();
}
sources = new OscSource[20];
main.setLayout(new RippleLayout());
cv = new RippleCanvas(this);
cv.addComponentListener(this);
cv.addMouseMotionListener(this);
cv.addMouseListener(this);
main.add(cv);
setupChooser = new Choice();
int i;
for (i = 0; i != setupList.size(); i++)
setupChooser.add("Setup: " +
((Setup) setupList.elementAt(i)).getName());
setupChooser.addItemListener(this);
if (showControls)
main.add(setupChooser);
//add(new Label("Source mode:", Label.CENTER));
sourceChooser = new Choice();
sourceChooser.add("No Sources");
sourceChooser.add("1 Src, 1 Freq");
sourceChooser.add("1 Src, 2 Freq");
sourceChooser.add("2 Src, 1 Freq");
sourceChooser.add("2 Src, 2 Freq");
sourceChooser.add("3 Src, 1 Freq");
sourceChooser.add("4 Src, 1 Freq");
sourceChooser.add("1 Src, 1 Freq (Square)");
sourceChooser.add("1 Src, 1 Freq (Pulse)");
sourceChooser.add("1 Moving Src");
sourceChooser.add("1 Plane Src, 1 Freq");
sourceChooser.add("1 Plane Src, 2 Freq");
sourceChooser.add("2 Plane Src, 1 Freq");
sourceChooser.add("2 Plane Src, 2 Freq");
sourceChooser.add("1 Plane 1 Freq (Pulse)");
sourceChooser.add("1 Plane 1 Freq w/Phase");
sourceChooser.add("6 Src, 1 Freq");
sourceChooser.add("8 Src, 1 Freq");
sourceChooser.add("10 Src, 1 Freq");
sourceChooser.add("12 Src, 1 Freq");
sourceChooser.add("16 Src, 1 Freq");
sourceChooser.add("20 Src, 1 Freq");
sourceChooser.select(SRC_1S1F);
sourceChooser.addItemListener(this);
if (showControls)
main.add(sourceChooser);
//add(new Label("Mouse mode:", Label.CENTER));
modeChooser = new Choice();
modeChooser.add("Mouse = Edit Wave");
modeChooser.add("Mouse = Edit Walls");
modeChooser.add("Mouse = Edit Medium");
modeChooser.add("Mouse = Hold Wave");
modeChooser.addItemListener(this);
if (showControls)
main.add(modeChooser);
else
modeChooser.select(1);
colorChooser = new Choice();
colorChooser.addItemListener(this);
if (showControls)
main.add(colorChooser);
blankButton = new Button("Clear Waves");
if (showControls)
main.add(blankButton);
blankButton.addActionListener(this);
blankWallsButton = new Button("Clear Walls");
if (showControls)
main.add(blankWallsButton);
blankWallsButton.addActionListener(this);
borderButton = new Button("Add Border");
if (showControls)
main.add(borderButton);
borderButton.addActionListener(this);
exportButton = new Button("Import/Export");
if (showControls)
main.add(exportButton);
exportButton.addActionListener(this);
stoppedCheck = new Checkbox("Stopped");
stoppedCheck.addItemListener(this);
if (showControls)
main.add(stoppedCheck);
fixedEndsCheck = new Checkbox("Fixed Edges", true);
fixedEndsCheck.addItemListener(this);
if (showControls)
main.add(fixedEndsCheck);
view3dCheck = new Checkbox("3-D View");
view3dCheck.addItemListener(this);
if (showControls)
main.add(view3dCheck);
Label l = new Label("Simulation Speed", Label.CENTER);
speedBar = new Scrollbar(Scrollbar.HORIZONTAL, 8, 1, 1, 100);
if (showControls) {
main.add(l);
main.add(speedBar);
}
speedBar.addAdjustmentListener(this);
l = new Label("Resolution", Label.CENTER);
resBar = new Scrollbar(Scrollbar.HORIZONTAL, res, 5, 5, 400);
if (showControls) {
main.add(l);
main.add(resBar);
}
resBar.addAdjustmentListener(this);
setResolution();
l = new Label("Damping", Label.CENTER);
dampingBar = new Scrollbar(Scrollbar.HORIZONTAL, 10, 1, 2, 100);
dampingBar.addAdjustmentListener(this);
if (showControls) {
main.add(l);
main.add(dampingBar);
}
l = new Label("Source Frequency", Label.CENTER);
freqBar = new Scrollbar(Scrollbar.HORIZONTAL,
freqBarValue = 15, 1, 1, 30);
freqBar.addAdjustmentListener(this);
if (showControls) {
main.add(l);
main.add(freqBar);
}
l = new Label("Brightness", Label.CENTER);
brightnessBar = new Scrollbar(Scrollbar.HORIZONTAL,
27, 1, 1, 1200);
brightnessBar.addAdjustmentListener(this);
if (showControls) {
main.add(l);
main.add(brightnessBar);
}
auxLabel = new Label("", Label.CENTER);
auxBar = new Scrollbar(Scrollbar.HORIZONTAL, 1, 1, 1, 30);
auxBar.addAdjustmentListener(this);
if (showControls) {
main.add(auxLabel);
main.add(auxBar);
}
if (showControls)
main.add(new Label(""));
schemeColors = new Color[20][8];
try {
String param;
param = applet.getParameter("setup");
if (param != null)
setupChooser.select(Integer.parseInt(param));
param = applet.getParameter("setupClass");
if (param != null) {
for (i = 0; i != setupList.size(); i++) {
if (setupList.elementAt(i).getClass().getName().
equalsIgnoreCase("RippleFrame$" + param))
break;
}
if (i != setupList.size())
setupChooser.select(i);
}
for (i = 0; i != 20; i++) {
param = applet.getParameter("colorScheme" + (i+1));
if (param == null)
break;
decodeColorScheme(i, param);
}
} catch (Exception e) { if (applet != null) e.printStackTrace(); }
if (colorChooser.getItemCount() == 0)
addDefaultColorScheme();
doColor();
random = new Random();
setDamping();
setup = (Setup) setupList.elementAt(setupChooser.getSelectedIndex());
reinit();
cv.setBackground(Color.black);
cv.setForeground(Color.lightGray);
startTime = getTimeMillis();
if (useFrame) {
resize(800, 640);
handleResize();
Dimension x = getSize();
Dimension screen = getToolkit().getScreenSize();
setLocation((screen.width - x.width)/2,
(screen.height - x.height)/2);
show();
} else {
hide();
handleResize();
applet.validate();
}
main.requestFocus();
}
void reinit() { reinit(true); }
void reinit(boolean setup) {
sourceCount = -1;
System.out.print("reinit " + gridSizeX + " " + gridSizeY + "\n");
gridSizeXY = gridSizeX*gridSizeY;
gw = gridSizeY;
func = new float[gridSizeXY];
funci = new float[gridSizeXY];
damp = new float[gridSizeXY];
exceptional = new boolean[gridSizeXY];
medium = new int[gridSizeXY];
walls = new boolean[gridSizeXY];
int i, j;
for (i = 0; i != gridSizeXY; i++)
damp[i] = 1f; // (float) dampcoef;
for (i = 0; i != windowOffsetX; i++)
for (j = 0; j != gridSizeX; j++)
damp[i+j*gw] = damp[gridSizeX-1-i+gw*j] =
damp[j+gw*i] = damp[j+(gridSizeY-1-i)*gw] =
(float) (.999-(windowOffsetX-i) * .002);
if (setup)
doSetup();
}
boolean shown = false;
public void triggerShow() {
if (!shown)
show();
shown = true;
}
void handleResize() {
Dimension d = winSize = cv.getSize();
if (winSize.width == 0)
return;
pixels = null;
if (useBufferedImage) {
try {
/* simulate the following code using reflection:
dbimage = new BufferedImage(d.width, d.height,
BufferedImage.TYPE_INT_RGB);
DataBuffer db = (DataBuffer)(((BufferedImage)dbimage).
getRaster().getDataBuffer());
DataBufferInt dbi = (DataBufferInt) db;
pixels = dbi.getData();
*/
Class biclass = Class.forName("java.awt.image.BufferedImage");
Class dbiclass = Class.forName("java.awt.image.DataBufferInt");
Class rasclass = Class.forName("java.awt.image.Raster");
Constructor cstr = biclass.getConstructor(
new Class[] { int.class, int.class, int.class });
dbimage = (Image) cstr.newInstance(new Object[] {
new Integer(d.width), new Integer(d.height),
new Integer(BufferedImage.TYPE_INT_RGB)});
Method m = biclass.getMethod("getRaster", null);
Object ras = m.invoke(dbimage, null);
Object db = rasclass.getMethod("getDataBuffer", null).
invoke(ras, null);
pixels = (int[])
dbiclass.getMethod("getData", null).invoke(db, null);
} catch (Exception ee) {
// ee.printStackTrace();
System.out.println("BufferedImage failed");
}
}
if (pixels == null) {
pixels = new int[d.width*d.height];
int i;
for (i = 0; i != d.width*d.height; i++)
pixels[i] = 0xFF000000;
imageSource = new MemoryImageSource(d.width, d.height, pixels, 0,
d.width);
imageSource.setAnimated(true);
imageSource.setFullBufferUpdates(true);
dbimage = cv.createImage(imageSource);
}
}
public boolean handleEvent(Event ev) {
if (ev.id == Event.WINDOW_DESTROY) {
destroyFrame();
return true;
}
return super.handleEvent(ev);
}
void destroyFrame() {
if (applet == null)
dispose();
else
applet.destroyFrame();
}
void doBlank() {
int x, y;
// I set all the elements in the grid to 1e-10 instead of 0 because
// if I set them to zero, then the simulation slows down for a
// short time until the grid fills up again. Don't ask me why!
// I don't know. This showed up when I started using floats
// instead of doubles.
for (x = 0; x != gridSizeXY; x++)
func[x] = funci[x] = 1e-10f;
}
void doBlankWalls() {
int x, y;
for (x = 0; x != gridSizeXY; x++) {
walls[x] = false;
medium[x] = 0;
}
calcExceptions();
}
void doBorder() {
int x, y;
for (x = 0; x < gridSizeX; x++) {
setWall(x, windowOffsetY);
setWall(x, windowBottom);
}
for (y = 0; y < gridSizeY; y++) {
setWall(windowOffsetX, y);
setWall(windowRight, y);
}
calcExceptions();
}
void setWall(int x, int y) { walls[x+gw*y] = true; }
void setWall(int x, int y, boolean b) { walls[x+gw*y] = b; }
void setMedium(int x, int y, int q) { medium[x+gw*y] = q; }
long getTimeMillis() {
try {
Long time = (Long) timerMethod.invoke(null, new Object[] { } );
return time.longValue() / timerDiv;
} catch (Exception ee) { ee.printStackTrace(); return 0; }
}
void calcExceptions() {
int x, y;
// if walls are in place on border, need to extend that through
// hidden area to avoid "leaks"
for (x = 0; x != gridSizeX; x++)
for (y = 0; y < windowOffsetY; y++) {
walls[x+gw*y] = walls[x+gw*windowOffsetY];
walls[x+gw*(gridSizeY-y-1)] =
walls[x+gw*(gridSizeY-windowOffsetY-1)];
}
for (y = 0; y < gridSizeY; y++)
for (x = 0; x < windowOffsetX; x++) {
walls[x+gw*y] = walls[windowOffsetX+gw*y];
walls[gridSizeX-x-1+gw*y] =
walls[gridSizeX-windowOffsetX-1+gw*y];
}
// generate exceptional array, which is useful for doing
// special handling of elements
for (x = 1; x < gridSizeX-1; x++)
for (y = 1; y < gridSizeY-1; y++) {
int gi = x+gw*y;
exceptional[gi] =
walls[gi-1] || walls[gi+1] ||
walls[gi-gw] || walls[gi+gw] || walls[gi] ||
medium[gi] != medium[gi-1] ||
medium[gi] != medium[gi+1];
if ((x == 1 || x == gridSizeX-2) &&
medium[gi] != medium[gridSizeX-1-x+gw*(y+1)] ||
medium[gi] != medium[gridSizeX-1-x+gw*(y-1)])
exceptional[gi] = true;
}
// put some extra exceptions at the corners to ensure tadd2, sinth,
// etc get calculated
exceptional[1+gw] = exceptional[gridSizeX-2+gw] =
exceptional[1+(gridSizeY-2)*gw] =
exceptional[gridSizeX-2+(gridSizeY-2)*gw] = true;
}
void centerString(Graphics g, String s, int y) {
FontMetrics fm = g.getFontMetrics();
g.drawString(s, (winSize.width-fm.stringWidth(s))/2, y);
}
public void paint(Graphics g) {
cv.repaint();
}
long lastTime = 0, lastFrameTime, secTime = 0;
int frames = 0;
int steps = 0;
int framerate = 0, steprate = 0;
boolean moveRight = true;
boolean moveDown = true;
public void updateRipple(Graphics realg) {
if (winSize == null || winSize.width == 0) {
// this works around some weird bug in IE which causes the
// applet to not show up properly sometimes.
handleResize();
return;
}
if (increaseResolution) {
increaseResolution = false;
if (resBar.getValue() < 495)
setResolution(resBar.getValue() + 10);
}
long sysTime = getTimeMillis();
double tadd = 0;
if (!stoppedCheck.getState()) {
int val = 5; //speedBar.getValue();
tadd = val*.05;
}
int i, j;
boolean stopFunc =
dragging && selectedSource == -1 &&
view3dCheck.getState() == false &&
modeChooser.getSelectedIndex() == MODE_SETFUNC;
if (stoppedCheck.getState())
stopFunc = true;
int iterCount = speedBar.getValue();
if (!stopFunc) {
/*
long sysTime = System.currentTimeMillis();
if (sysTime-secTime >= 1000) {
framerate = frames; steprate = steps;
frames = 0; steps = 0;
secTime = sysTime;
}
lastTime = sysTime;
*/
int iter;
int mxx = gridSizeX-1;
int mxy = gridSizeY-1;
for (iter = 0; iter != iterCount; iter++) {
int jstart, jend, jinc;
if (moveDown) {
// we process the rows in alternate directions
// each time to avoid any directional bias.
jstart = 1; jend = mxy; jinc = 1; moveDown = false;
} else {
jstart = mxy-1; jend = 0; jinc = -1; moveDown = true;
}
moveRight = moveDown;
float sinhalfth = 0;
float sinth = 0;
float scaleo = 0;
int curMedium = -1;
for (j = jstart; j != jend; j += jinc) {
int istart, iend, iinc;
if (moveRight) {
iinc = 1; istart = 1; iend = mxx; moveRight = false;
} else {
iinc = -1; istart = mxx-1; iend = 0; moveRight = true;
}
int gi = j*gw+istart;
int giEnd = j*gw+iend;
for (; gi != giEnd; gi += iinc) {
// calculate equilibrum point of this
// element's oscillation
float previ = func[gi-1];
float nexti = func[gi+1];
float prevj = func[gi-gw];
float nextj = func[gi+gw];
float basis = (nexti+previ+nextj+prevj)*.25f;
if (exceptional[gi]) {
if (curMedium != medium[gi]) {
curMedium = medium[gi];
double tadd2 = tadd*(1-
(mediumMaxIndex/mediumMax)*curMedium);
sinhalfth = (float)
Math.sin(tadd2/2);
sinth = (float)
(Math.sin(tadd2)*dampcoef);
scaleo = (float) (1-Math.sqrt(
4*sinhalfth*sinhalfth-sinth*sinth));
}
if (walls[gi])
continue;
int count = 4;
if (fixedEndsCheck.getState()) {
if (walls[gi-1]) previ = 0;
if (walls[gi+1]) nexti = 0;
if (walls[gi-gw]) prevj = 0;
if (walls[gi+gw]) nextj = 0;
} else {
if (walls[gi-1])
previ = walls[gi+1] ? func[gi] : func[gi+1];
if (walls[gi+1])
nexti = walls[gi-1] ? func[gi] : func[gi-1];
if (walls[gi-gw])
prevj = walls[gi+gw] ? func[gi] : func[gi+gw];
if (walls[gi+gw])
nextj = walls[gi-gw] ? func[gi] : func[gi-gw];
}
basis = (nexti+previ+nextj+prevj)*.25f;
}
// what we are doing here (aside from damping)
// is rotating the point (func[gi], funci[gi])
// an angle tadd about the point (basis, 0).
// Rather than call atan2/sin/cos, we use this
// faster method using some precomputed info.
float a = 0;
float b = 0;
if (damp[gi] == 1f) {
a = func[gi] - basis;
b = funci[gi];
} else {
a = (func[gi] - basis) * damp[gi];
b = funci[gi] * damp[gi];
}
func [gi] = basis + a*scaleo - b*sinth;
funci[gi] = b*scaleo + a*sinth;
}
}
t += tadd;
if (sourceCount > 0) {
double w = freqBar.getValue()*(t-freqTimeZero)*freqMult;
double w2 = w;
boolean skip = false;
switch (auxFunction) {
case AUX_FREQ:
w2 = auxBar.getValue()*t*freqMult;
break;
case AUX_PHASE:
w2 = w+(auxBar.getValue()-1) * (pi/29);
break;
}
double v = 0;
double v2 = 0;
switch (sourceWaveform) {
case SWF_SIN:
v = Math.cos(w);
if (sourceCount >= (sourcePlane ? 4 : 2))
v2 = Math.cos(w2);
else if (sourceFreqCount == 2)
v = (v+Math.cos(w2))*.5;
break;
case SWF_SQUARE:
w %= pi*2;
v = (w < pi) ? 1 : -1;
break;
case SWF_PULSE:
{
w %= pi*2;
double pulselen = pi/4;
double pulselen2 = freqBar.getValue() * .2;
if (pulselen2 < pulselen)
pulselen = pulselen2;
v = (w > pulselen) ? 0 :
Math.sin(w*pi/pulselen);
if (w > pulselen*2)
skip = true;
}
break;
}
for (j = 0; j != sourceCount; j++) {
if ((j % 2) == 0)
sources[j].v = (float) (v*setup.sourceStrength());
else
sources[j].v = (float) (v2*setup.sourceStrength());
}
if (sourcePlane) {
if (!skip) {
for (j = 0; j != sourceCount/2; j++) {
OscSource src1 = sources[j*2];
OscSource src2 = sources[j*2+1];
OscSource src3 = sources[j];
drawPlaneSource(src1.x, src1.y,
src2.x, src2.y, src3.v, w);
}
}
} else {
if (sourceMoving) {
int sy;
movingSourcePos += tadd*.02*auxBar.getValue();
double wm = movingSourcePos;
int h = windowHeight-3;
wm %= h*2;
sy = (int) wm;
if (sy > h)
sy = 2*h-sy;
sy += windowOffsetY+1;
sources[0].y = sy;
}
for (i = 0; i != sourceCount; i++) {
OscSource src = sources[i];
func[src.x+gw*src.y] = src.v;
funci[src.x+gw*src.y] = 0;
}
}
}
setup.eachFrame();
steps++;
filterGrid();
}
}
brightMult = Math.exp(brightnessBar.getValue()/100. - 5.);
if (view3dCheck.getState())
draw3dView();
else
draw2dView();
if (imageSource != null)
imageSource.newPixels();
realg.drawImage(dbimage, 0, 0, this);
if (dragStartX >= 0 && !view3dCheck.getState()) {
int x = dragStartX*windowWidth/winSize.width;
int y = windowHeight-1-(dragStartY*windowHeight/winSize.height);
String s = "(" + x + "," + y +")";
realg.setColor(Color.white);
FontMetrics fm = realg.getFontMetrics();
int h = 5+fm.getAscent();
realg.fillRect(0, winSize.height-h, fm.stringWidth(s)+10, h);
realg.setColor(Color.black);
realg.drawString(s, 5, winSize.height-5);
}
/*frames++;
realg.setColor(Color.white);
realg.drawString("Framerate: " + framerate, 10, 10);
realg.drawString("Steprate: " + steprate, 10, 30);
lastFrameTime = lastTime;
*/
if (!stoppedCheck.getState()) {
long diff = getTimeMillis()-sysTime;
// we want the time it takes for a wave to travel across the screen
// to be more-or-less constant, but don't do anything after 5 seconds
if (adjustResolution && diff > 0 && sysTime < startTime+1000 &&
windowOffsetX*diff/iterCount < 55) {
increaseResolution = true;
startTime = sysTime;
}
if (dragging && selectedSource == -1 &&
modeChooser.getSelectedIndex() == MODE_FUNCHOLD)
editFuncPoint(dragX, dragY);
cv.repaint(0);
}
}
// filter out high-frequency noise
int filterCount;
void filterGrid() {
int x, y;
if (fixedEndsCheck.getState())
return;
if (sourceCount > 0 && freqBarValue > 23)
return;
if (sourceFreqCount >= 2 && auxBar.getValue() > 23)
return;
if (++filterCount < 10)
return;
filterCount = 0;
for (y = windowOffsetY; y < windowBottom; y++)
for (x = windowOffsetX; x < windowRight; x++) {
int gi = x+y*gw;
if (walls[gi])
continue;
if (func[gi-1] < 0 && func[gi] > 0 && func[gi+1] < 0 &&
!walls[gi+1] && !walls[gi-1])
func[gi] = (func[gi-1]+func[gi+1])/2;
if (func[gi-gw] < 0 && func[gi] > 0 && func[gi+gw] < 0 &&
!walls[gi-gw] && !walls[gi+gw])
func[gi] = (func[gi-gw]+func[gi+gw])/2;
if (func[gi-1] > 0 && func[gi] < 0 && func[gi+1] > 0 &&
!walls[gi+1] && !walls[gi-1])
func[gi] = (func[gi-1]+func[gi+1])/2;
if (func[gi-gw] > 0 && func[gi] < 0 && func[gi+gw] > 0 &&
!walls[gi-gw] && !walls[gi+gw])
func[gi] = (func[gi-gw]+func[gi+gw])/2;
}
}
void plotPixel(int x, int y, int pix) {
if (x < 0 || x >= winSize.width)
return;
try { pixels[x+y*winSize.width] = pix; } catch (Exception e) {}
}
// draw a circle the slow and dirty way
void plotSource(int n, int xx, int yy) {
int rad = sourceRadius;
int j;
int col = (sourceColor.getRed()<<16)|
(sourceColor.getGreen()<<8)|
(sourceColor.getBlue())| 0xFF000000;
if (n == selectedSource)
col ^= 0xFFFFFF;
for (j = 0; j <= rad; j++) {
int k = (int) (Math.sqrt(rad*rad-j*j)+.5);
plotPixel(xx+j, yy+k, col);
plotPixel(xx+k, yy+j, col);
plotPixel(xx+j, yy-k, col);
plotPixel(xx-k, yy+j, col);
plotPixel(xx-j, yy+k, col);
plotPixel(xx+k, yy-j, col);
plotPixel(xx-j, yy-k, col);
plotPixel(xx-k, yy-j, col);
plotPixel(xx, yy+j, col);
plotPixel(xx, yy-j, col);
plotPixel(xx+j, yy, col);
plotPixel(xx-j, yy, col);
}
}
void draw2dView() {
int ix = 0;
int i, j, k, l;
for (j = 0; j != windowHeight; j++) {
ix = winSize.width*(j*winSize.height/windowHeight);
int j2 = j+windowOffsetY;
int gi = j2*gw+windowOffsetX;
int y = j*winSize.height/windowHeight;
int y2 = (j+1)*winSize.height/windowHeight;
for (i = 0; i != windowWidth; i++, gi++) {
int x = i*winSize.width/windowWidth;
int x2 = (i+1)*winSize.width/windowWidth;
int i2 = i+windowOffsetX;
double dy = func[gi] * brightMult;
if (dy < -1)
dy = -1;
if (dy > 1)
dy = 1;
int col = 0;
int colR = 0, colG = 0, colB = 0;
if (walls[gi]) {
colR = wallColor.getRed();
colG = wallColor.getGreen();
colB = wallColor.getBlue();
} else if (dy < 0) {
double d1 = -dy;
double d2 = 1-d1;
double d3 = medium[gi]*(1/255.01);
double d4 = 1-d3;
double a1 = d1*d4; double a2 = d2*d4;
double a3 = d1*d3; double a4 = d2*d3;
colR = (int) (negColor. getRed() *a1 +
zeroColor.getRed() *a2 +
negMedColor.getRed() *a3 +
medColor.getRed() *a4);
colG = (int) (negColor. getGreen() *a1 +
zeroColor.getGreen() *a2 +
negMedColor.getGreen()*a3 +
medColor.getGreen() *a4);
colB = (int) (negColor. getBlue() *a1 +
zeroColor.getBlue() *a2 +
negMedColor.getBlue() *a3 +
medColor.getBlue() *a4);
} else {
double d1 = dy;
double d2 = 1-dy;
double d3 = medium[gi]*(1/255.01);
double d4 = 1-d3;
double a1 = d1*d4; double a2 = d2*d4;
double a3 = d1*d3; double a4 = d2*d3;
colR = (int) (posColor. getRed() *a1 +
zeroColor.getRed() *a2 +
posMedColor.getRed() *a3 +
medColor.getRed() *a4);
colG = (int) (posColor. getGreen() *a1 +
zeroColor.getGreen() *a2 +
posMedColor.getGreen()*a3 +
medColor.getGreen() *a4);
colB = (int) (posColor. getBlue() *a1 +
zeroColor.getBlue() *a2 +
posMedColor.getBlue() *a3 +
medColor.getBlue() *a4);
}
col = (255<<24) | (colR<<16) | (colG<<8) | (colB);
for (k = 0; k != x2-x; k++, ix++)
for (l = 0; l != y2-y; l++)
pixels[ix+l*winSize.width] = col;
}
}
int intf = (gridSizeY/2-windowOffsetY)*winSize.height/windowHeight;
for (i = 0; i != sourceCount; i++) {
OscSource src = sources[i];
int xx = src.getScreenX();
int yy = src.getScreenY();
plotSource(i, xx, yy);
}
}
double realxmx, realxmy, realymz, realzmy, realzmx, realymadd, realzmadd;
double viewAngle = pi, viewAngleDragStart;
double viewZoom = .775, viewZoomDragStart;
double viewAngleCos = -1, viewAngleSin = 0;
double viewHeight = -38, viewHeightDragStart;
double scalex, scaley;
int centerX3d, centerY3d;
int xpoints[] = new int[4], ypoints[] = new int[4];
final double viewDistance = 66;
void map3d(double x, double y, double z, int xpoints[], int ypoints[], int pt) {
/*x *= aspectRatio;
z *= -4;
x *= 16./sampleCount; y *= 16./sampleCount;
double realx = x*viewAngleCos + y*viewAngleSin; // range: [-10,10]
double realy = z-viewHeight;
double realz = y*viewAngleCos - x*viewAngleSin + viewDistance;*/
double realx = realxmx*x + realxmy*y;
double realy = realymz*z + realymadd;
double realz = realzmx*x + realzmy*y + realzmadd;
xpoints[pt] = centerX3d + (int) (realx/realz);
ypoints[pt] = centerY3d - (int) (realy/realz);
}
double scaleMult;
void scaleworld() {
scalex = viewZoom * (winSize.width/4) * viewDistance / 8;
scaley = -scalex;
int y = (int) (scaley*viewHeight/viewDistance);
/*centerX3d = winSize.x + winSize.width/2;
centerY3d = winSize.y + winSize.height/2 - y;*/
centerX3d = winSize.width/2;
centerY3d = winSize.height/2 - y;
scaleMult = 16./(windowWidth/2);
realxmx = -viewAngleCos*scaleMult * scalex;
realxmy = viewAngleSin*scaleMult * scalex;
realymz = -brightMult*scaley;
realzmy = viewAngleCos*scaleMult;
realzmx = viewAngleSin*scaleMult;
realymadd = -viewHeight*scaley;
realzmadd = viewDistance;
}
void draw3dView() {
int half = gridSizeX/2;
scaleworld();
int x, y;
int xdir, xstart, xend;
int ydir, ystart, yend;
int sc = windowRight-1;
// figure out what order to render the grid elements so that
// the ones in front are rendered first.
if (viewAngleCos > 0) {
ystart = sc;
yend = windowOffsetY-1;
ydir = -1;
} else {
ystart = windowOffsetY;
yend = sc+1;
ydir = 1;
}
if (viewAngleSin < 0) {
xstart = windowOffsetX;
xend = sc+1;
xdir = 1;
} else {
xstart = sc;
xend = windowOffsetX-1;
xdir = -1;
}
boolean xFirst = (viewAngleSin * xdir < viewAngleCos * ydir);
for (x = 0; x != winSize.width*winSize.height; x++)
pixels[x] = 0xFF000000;
/*double zval = 2.0/sampleCount;
System.out.println(zval);
if (sampleCount == 128)
zval = .1;*/
double zval = .1;
double zval2 = zval*zval;
for (x = xstart; x != xend; x += xdir) {
for (y = ystart; y != yend; y += ydir) {
if (!xFirst)
x = xstart;
for (; x != xend; x += xdir) {
int gi = x+gw*y;
map3d(x-half, y-half, func[gi], xpoints, ypoints, 0);
map3d(x+1-half, y-half, func[gi+1],
xpoints, ypoints, 1);
map3d(x-half, y+1-half, func[gi+gw],
xpoints, ypoints, 2);
map3d(x+1-half, y+1-half, func[gi+gw+1],
xpoints, ypoints, 3);
double qx = func[gi+1] -func[gi];
double qy = func[gi+gw]-func[gi];
// calculate lighting
double normdot = (qx+qy+zval)*(1/1.73)/
Math.sqrt(qx*qx+qy*qy+zval2);
int col = computeColor(gi, normdot);
fillTriangle(xpoints[0], ypoints[0],
xpoints[1], ypoints[1],
xpoints[3], ypoints[3], col);
fillTriangle(xpoints[0], ypoints[0],
xpoints[2], ypoints[2],
xpoints[3], ypoints[3], col);
if (xFirst)
break;
}
}
if (!xFirst)
break;
}
}
int computeColor(int gix, double c) {
double h = func[gix]*brightMult;
if (c < 0)
c = 0;
if (c > 1)
c = 1;
c = .5 + c * .5;
double redness = (h < 0) ? -h : 0;
double grnness = (h > 0) ? h : 0;
if (redness > 1)
redness = 1;
if (grnness > 1)
grnness = 1;
if (grnness < 0)
grnness = 0;
if (redness < 0)
redness = 0;
double grayness = (1-(redness+grnness))*c;
double grayness2 = grayness;
if (medium[gix] > 0) {
double mm = 1-(medium[gix] * (1/255.01));
grayness2 *= mm;
}
double gray = .6;
int ri = (int) ((c*redness+gray*grayness2)*255);
int gi = (int) ((c*grnness+gray*grayness2)*255);
int bi = (int) ((gray*grayness)*255);
return 0xFF000000 | (ri<<16) | (gi<<8) | bi;
}
void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3,
int col) {
if (x1 > x2) {
if (x2 > x3) {
// x1 > x2 > x3
int ay = interp(x1, y1, x3, y3, x2);
fillTriangle1(x3, y3, x2, y2, ay, col);
fillTriangle1(x1, y1, x2, y2, ay, col);
} else if (x1 > x3) {
// x1 > x3 > x2
int ay = interp(x1, y1, x2, y2, x3);
fillTriangle1(x2, y2, x3, y3, ay, col);
fillTriangle1(x1, y1, x3, y3, ay, col);
} else {
// x3 > x1 > x2
int ay = interp(x3, y3, x2, y2, x1);
fillTriangle1(x2, y2, x1, y1, ay, col);
fillTriangle1(x3, y3, x1, y1, ay, col);
}
} else {
if (x1 > x3) {
// x2 > x1 > x3
int ay = interp(x2, y2, x3, y3, x1);
fillTriangle1(x3, y3, x1, y1, ay, col);
fillTriangle1(x2, y2, x1, y1, ay, col);
} else if (x2 > x3) {
// x2 > x3 > x1
int ay = interp(x2, y2, x1, y1, x3);
fillTriangle1(x1, y1, x3, y3, ay, col);
fillTriangle1(x2, y2, x3, y3, ay, col);
} else {
// x3 > x2 > x1
int ay = interp(x3, y3, x1, y1, x2);
fillTriangle1(x1, y1, x2, y2, ay, col);
fillTriangle1(x3, y3, x2, y2, ay, col);
}
}
}
int interp(int x1, int y1, int x2, int y2, int x) {
if (x1 == x2)
return y1;
if (x < x1 && x < x2 || x > x1 && x > x2)
System.out.print("interp out of bounds\n");
return (int) (y1+((double) x-x1)*(y2-y1)/(x2-x1));
}
void fillTriangle1(int x1, int y1, int x2, int y2, int y3, int col) {
// x2 == x3
int dir = (x1 > x2) ? -1 : 1;
int x = x1;
if (x < 0) {
x = 0;
if (x2 < 0)
return;
}
if (x >= winSize.width) {
x = winSize.width-1;
if (x2 >= winSize.width)
return;
}
if (y2 > y3) {
int q = y2;
y2 = y3; y3 = q;
}
// y2 < y3
while (x != x2+dir) {
// XXX this could be speeded up
int ya = interp(x1, y1, x2, y2, x);
int yb = interp(x1, y1, x2, y3, x);
if (ya < 0)
ya = 0;
if (yb >= winSize.height)
yb = winSize.height-1;
for (; ya <= yb; ya++)
pixels[x+ya*winSize.width] = col;
x += dir;
if (x < 0 || x >= winSize.width)
return;
}
}
int abs(int x) {
return x < 0 ? -x : x;
}
void drawPlaneSource(int x1, int y1, int x2, int y2, float v, double w) {
if (y1 == y2) {
if (x1 == windowOffsetX)
x1 = 0;
if (x2 == windowOffsetX)
x2 = 0;
if (x1 == windowOffsetX+windowWidth-1)
x1 = gridSizeX-1;
if (x2 == windowOffsetX+windowWidth-1)
x2 = gridSizeX-1;
}
if (x1 == x2) {
if (y1 == windowOffsetY)
y1 = 0;
if (y2 == windowOffsetY)
y2 = 0;
if (y1 == windowOffsetY+windowHeight-1)
y1 = gridSizeY-1;
if (y2 == windowOffsetY+windowHeight-1)
y2 = gridSizeY-1;
}
/*double phase = 0;
if (sourceChooser.getSelectedIndex() == SRC_1S1F_PLANE_PHASE)
phase = (auxBar.getValue()-15)*3.8*freqBar.getValue()*freqMult;*/
// need to draw a line from x1,y1 to x2,y2
if (x1 == x2 && y1 == y2) {
func [x1+gw*y1] = v;
funci[x1+gw*y1] = 0;
} else if (abs(y2-y1) > abs(x2-x1)) {
// y difference is greater, so we step along y's
// from min to max y and calculate x for each step
double sgn = sign(y2-y1);
int x, y;
for (y = y1; y != y2+sgn; y += sgn) {
x = x1+(x2-x1)*(y-y1)/(y2-y1);
double ph = sgn*(y-y1)/(y2-y1);
int gi = x+gw*y;
func [gi] = setup.calcSourcePhase(ph, v, w);
//(phase == 0) ? v :
// (float) (Math.sin(w+ph));
funci[gi] = 0;
}
} else {
// x difference is greater, so we step along x's
// from min to max x and calculate y for each step
double sgn = sign(x2-x1);
int x, y;
for (x = x1; x != x2+sgn; x += sgn) {
y = y1+(y2-y1)*(x-x1)/(x2-x1);
double ph = sgn*(x-x1)/(x2-x1);
int gi = x+gw*y;
func [gi] = setup.calcSourcePhase(ph, v, w);
// (phase == 0) ? v :
// (float) (Math.sin(w+ph));
funci[gi] = 0;
}
}
}
int sign(int x) {
return (x < 0) ? -1 : (x == 0) ? 0 : 1;
}
void edit(MouseEvent e) {
if (view3dCheck.getState())
return;
int x = e.getX();
int y = e.getY();
if (selectedSource != -1) {
x = x*windowWidth/winSize.width;
y = y*windowHeight/winSize.height;
if (x >= 0 && y >= 0 && x < windowWidth && y < windowHeight) {
sources[selectedSource].x = x+windowOffsetX;
sources[selectedSource].y = y+windowOffsetY;
}
return;
}
if (dragX == x && dragY == y)
editFuncPoint(x, y);
else {
// need to draw a line from old x,y to new x,y and
// call editFuncPoint for each point on that line. yuck.
if (abs(y-dragY) > abs(x-dragX)) {
// y difference is greater, so we step along y's
// from min to max y and calculate x for each step
int x1 = (y < dragY) ? x : dragX;
int y1 = (y < dragY) ? y : dragY;
int x2 = (y > dragY) ? x : dragX;
int y2 = (y > dragY) ? y : dragY;
dragX = x;
dragY = y;
for (y = y1; y <= y2; y++) {
x = x1+(x2-x1)*(y-y1)/(y2-y1);
editFuncPoint(x, y);
}
} else {
// x difference is greater, so we step along x's
// from min to max x and calculate y for each step
int x1 = (x < dragX) ? x : dragX;
int y1 = (x < dragX) ? y : dragY;
int x2 = (x > dragX) ? x : dragX;
int y2 = (x > dragX) ? y : dragY;
dragX = x;
dragY = y;
for (x = x1; x <= x2; x++) {
y = y1+(y2-y1)*(x-x1)/(x2-x1);
editFuncPoint(x, y);
}
}
}
}
void editFuncPoint(int x, int y) {
int xp = x*windowWidth/winSize.width+windowOffsetX;
int yp = y*windowHeight/winSize.height+windowOffsetY;
int gi = xp+yp*gw;
if (modeChooser.getSelectedIndex() == MODE_WALLS) {
if (!dragSet && !dragClear) {
dragClear = walls[gi];
dragSet = !dragClear;
}
walls[gi] = dragSet;
calcExceptions();
func[gi] = funci[gi] = 0;
} else if (modeChooser.getSelectedIndex() == MODE_MEDIUM) {
if (!dragSet && !dragClear) {
dragClear = medium[gi] > 0;
dragSet = !dragClear;
}
medium[gi] = (dragSet) ? mediumMax : 0;
calcExceptions();
} else {
if (!dragSet && !dragClear) {
dragClear = func[gi] > .1;
dragSet = !dragClear;
}
func[gi] = (dragSet) ? 1 : -1;
funci[gi] = 0;
}
cv.repaint(0);
}
void selectSource(MouseEvent me) {
int x = me.getX();
int y = me.getY();
int i;
for (i = 0; i != sourceCount; i++) {
OscSource src = sources[i];
int sx = src.getScreenX();
int sy = src.getScreenY();
int r2 = (sx-x)*(sx-x)+(sy-y)*(sy-y);
if (sourceRadius*sourceRadius > r2) {
selectedSource = i;
return;
}
}
selectedSource = -1;
}
void setDamping() {
/*int i;
double damper = dampingBar.getValue() * .00002;// was 5
dampcoef = Math.exp(-damper);*/
dampcoef = 1;
}
public void componentHidden(ComponentEvent e){}
public void componentMoved(ComponentEvent e){}
public void componentShown(ComponentEvent e) {
cv.repaint();
}
public void componentResized(ComponentEvent e) {
handleResize();
cv.repaint(100);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == blankButton) {
doBlank();
cv.repaint();
}
if (e.getSource() == blankWallsButton) {
doBlankWalls();
cv.repaint();
}
if (e.getSource() == borderButton) {
doBorder();
cv.repaint();
}
if (e.getSource() == exportButton)
doImport();
}
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.print(((Scrollbar) e.getSource()).getValue() + "\n");
if (e.getSource() == resBar) {
setResolution();
reinit();
}
if (e.getSource() == dampingBar)
setDamping();
if (e.getSource() == brightnessBar)
cv.repaint(0);
if (e.getSource() == freqBar)
setFreq();
}
void setFreqBar(int x) {
freqBar.setValue(x);
freqBarValue = x;
freqTimeZero = 0;
}
void setFreq() {
// adjust time zero to maintain continuity in the freq func
// even though the frequency has changed.
double oldfreq = freqBarValue * freqMult;
freqBarValue = freqBar.getValue();
double newfreq = freqBarValue * freqMult;
double adj = newfreq-oldfreq;
freqTimeZero = t-oldfreq*(t-freqTimeZero)/newfreq;
}
void setResolution() {
windowWidth = windowHeight = resBar.getValue();
int border = windowWidth/9;
if (border < 20)
border = 20;
windowOffsetX = windowOffsetY = border;
gridSizeX = windowWidth + windowOffsetX*2;
gridSizeY = windowHeight + windowOffsetY*2;
windowBottom = windowOffsetY+windowHeight-1;
windowRight = windowOffsetX+windowWidth -1;
}
void setResolution(int x) {
resBar.setValue(x);
setResolution();
reinit();
}
public void mouseDragged(MouseEvent e) {
if (view3dCheck.getState()) {
view3dDrag(e);
}
if (!dragging)
selectSource(e);
dragging = true;
edit(e);
adjustResolution = false;
cv.repaint(0);
}
public void mouseMoved(MouseEvent e) {
if (dragging)
return;
int x = e.getX();
int y = e.getY();
dragStartX = dragX = x; dragStartY = dragY = y;
viewAngleDragStart = viewAngle;
viewHeightDragStart = viewHeight;
selectSource(e);
if (stoppedCheck.getState())
cv.repaint(0);
}
void view3dDrag(MouseEvent e) {
int x = e.getX(); int y = e.getY();
viewAngle = (dragStartX-x)/40. + viewAngleDragStart;
while (viewAngle < 0)
viewAngle += 2*pi;
while (viewAngle >= 2*pi)
viewAngle -= 2*pi;
viewAngleCos = Math.cos(viewAngle);
viewAngleSin = Math.sin(viewAngle);
viewHeight = (dragStartY-y)/10. + viewHeightDragStart;
/*viewZoom = (y-dragStartY)/40. + viewZoomDragStart;
if (viewZoom < .1)
viewZoom = .1;
System.out.println(viewZoom);*/
cv.repaint();
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
dragStartX = -1;
}
public void mousePressed(MouseEvent e) {
adjustResolution = false;
mouseMoved(e);
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
return;
dragging = true;
edit(e);
}
public void mouseReleased(MouseEvent e) {
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
return;
dragging = false;
dragSet = dragClear = false;
cv.repaint();
}
public void itemStateChanged(ItemEvent e) {
if (e.getItemSelectable() == stoppedCheck) {
cv.repaint();
return;
}
if (e.getItemSelectable() == sourceChooser) {
if (sourceChooser.getSelectedIndex() != sourceIndex)
setSources();
}
if (e.getItemSelectable() == setupChooser)
doSetup();
if (e.getItemSelectable() == colorChooser)
doColor();
}
void doSetup() {
t = 0;
if (resBar.getValue() < 32)
setResolution(32);
doBlank();
doBlankWalls();
// don't use previous source positions, use defaults
sourceCount = -1;
sourceChooser.select(SRC_1S1F);
dampingBar.setValue(10);
setFreqBar(5);
setBrightness(10);
auxBar.setValue(1);
fixedEndsCheck.setState(true);
setup = (Setup)
setupList.elementAt(setupChooser.getSelectedIndex());
setup.select();
setup.doSetupSources();
calcExceptions();
setDamping();
//System.out.println("setup " + setupChooser.getSelectedIndex());
}
void setBrightness(int x) {
double m = x / 5.;
m = (Math.log(m) + 5.) * 100;
brightnessBar.setValue((int) m);
}
void doColor() {
int cn = colorChooser.getSelectedIndex();
wallColor = schemeColors[cn][0];
posColor = schemeColors[cn][1];
negColor = schemeColors[cn][2];
zeroColor = schemeColors[cn][3];
posMedColor = schemeColors[cn][4];
negMedColor = schemeColors[cn][5];
medColor = schemeColors[cn][6];
sourceColor = schemeColors[cn][7];
}
void addDefaultColorScheme() {
String schemes[] = {
"#808080 #00ffff #000000 #008080 #0000ff #000000 #000080 #ffffff",
"#808080 #00ff00 #ff0000 #000000 #00ffff #ff00ff #0000ff #0000ff",
"#800000 #00ffff #0000ff #000000 #80c8c8 #8080c8 #808080 #ffffff",
"#800000 #ffffff #000000 #808080 #0000ff #000000 #000080 #00ff00",
"#800000 #ffff00 #0000ff #000000 #ffff80 #8080ff #808080 #ffffff",
"#808080 #00ff00 #ff0000 #FFFFFF #00ffff #ff00ff #0000ff #0000ff",
"#FF0000 #00FF00 #0000FF #FFFF00 #00FFFF #FF00FF #FFFFFF #000000"
};
int i;
for (i = 0; i != 7; i++)
decodeColorScheme(i, schemes[i]);
//colorChooser.hide();
}
void decodeColorScheme(int cn, String s) {
StringTokenizer st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
int i;
for (i = 0; i != 8; i++)
schemeColors[cn][i] = Color.decode(st.nextToken());
}
colorChooser.add("Color Scheme " + (cn+1));
}
void addMedium() {
int i, j;
for (i = 0; i != gridSizeX; i++)
for (j = gridSizeY/2; j != gridSizeY; j++)
medium[i+j*gw] = mediumMax;
}
void setSources() {
sourceIndex = sourceChooser.getSelectedIndex();
int oldSCount = sourceCount;
boolean oldPlane = sourcePlane;
sourceFreqCount = 1;
sourcePlane = (sourceChooser.getSelectedIndex() >= SRC_1S1F_PLANE &&
sourceChooser.getSelectedIndex() < SRC_6S1F);
sourceMoving = false;
sourceWaveform = SWF_SIN;
sourceCount = 1;
boolean phase = false;
switch (sourceChooser.getSelectedIndex()) {
case 0: sourceCount = 0; break;
case 2: sourceFreqCount = 2; break;
case 3: sourceCount = 2; break;
case 4: sourceCount = 2; sourceFreqCount = 2; break;
case 5: sourceCount = 3; break;
case 6: sourceCount = 4; break;
case 7: sourceWaveform = SWF_SQUARE; break;
case 8: sourceWaveform = SWF_PULSE; break;
case 9: sourceMoving = true; break;
case 11: sourceFreqCount = 2; break;
case 12: sourceCount = 2; break;
case 13: sourceCount = sourceFreqCount = 2; break;
case 14: sourceWaveform = SWF_PULSE; break;
case 15: phase = true; break;
case 16: sourceCount = 6; break;
case 17: sourceCount = 8; break;
case 18: sourceCount = 10; break;
case 19: sourceCount = 12; break;
case 20: sourceCount = 16; break;
case 21: sourceCount = 20; break;
}
if (sourceFreqCount >= 2) {
auxFunction = AUX_FREQ;
auxBar.setValue(freqBar.getValue());
if (sourceCount == 2)
auxLabel.setText("Source 2 Frequency");
else
auxLabel.setText("2nd Frequency");
} else if (sourceCount == 2 || sourceCount >= 4 || phase) {
auxFunction = AUX_PHASE;
auxBar.setValue(1);
auxLabel.setText("Phase Difference");
} else if (sourceMoving) {
auxFunction = AUX_SPEED;
auxBar.setValue(7);
auxLabel.setText("Source Speed");
} else {
auxFunction = AUX_NONE;
auxBar.hide();
auxLabel.hide();
}
if (auxFunction != AUX_NONE) {
auxBar.show();
auxLabel.show();
}
validate();
if (sourcePlane) {
sourceCount *= 2;
if (!(oldPlane && oldSCount == sourceCount)) {
int x2 = windowOffsetX+windowWidth-1;
int y2 = windowOffsetY+windowHeight-1;
sources[0] = new OscSource(windowOffsetX, windowOffsetY+1);
sources[1] = new OscSource(x2, windowOffsetY+1);
sources[2] = new OscSource(windowOffsetX, y2);
sources[3] = new OscSource(x2, y2);
}
} else if (!(oldSCount == sourceCount && !oldPlane)) {
sources[0] = new OscSource(gridSizeX/2, windowOffsetY+1);
sources[1] = new OscSource(gridSizeX/2, gridSizeY-windowOffsetY-2);
sources[2] = new OscSource(windowOffsetX+1, gridSizeY/2);
sources[3] = new OscSource(gridSizeX-windowOffsetX-2, gridSizeY/2);
int i;
for (i = 4; i < sourceCount; i++)
sources[i] = new OscSource(windowOffsetX+1+i*2, gridSizeY/2);
}
}
class OscSource {
int x;
int y;
float v;
OscSource(int xx, int yy) { x = xx; y = yy; }
int getScreenX() {
return ((x-windowOffsetX) * winSize.width+winSize.width/2)
/windowWidth;
}
int getScreenY() {
return ((y-windowOffsetY) * winSize.height+winSize.height/2)
/windowHeight;
}
};
void doImport() {
if (impDialog != null) {
requestFocus();
impDialog.setVisible(false);
impDialog = null;
}
String dump = "";
int i;
dump = "$ 0 " + resBar.getValue() + " " +
sourceChooser.getSelectedIndex() + " " +
colorChooser.getSelectedIndex() + " " +
fixedEndsCheck.getState() + " " +
view3dCheck.getState() + " " +
speedBar.getValue() + " " +
freqBar.getValue() + " " +
brightnessBar.getValue() + " "+
auxBar.getValue() + "\n";
for (i = 0; i != sourceCount; i++) {
OscSource src = sources[i];
dump += "s " + src.x + " " + src.y + "\n";
}
for (i = 0; i != gridSizeXY; ) {
if (i >= gridSizeX) {
int istart = i;
for (; i < gridSizeXY &&
walls [i] == walls [i-gridSizeX] &&
medium[i] == medium[i-gridSizeX]; i++)
;
if (i > istart) {
dump += "l " + (i-istart) + "\n";
continue;
}
}
boolean x = walls[i];
int m = medium[i];
int ct = 0;
for (; i < gridSizeXY && walls[i] == x && medium[i] == m; ct++, i++)
;
dump += (x ? "w " : "c ") + ct + " " + m + "\n";
}
impDialog = new ImportDialog(this, dump);
impDialog.show();
}
void readImport(String s) {
byte b[] = s.getBytes();
int len = s.length();
int p;
int x = 0;
int srci = 0;
setupChooser.select(0);
setup = (Setup) setupList.elementAt(0);
for (p = 0; p < len; ) {
int l;
int linelen = 0;
for (l = 0; l != len-p; l++)
if (b[l+p] == '\n' || b[l+p] == '\r') {
linelen = l++;
if (l+p < b.length && b[l+p] == '\n')
l++;
break;
}
String line = new String(b, p, linelen);
StringTokenizer st = new StringTokenizer(line);
while (st.hasMoreTokens()) {
String type = st.nextToken();
int tint = type.charAt(0);
try {
if (tint == '$') {
int flags = new Integer(st.nextToken()).intValue();
resBar.setValue(new Integer(st.nextToken()).intValue());
setResolution();
reinit(false);
sourceChooser.select(new Integer(st.nextToken()).intValue());
setSources();
colorChooser.select(new Integer(st.nextToken()).intValue());
doColor();
fixedEndsCheck.setState(st.nextToken().compareTo("true") == 0);
view3dCheck.setState(st.nextToken().compareTo("true") == 0);
speedBar.setValue(new Integer(st.nextToken()).intValue());
freqBar.setValue(new Integer(st.nextToken()).intValue());
brightnessBar.setValue(new Integer(st.nextToken()).intValue());
auxBar.setValue(new Integer(st.nextToken()).intValue());
break;
}
if (tint == 'w' || tint == 'c') {
boolean w = (tint == 'w');
int ct = new Integer(st.nextToken()).intValue();
int md = new Integer(st.nextToken()).intValue();
for (; ct > 0; ct--, x++) {
walls[x] = w;
medium[x] = md;
}
break;
}
if (tint == 'l') {
int ct = new Integer(st.nextToken()).intValue();
for (; ct > 0; ct--, x++) {
walls[x] = walls[x-gridSizeX];
medium[x] = medium[x-gridSizeX];
}
break;
}
if (tint == 's') {
int sx = new Integer(st.nextToken()).intValue();
int sy = new Integer(st.nextToken()).intValue();
sources[srci].x = sx;
sources[srci].y = sy;
srci++;
break;
}
System.out.println("unknown type!");
} catch (Exception ee) {
ee.printStackTrace();
break;
}
break;
}
p += l;
}
calcExceptions();
setDamping();
}
class ImportDialogLayout implements LayoutManager {
public ImportDialogLayout() {}
public void addLayoutComponent(String name, Component c) {}
public void removeLayoutComponent(Component c) {}
public Dimension preferredLayoutSize(Container target) {
return new Dimension(500, 500);
}
public Dimension minimumLayoutSize(Container target) {
return new Dimension(100,100);
}
public void layoutContainer(Container target) {
Insets insets = target.insets();
int targetw = target.size().width - insets.left - insets.right;
int targeth = target.size().height - (insets.top+insets.bottom);
int i;
int pw = 300;
if (target.getComponentCount() == 0)
return;
Component cl = target.getComponent(target.getComponentCount()-1);
Dimension dl = cl.getPreferredSize();
target.getComponent(0).move(insets.left, insets.top);
int cw = target.size().width - insets.left - insets.right;
int ch = target.size().height - insets.top - insets.bottom -
dl.height;
target.getComponent(0).resize(cw, ch);
int h = ch + insets.top;
int x = 0;
for (i = 1; i < target.getComponentCount(); i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = m.getPreferredSize();
m.move(insets.left+x, h);
m.resize(d.width, d.height);
x += d.width;
}
}
}
};
class ImportDialog extends Dialog implements ActionListener {
RippleFrame rframe;
Button importButton, clearButton, closeButton;
TextArea text;
ImportDialog(RippleFrame f, String str) {
super(f, (str.length() > 0) ? "Export" : "Import", false);
rframe = f;
setLayout(new ImportDialogLayout());
add(text = new TextArea(str, 10, 60, TextArea.SCROLLBARS_BOTH));
add(importButton = new Button("Import"));
importButton.addActionListener(this);
add(clearButton = new Button("Clear"));
clearButton.addActionListener(this);
add(closeButton = new Button("Close"));
closeButton.addActionListener(this);
Point x = rframe.getLocationOnScreen();
resize(400, 300);
Dimension d = getSize();
setLocation(x.x + (winSize.width-d.width)/2,
x.y + (winSize.height-d.height)/2);
show();
if (str.length() > 0)
text.selectAll();
}
public void actionPerformed(ActionEvent e) {
int i;
Object src = e.getSource();
if (src == importButton) {
rframe.readImport(text.getText());
setVisible(false);
}
if (src == closeButton)
setVisible(false);
if (src == clearButton)
text.setText("");
}
public boolean handleEvent(Event ev) {
if (ev.id == Event.WINDOW_DESTROY) {
rframe.requestFocus();
setVisible(false);
return true;
}
return super.handleEvent(ev);
}
}
abstract class Setup {
abstract String getName();
abstract void select();
void doSetupSources() { setSources(); }
void deselect() {}
double sourceStrength() { return 1; }
abstract Setup createNext();
void eachFrame() {}
float calcSourcePhase(double ph, float v, double w) {
return v;
}
};
class SingleSourceSetup extends Setup {
String getName() { return "Single Source"; }
void select() {
setFreqBar(15);
setBrightness(27);
}
Setup createNext() { return new DoubleSourceSetup(); }
}
class DoubleSourceSetup extends Setup {
String getName() { return "Two Sources"; }
void select() {
setFreqBar(15);
setBrightness(19);
}
void doSetupSources() {
sourceChooser.select(SRC_2S1F);
setSources();
sources[0].y = gridSizeY/2 - 8;
sources[1].y = gridSizeY/2 + 8;
sources[0].x = sources[1].x = gridSizeX/2;
}
Setup createNext() { return new QuadrupleSourceSetup(); }
}
class QuadrupleSourceSetup extends Setup {
String getName() { return "Four Sources"; }
void select() {
sourceChooser.select(SRC_4S1F);
setFreqBar(15);
}
Setup createNext() { return new SingleSlitSetup(); }
}
class SingleSlitSetup extends Setup {
String getName() { return "Single Slit"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i;
int x = gridSizeX/2;
int y = windowOffsetY+8; // +4
for (i = 0; i != gridSizeX; i++)
setWall(i, y);
for (i = -8; i <= 8; i++) // was 4
setWall(x+i, y, false);
setBrightness(7);
setFreqBar(25);
}
Setup createNext() { return new DoubleSlitSetup(); }
}
class DoubleSlitSetup extends Setup {
String getName() { return "Double Slit"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i;
int x = gridSizeX/2;
int y = windowOffsetY+4;
for (i = 0; i != gridSizeX; i++)
setWall(i, y);
for (i = 0; i != 3; i++) {
setWall(x-5-i, y, false);
setWall(x+5+i, y, false);
}
brightnessBar.setValue(488);
setFreqBar(22);
}
Setup createNext() { return new TripleSlitSetup(); }
}
class TripleSlitSetup extends Setup {
String getName() { return "Triple Slit"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i;
int x = gridSizeX/2;
int y = windowOffsetY+4;
for (i = 0; i != gridSizeX; i++)
setWall(i, y);
for (i = -1; i <= 1; i++) {
setWall(x-12+i, y, false);
setWall(x+i, y, false);
setWall(x+12+i, y, false);
}
setBrightness(12);
setFreqBar(22);
}
Setup createNext() { return new ObstacleSetup(); }
}
class ObstacleSetup extends Setup {
String getName() { return "Obstacle"; }
void select() {
int i;
int x = gridSizeX/2;
int y = windowOffsetY+12; // was +6
for (i = -15; i <= 15; i++) // was 5
setWall(x+i, y);
setBrightness(280);
setFreqBar(20);
}
Setup createNext() { return new HalfPlaneSetup(); }
}
class HalfPlaneSetup extends Setup {
String getName() { return "Half Plane"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int x = windowOffsetX+windowWidth/2;
int i;
for (i = windowWidth/2; i < windowWidth; i++)
setWall(windowOffsetX+i, windowOffsetY+3);
setBrightness(4);
setFreqBar(25);
}
Setup createNext() { return new DipoleSourceSetup(); }
}
class DipoleSourceSetup extends Setup {
String getName() { return "Dipole Source"; }
void doSetupSources() {
sourceChooser.select(SRC_2S1F);
setSources();
sources[0].y = sources[1].y = gridSizeY/2;
sources[0].x = gridSizeX/2 - 1;
sources[1].x = gridSizeX/2 + 1;
auxBar.setValue(29);
setFreqBar(13);
}
void select() {
setBrightness(33);
}
Setup createNext() { return new LateralQuadrupoleSetup(); }
}
class LateralQuadrupoleSetup extends Setup {
String getName() { return "Lateral Quadrupole"; }
void doSetupSources() {
sourceChooser.select(SRC_4S1F);
setSources();
sources[0].y = sources[2].y = gridSizeY/2;
sources[0].x = gridSizeX/2 - 2; sources[2].x = gridSizeX/2 + 2;
sources[1].x = sources[3].x = gridSizeX/2;
sources[1].y = gridSizeY/2 - 2; sources[3].y = gridSizeY/2 + 2;
setFreqBar(13);
auxBar.setValue(29);
}
void select() {
setBrightness(33);
}
Setup createNext() { return new LinearQuadrupoleSetup(); }
}
class LinearQuadrupoleSetup extends Setup {
String getName() { return "Linear Quadrupole"; }
void doSetupSources() {
sourceChooser.select(SRC_4S1F);
setSources();
sources[0].y = sources[1].y = sources[2].y = sources[3].y =
gridSizeY/2;
sources[0].x = gridSizeX/2 - 3;
sources[2].x = gridSizeX/2 + 3;
sources[1].x = gridSizeX/2 + 1;
sources[3].x = gridSizeX/2 - 1;
auxBar.setValue(29);
setFreqBar(13);
}
void select() {
setBrightness(33);
}
Setup createNext() { return new HexapoleSetup(); }
}
class HexapoleSetup extends Setup {
String getName() { return "Hexapole"; }
void doSetupSources() {
sourceChooser.select(SRC_6S1F);
setSources();
doMultipole(6, 4);
setFreqBar(22);
auxBar.setValue(29);
}
void doMultipole(int n, double dist) {
int i;
for (i = 0; i != n; i++) {
double xx = Math.round(dist*Math.cos(2*pi*i/n));
double yy = Math.round(dist*Math.sin(2*pi*i/n));
sources[i].x = gridSizeX/2 + (int) xx;
sources[i].y = gridSizeY/2 + (int) yy;
}
}
void select() {
brightnessBar.setValue(648);
}
Setup createNext() { return new OctupoleSetup(); }
}
class OctupoleSetup extends HexapoleSetup {
String getName() { return "Octupole"; }
void doSetupSources() {
sourceChooser.select(SRC_8S1F);
setSources();
doMultipole(8, 4);
setFreqBar(22);
auxBar.setValue(29);
}
Setup createNext() { return new Multi12Setup(); }
}
/*class Multi10Setup extends HexapoleSetup {
String getName() { return "10-Pole"; }
void doSetupSources() {
sourceChooser.select(SRC_10S1F);
setSources();
doMultipole(10, 6);
setFreqBar(22);
auxBar.setValue(29);
}
Setup createNext() { return new Multi12Setup(); }
}*/
class Multi12Setup extends HexapoleSetup {
String getName() { return "12-Pole"; }
void doSetupSources() {
sourceChooser.select(SRC_12S1F);
setSources();
doMultipole(12, 6);
setFreqBar(22);
auxBar.setValue(29);
}
Setup createNext() { return new PlaneWaveSetup(); }
}
/*class Multi16Setup extends HexapoleSetup {
String getName() { return "16-Pole"; }
void doSetupSources() {
sourceChooser.select(SRC_16S1F);
setSources();
doMultipole(16, 8);
setFreqBar(22);
auxBar.setValue(29);
}
Setup createNext() { return new Multi20Setup(); }
}
class Multi20Setup extends HexapoleSetup {
String getName() { return "20-Pole"; }
void doSetupSources() {
sourceChooser.select(SRC_20S1F);
setSources();
doMultipole(20, 10);
setFreqBar(22);
auxBar.setValue(29);
}
Setup createNext() { return new PlaneWaveSetup(); }
}*/
class PlaneWaveSetup extends Setup {
String getName() { return "Plane Wave"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
//setBrightness(7);
setFreqBar(15);
}
Setup createNext() { return new IntersectingPlaneWavesSetup(); }
}
class IntersectingPlaneWavesSetup extends Setup {
String getName() { return "Intersecting Planes"; }
void select() {
setBrightness(4);
setFreqBar(17);
}
void doSetupSources() {
sourceChooser.select(SRC_2S1F_PLANE);
setSources();
sources[0].y = sources[1].y = windowOffsetY;
sources[0].x = windowOffsetX+1;
sources[2].x = sources[3].x = windowOffsetX;
sources[2].y = windowOffsetY+1;
sources[3].y = windowOffsetY+windowHeight-1;
}
Setup createNext() { return new PhasedArray1Setup(); }
}
class PhasedArray1Setup extends Setup {
String getName() { return "Phased Array 1"; }
void select() {
setBrightness(5);
setFreqBar(17);
}
void doSetupSources() {
sourceChooser.select(SRC_1S1F_PLANE_PHASE);
setSources();
sources[0].x = sources[1].x = gridSizeX/2;
sources[0].y = gridSizeY/2-12;
sources[1].y = gridSizeY/2+12;
auxBar.setValue(5);
}
float calcSourcePhase(double ph, float v, double w) {
ph *= (auxBar.getValue()-15)*3.8*freqBar.getValue()*freqMult;
return (float) Math.sin(w+ph);
}
Setup createNext() { return new PhasedArray2Setup(); }
}
class PhasedArray2Setup extends PhasedArray1Setup {
String getName() { return "Phased Array 2"; }
void doSetupSources() {
sourceChooser.select(SRC_1S1F_PLANE_PHASE);
setSources();
sources[0].x = sources[1].x = windowOffsetX+1;
sources[0].y = windowOffsetY+1;
sources[1].y = windowOffsetY+windowHeight-2;
auxBar.setValue(5);
}
float calcSourcePhase(double ph, float v, double w) {
double d = auxBar.getValue()*2.5/30.;
ph -= .5;
ph = Math.sqrt(ph*ph+d*d);
ph *= freqBar.getValue()*freqMult*108;
return (float) Math.sin(w+ph);
}
Setup createNext() { return new PhasedArray3Setup(); }
}
class PhasedArray3Setup extends PhasedArray2Setup {
String getName() { return "Phased Array 3"; }
float calcSourcePhase(double ph, float v, double w) {
double d = auxBar.getValue()*2.5/30.;
ph -= .5;
ph = Math.sqrt(ph*ph+d*d);
ph *= freqBar.getValue()*freqMult*108;
return (float) Math.sin(w-ph);
}
Setup createNext() { return new DopplerSetup(); }
}
class DopplerSetup extends Setup {
String getName() { return "Doppler Effect 1"; }
void select() {
sourceChooser.select(SRC_1S1F_MOVING);
setFreqBar(13);
setBrightness(20);
fixedEndsCheck.setState(false);
}
Setup createNext() { return new Doppler2Setup(); }
}
class Doppler2Setup extends Setup {
String getName() { return "Doppler Effect 2"; }
double wall;
int dir;
int waiting;
void select() {
wall = gridSizeY/2.;
dir = 1;
waiting = 0;
setFreqBar(13);
setBrightness(220);
}
void doSetupSources() {
sourceChooser.select(SRC_1S1F);
setSources();
sources[0].x = windowOffsetX+1;
sources[0].y = windowOffsetY+1;
}
void eachFrame() {
if (waiting > 0) {
waiting--;
return;
}
int w1 = (int) wall;
wall += dir*.04;
int w2 = (int) wall;
if (w1 != w2) {
int i;
for (i = windowOffsetX+windowWidth/3;
i <= gridSizeX-1; i++) {
setWall(i, w1, false);
setWall(i, w2);
int gi = i+w1*gw;
if (w2 < w1)
func[gi] = funci[gi] = 0;
else if (w1 > 1) {
func [gi] = func [gi-gw]/2;
funci[gi] = funci[gi-gw]/2;
}
}
int w3 = (w2-windowOffsetY)/2 + windowOffsetY;
for (i = windowOffsetY; i < w3; i++)
setWall(gridSizeX/2, i);
setWall(gridSizeX/2, i, false);
calcExceptions();
}
if (w2 == windowOffsetY+windowHeight/4 ||
w2 == windowOffsetY+windowHeight*3/4) {
dir = -dir;
waiting = 1000;
}
}
Setup createNext() { return new SonicBoomSetup(); }
}
class SonicBoomSetup extends Setup {
String getName() { return "Sonic Boom"; }
void select() {
sourceChooser.select(SRC_1S1F_MOVING);
setFreqBar(13);
setBrightness(20);
fixedEndsCheck.setState(false);
}
void doSetupSources() {
setSources();
auxBar.setValue(30);
}
Setup createNext() { return new BigModeSetup(); }
}
void setupMode(int x, int y, int sx, int sy, int nx, int ny) {
int i, j;
for (i = 0; i != sx; i++)
for (j = 0; j != sy; j++) {
int gi = i+x+gw*(j+y);
func [gi] = (float)
(Math.sin(pi*nx*(i+1)/(sx+1))*
Math.sin(pi*ny*(j+1)/(sy+1)));
funci[gi] = 0;
}
}
void setupAcousticMode(int x, int y, int sx, int sy, int nx, int ny) {
int i, j;
if (nx == 0 && ny == 0)
return;
for (i = 0; i != sx; i++)
for (j = 0; j != sy; j++) {
int gi = i+x+gw*(j+y);
func [gi] = (float)
(Math.cos(pi*nx*i/(sx-1))*
Math.cos(pi*ny*j/(sy-1)));
funci[gi] = 0;
}
}
class BigModeSetup extends Setup {
String getName() { return "Big 1x1 Mode"; }
void select() {
sourceChooser.select(SRC_NONE);
int i;
int n = windowWidth*3/4;
int x = windowOffsetX+windowWidth/2-n/2;
int y = windowOffsetY+windowHeight/2-n/2;
for (i = 0; i != n+2; i++) {
setWall(x+i-1, y-1);
setWall(x+i-1, y+n);
setWall(x-1, y+i-1);
setWall(x+n, y+i-1);
}
setupMode(x, y, n, n, 1, 1);
dampingBar.setValue(1);
}
Setup createNext() { return new OneByOneModesSetup(); }
}
class OneByOneModesSetup extends Setup {
String getName() { return "1x1 Modes"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 5;
while (y + ny < windowHeight) {
int nx = ((y+ny)*(windowWidth-8)/windowHeight)+6;
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
setupMode(x1, y1, nx, ny, 1, 1);
y += ny+1;
}
dampingBar.setValue(1);
}
Setup createNext() { return new OneByNModesSetup(); }
}
class OneByNModesSetup extends Setup {
String getName() { return "1xN Modes"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 5;
int nx = windowWidth-2;
int mode = 1;
while (y + ny < windowHeight) {
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
setupMode(x1, y1, nx, ny, mode, 1);
y += ny+1;
mode++;
}
dampingBar.setValue(1);
}
Setup createNext() { return new NByNModesSetup(); }
}
class NByNModesSetup extends Setup {
String getName() { return "NxN Modes"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int modex, modey;
int maxmode = 3;
if (resBar.getValue() >= 70)
maxmode++;
if (resBar.getValue() >= 100)
maxmode++;
int ny = windowHeight/maxmode-2;
int nx = windowWidth/maxmode-2;
for (modex = 1; modex <= maxmode; modex++)
for (modey = 1; modey <= maxmode; modey++) {
int x1 = windowOffsetX + 1 + (ny+1)*(modey-1);
int y1 = windowOffsetY + 1 + (nx+1)*(modex-1);
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
setupMode(x1, y1, nx, ny, modex, modey);
}
dampingBar.setValue(1);
}
Setup createNext() { return new OneByNModeCombosSetup(); }
}
class OneByNModeCombosSetup extends Setup {
String getName() { return "1xN Mode Combos"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 5;
int nx = windowWidth-2;
while (y + ny < windowHeight) {
int mode1 = getrand(12)+1;
int mode2;
do
mode2 = getrand(12)+1;
while (mode1 == mode2);
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
for (i = 0; i != nx; i++)
for (j = 0; j != ny; j++) {
int gi = i+x1+gw*(j+y1);
func [gi] = (float)
(Math.sin(mode1*pi*(i+1)/(nx+1))*
Math.sin(pi*(j+1)/(ny+1))*.5 +
Math.sin(mode2*pi*(i+1)/(nx+1))*
Math.sin(pi*(j+1)/(ny+1))*.5);
funci[gi] = 0;
}
y += ny+1;
}
dampingBar.setValue(1);
}
Setup createNext() { return new NByNModeCombosSetup(); }
}
class NByNModeCombosSetup extends Setup {
String getName() { return "NxN Mode Combos"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int maxmode = 3;
if (resBar.getValue() >= 70)
maxmode++;
if (resBar.getValue() >= 100)
maxmode++;
int ny = windowHeight/maxmode-2;
int nx = windowWidth/maxmode-2;
int gx, gy;
for (gx = 1; gx <= maxmode; gx++)
for (gy = 1; gy <= maxmode; gy++) {
int mode1x = getrand(4)+1;
int mode1y = getrand(4)+1;
int mode2x, mode2y;
do {
mode2x = getrand(4)+1;
mode2y = getrand(4)+1;
} while (mode1x == mode2x && mode1y == mode2y);
int x1 = windowOffsetX + 1 + (ny+1)*(gx-1);
int y1 = windowOffsetY + 1 + (nx+1)*(gy-1);
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
for (i = 0; i != nx; i++)
for (j = 0; j != ny; j++) {
int gi = i+x1+gw*(j+y1);
func[gi] = (float)
(Math.sin(mode1x*pi*(i+1)/(nx+1))*
Math.sin(mode1y*pi*(j+1)/(ny+1))*.5 +
Math.sin(mode2x*pi*(i+1)/(nx+1))*
Math.sin(mode2y*pi*(j+1)/(ny+1))*.5);
funci[gi] = 0;
}
}
dampingBar.setValue(1);
}
Setup createNext() { return new ZeroByOneModesSetup(); }
}
class ZeroByOneModesSetup extends Setup {
String getName() { return "0x1 Acoustic Modes"; }
void select() {
fixedEndsCheck.setState(false);
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 5;
while (y + ny < windowHeight) {
int nx = ((y+ny)*(windowWidth-8)/windowHeight)+6;
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
setupAcousticMode(x1, y1, nx, ny, 1, 0);
y += ny+1;
}
dampingBar.setValue(1);
}
Setup createNext() { return new ZeroByNModesSetup(); }
}
class ZeroByNModesSetup extends Setup {
String getName() { return "0xN Acoustic Modes"; }
void select() {
fixedEndsCheck.setState(false);
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 5;
int nx = windowWidth-2;
int mode = 1;
while (y + ny < windowHeight) {
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
setupAcousticMode(x1, y1, nx, ny, mode, 0);
y += ny+1;
mode++;
}
dampingBar.setValue(1);
}
Setup createNext() { return new NByNAcoModesSetup(); }
}
class NByNAcoModesSetup extends Setup {
String getName() { return "NxN Acoustic Modes"; }
void select() {
fixedEndsCheck.setState(false);
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int modex, modey;
int maxmode = 2;
if (resBar.getValue() >= 70)
maxmode++;
// weird things start to happen if maxmode goes higher than 4
int ny = windowHeight/(maxmode+1)-2;
int nx = windowWidth/(maxmode+1)-2;
for (modex = 0; modex <= maxmode; modex++)
for (modey = 0; modey <= maxmode; modey++) {
int x1 = windowOffsetX + 1 + (ny+1)*(modey);
int y1 = windowOffsetY + 1 + (nx+1)*(modex);
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
setupAcousticMode(x1, y1, nx, ny, modex, modey);
}
dampingBar.setValue(1);
}
Setup createNext() { return new CoupledCavitiesSetup(); }
}
class CoupledCavitiesSetup extends Setup {
String getName() { return "Coupled Cavities"; }
void select() {
fixedEndsCheck.setState(false);
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 5;
while (y + ny < windowHeight) {
int nx = 35;
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
for (j = 0; j != 2; j++) {
setWall(x1+nx/2, y1+j);
setWall(x1+nx/2, y1+4-j);
}
setupAcousticMode(x1, y1, nx/2, ny, 1, 0);
y += ny+3;
}
dampingBar.setValue(1);
}
Setup createNext() { return new BeatsSetup(); }
}
class BeatsSetup extends Setup {
String getName() { return "Beats"; }
void doSetupSources() {
sourceChooser.select(SRC_2S2F);
setSources();
auxBar.setValue(24);
sources[0].y = sources[1].y = gridSizeY/2;
sources[0].x = gridSizeX/2 - 2;
sources[1].x = gridSizeX/2 + 2;
}
void select() {
setBrightness(25);
setFreqBar(18);
}
Setup createNext() { return new SlowMediumSetup(); }
}
class SlowMediumSetup extends Setup {
String getName() { return "Slow Medium"; }
void select() {
addMedium();
setFreqBar(10);
setBrightness(33);
}
Setup createNext() { return new RefractionSetup(); }
}
class RefractionSetup extends Setup {
String getName() { return "Refraction"; }
void doSetupSources() {
sourceChooser.select(SRC_1S1F_PLANE_PULSE);
setSources();
sources[0].x = windowOffsetX;
sources[0].y = windowOffsetY + windowHeight/4;
sources[1].x = windowOffsetX + windowWidth/3;
sources[1].y = windowOffsetY;
addMedium();
setFreqBar(1);
setBrightness(33);
}
void select() {}
Setup createNext() { return new InternalReflectionSetup(); }
}
class InternalReflectionSetup extends Setup {
String getName() { return "Internal Reflection"; }
void doSetupSources() {
sourceChooser.select(SRC_1S1F_PLANE_PULSE);
setSources();
sources[0].x = windowOffsetX;
sources[0].y = windowOffsetY + windowHeight*2/3;
sources[1].x = windowOffsetX + windowWidth/3;
sources[1].y = windowOffsetY + windowHeight-1;
addMedium();
setFreqBar(1);
setBrightness(33);
}
void select() {
}
Setup createNext() { return new CoatingSetup(); }
}
class CoatingSetup extends Setup {
String getName() { return "Anti-Reflective Coating"; }
void select() {
sourceChooser.select(SRC_1S1F);
addMedium();
int i, j;
// v2/c2 = 1-(mediumMaxIndex/mediumMax)*medium);
// n = sqrt(v2/c2)
double nmax = Math.sqrt(1-mediumMaxIndex);
double nroot = Math.sqrt(nmax);
int mm = (int) ((1-nmax)*mediumMax/mediumMaxIndex);
for (i = 0; i != gridSizeX; i++)
for (j = gridSizeY/2-4; j != gridSizeY/2; j++)
medium[i+j*gw] = mm;
setFreqBar(6);
setBrightness(28);
}
Setup createNext() { return new ZonePlateEvenSetup(); }
}
class ZonePlateEvenSetup extends Setup {
int zoneq;
ZonePlateEvenSetup() { zoneq = 1; }
String getName() { return "Zone Plate (Even)"; }
void doSetupSources() { }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
setSources();
if (resBar.getValue() < 42)
setResolution(42);
int i;
// wavelength by default = 25, we want it to be 6
int freq = 30;
setFreqBar(freq);
double halfwave = 25./(freq*2/5);
int y = sources[0].y+1;
int dy = windowOffsetY+windowHeight/2-y;
int dy2 = dy*dy;
int cx = gridSizeX/2;
for (i = 0; i != windowWidth; i++) {
int x = windowOffsetX+i;
int dx = cx-x;
double dist = Math.sqrt(dx*dx+dy*dy);
dist = (dist-dy);
int zone = (int) (dist / halfwave);
setWall(x, y, ((zone & 1) == zoneq));
setWall(windowOffsetX, y);
setWall(windowOffsetX+windowWidth-1, y);
}
setBrightness(zoneq == 1 ? 4 : 7);
}
Setup createNext() { return new ZonePlateOddSetup(); }
}
class ZonePlateOddSetup extends ZonePlateEvenSetup {
ZonePlateOddSetup() { zoneq = 0; }
String getName() { return "Zone Plate (Odd)"; }
Setup createNext() { return new CircleSetup(); }
}
class CircleSetup extends Setup {
CircleSetup() { circle = true; }
boolean circle;
String getName() { return "Circle"; }
void doSetupSources() { }
void select() {
int i;
int dx = windowWidth/2-2;
double a2 = dx*dx;
double b2 = a2/2;
if (circle)
b2 = a2;
int cx = windowWidth/2 + windowOffsetX;
int cy = windowHeight/2 + windowOffsetY;
int ly = -1;
for (i = 0; i <= dx; i++) {
double y = Math.sqrt((1-i*i/a2)*b2);
int yi = (int) (y+1.5);
if (i == dx)
yi = 0;
if (ly == -1)
ly = yi;
for (; ly >= yi; ly--) {
setWall(cx+i, cy+ly);
setWall(cx-i, cy+ly);
setWall(cx+i, cy-ly);
setWall(cx-i, cy-ly);
//setWall(cx-ly, cx+i);
//setWall(cx+ly, cx+i);
}
ly = yi;
}
int c = (int) (Math.sqrt(a2-b2));
//walls[cx+c][cy] = walls[cx-c][cy] = true;
//walls[cx][cy+c] = true;
sourceChooser.select(SRC_1S1F_PULSE);
setSources();
sources[0].x = cx-c;
sources[0].y = cy;
setFreqBar(1);
setBrightness(16);
}
Setup createNext() { return new EllipseSetup(); }
}
class EllipseSetup extends CircleSetup {
EllipseSetup() { circle = false; }
String getName() { return "Ellipse"; }
Setup createNext() { return new ResonantCavitiesSetup(); }
}
class ResonantCavitiesSetup extends Setup {
String getName() { return "Resonant Cavities 1"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int x = 1;
int nx = 5;
int y1 = windowOffsetY + 11;
while (x + nx < windowWidth) {
int ny = ((x+nx)*(windowHeight-18)/windowWidth)+6;
int x1 = x + windowOffsetX;
for (i = 0; i != ny+2; i++) {
setWall(x1-1, y1+i-1);
setWall(x1+nx, y1+i-1);
}
for (j = 0; j != nx+2; j++) {
setWall(x1+j-1, y1-1);
setWall(x1+j-1, y1+ny);
}
setWall(x1+nx/2, y1-1, false);
x += nx+1;
}
for (; x < windowWidth; x++)
setWall(x+windowOffsetX, y1-1);
setBrightness(30);
setFreqBar(15);
}
double sourceStrength() { return .1; }
Setup createNext() { return new ResonantCavities2Setup(); }
}
class ResonantCavities2Setup extends Setup {
String getName() { return "Resonant Cavities 2"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int x = 1;
int nx = 5;
int y1 = windowOffsetY + 11;
int ny = 5;
while (x + nx < windowWidth) {
int x1 = x + windowOffsetX;
for (i = 0; i != ny+2; i++) {
setWall(x1-1, y1+i-1);
setWall(x1+nx, y1+i-1);
}
for (j = 0; j != nx+2; j++)
setWall(x1+j-1, y1+ny);
x += nx+1;
ny++;
}
for (; x < windowWidth; x++)
setWall(x+windowOffsetX, y1-1);
setBrightness(30);
setFreqBar(16);
}
double sourceStrength() { return .03; }
Setup createNext() { return new RoomResonanceSetup(); }
}
class RoomResonanceSetup extends Setup {
String getName() { return "Room Resonance"; }
void select() {
sourceChooser.select(SRC_4S1F);
setSources();
int i, j;
int modex, modey;
int ny = 17;
int nx = 17;
for (modex = 1; modex <= 2; modex++)
for (modey = 1; modey <= 2; modey++) {
int x1 = windowOffsetX + 1 + (ny+1)*(modey-1);
int y1 = windowOffsetY + 1 + (nx+1)*(modex-1);
for (i = 0; i != nx+2; i++) {
setWall(x1+i-1, y1-1);
setWall(x1+i-1, y1+ny);
}
for (j = 0; j != ny+2; j++) {
setWall(x1-1, y1+j-1);
setWall(x1+nx, y1+j-1);
}
}
sources[0].x = sources[2].x = windowOffsetX + 2;
sources[0].y = sources[1].y = windowOffsetY + 2;
sources[1].x = sources[3].x = windowOffsetX+1+nx+(nx+1)/2;
sources[2].y = sources[3].y = windowOffsetY+1+ny+(ny+1)/2;
fixedEndsCheck.setState(false);
dampingBar.setValue(10);
setBrightness(3);
}
void doSetupSources() { }
Setup createNext() { return new Waveguides1Setup(); }
}
class Waveguides1Setup extends Setup {
String getName() { return "Waveguides 1"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int x = 1;
int nx = 3;
int y1 = windowOffsetY + 3;
int ny = windowHeight-2;
while (x + nx < windowWidth) {
int x1 = x + windowOffsetX;
for (i = 0; i != ny; i++) {
setWall(x1-1, y1+i-1);
setWall(x1+nx, y1+i-1);
}
nx++;
x += nx;
}
for (; x < windowWidth; x++)
setWall(x+windowOffsetX, y1-1);
setBrightness(6);
setFreqBar(14);
}
Setup createNext() { return new Waveguides2Setup(); }
}
class Waveguides2Setup extends Waveguides1Setup {
String getName() { return "Waveguides 2"; }
void select() {
super.select();
setFreqBar(8);
}
Setup createNext() { return new Waveguides3Setup(); }
}
class Waveguides3Setup extends Setup {
String getName() { return "Waveguides 3"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int x = 1;
int nx = 8;
int y1 = windowOffsetY + 3;
int ny = windowHeight-2;
for (x = 1; x < windowWidth; x++)
setWall(x+windowOffsetX, y1-1);
x = 1;
j = 0;
while (x + nx < windowWidth && j < nx) {
int x1 = x + windowOffsetX;
for (i = 0; i != ny; i++) {
setWall(x1-1, y1+i-1);
setWall(x1+nx, y1+i-1);
}
setWall(x1+j++, y1-1, false);
x += nx+1;
}
setBrightness(89);
setFreqBar(16);
}
Setup createNext() { return new Waveguides4Setup(); }
}
class Waveguides4Setup extends Waveguides3Setup {
String getName() { return "Waveguides 4"; }
void select() {
super.select();
setBrightness(29);
setFreqBar(20);
fixedEndsCheck.setState(false);
}
Setup createNext() { return new Waveguides5Setup(); }
}
class Waveguides5Setup extends Waveguides3Setup {
String getName() { return "Waveguides 5"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i;
int x = 1;
int nx = 8;
int y1 = windowOffsetY + 2;
int ny = windowHeight-1;
x = 1;
while (x + nx < windowWidth) {
int x1 = x + windowOffsetX;
for (i = 0; i != ny; i++) {
setWall(x1-1, y1+i-1);
setWall(x1+nx, y1+i-1);
}
x += nx+1;
}
setBrightness(9);
setFreqBar(22);
}
void eachFrame() {
int y = windowOffsetY+1;
int nx = 8;
int x = 1;
int g = 1;
while (x + nx < windowWidth) {
int x1 = x + windowOffsetX;
int j;
int n1 = 1;
int n2 = 1;
switch (g) {
case 1: n1 = n2 = 1; break;
case 2: n1 = n2 = 2; break;
case 3: n1 = 1; n2 = 2; break;
case 4: n1 = n2 = 3; break;
case 5: n1 = 1; n2 = 3; break;
case 6: n1 = 2; n2 = 3; break;
default: n1 = n2 = 0; break;
}
for (j = 0; j != nx; j++)
func[x1+j+gw*y] *= .5*
(Math.sin(pi*n1*(j+1)/(nx+1)) +
Math.sin(pi*n2*(j+1)/(nx+1)));
x += nx+1;
g++;
}
}
Setup createNext() { return new ParabolicMirror1Setup(); }
}
/*class HornSetup extends Setup {
String getName() { return "Horn"; }
void select() {
if (resBar.getValue() < 76)
setResolution(76);
fixedEndsCheck.setState(false);
setFreqBar(3);
int i;
int cx = windowOffsetX+windowWidth/2;
int yy = windowHeight/2;
int oj = 0;
double lmult = Math.log(windowWidth/2-2)*1.2;
System.out.println(yy + " " + lmult);
for (i = 0; i < yy; i++) {
int j = (int) (Math.exp(i*lmult/yy));
System.out.println(i + " " +j);
//int j = i*((windowWidth-5)/2)/yy;
while (oj <= j) {
walls[cx+oj][windowOffsetY+i] =
walls[cx-oj][windowOffsetY+i] = true;
oj++;
}
oj = j;
}
setBrightness(12);
}
Setup createNext() { return new ParabolicMirror1Setup(); }
}*/
class ParabolicMirror1Setup extends Setup {
String getName() { return "Parabolic Mirror 1"; }
void select() {
if (resBar.getValue() < 50)
setResolution(50);
int i;
int cx = windowWidth/2 + windowOffsetX;
int lx = 0;
int dy = windowHeight/2;
int cy = windowHeight+windowOffsetY-2;
int dx = windowWidth/2-2;
double c = dx*dx*.5/dy;
if (c > 20)
c = 20;
for (i = 0; i <= dy; i++) {
double x = Math.sqrt(2*c*i);
int xi = (int) (x+1.5);
for (; lx <= xi; lx++) {
setWall(cx-lx, cy-i);
setWall(cx+lx, cy-i);
}
lx = xi;
}
setSources();
sources[0].x = cx;
sources[0].y = (int) (cy-1-c/2);
setBrightness(18);
}
void doSetupSources() {}
Setup createNext() { return new ParabolicMirror2Setup(); }
}
class ParabolicMirror2Setup extends ParabolicMirror1Setup {
String getName() { return "Parabolic Mirror 2"; }
void doSetupSources() {
sourceChooser.select(SRC_1S1F_PLANE);
brightnessBar.setValue(370);
setFreqBar(15);
setSources();
}
Setup createNext() { return new SoundDuctSetup(); }
}
class SoundDuctSetup extends Setup {
String getName() { return "Sound Duct"; }
void select() {
sourceChooser.select(SRC_1S1F_PULSE);
fixedEndsCheck.setState(false);
int i;
int cx = windowOffsetX+windowWidth/2;
for (i = 0; i != windowHeight-12; i++) {
setWall(cx-3, i+windowOffsetY+6);
setWall(cx+3, i+windowOffsetY+6);
}
setFreqBar(1);
setBrightness(60);
}
Setup createNext() { return new BaffledPistonSetup(); }
}
class BaffledPistonSetup extends Setup {
String getName() { return "Baffled Piston"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
fixedEndsCheck.setState(false);
int i;
for (i = 0; i != gridSizeY; i++)
setWall(windowOffsetX+2, i);
for (i = 0; i <= 11; i++) {
setWall(windowOffsetX, i+gridSizeY/2-5);
if (i != 0 && i != 11)
setWall(windowOffsetX+2, i+gridSizeY/2-5, false);
}
setWall(windowOffsetX+1, gridSizeY/2-5);
setWall(windowOffsetX+1, gridSizeY/2+6);
setFreqBar(24);
setSources();
sources[0].x = sources[1].x = windowOffsetX+1;
sources[0].y = gridSizeY/2-4;
sources[1].y = gridSizeY/2+5;
setBrightness(18);
}
void doSetupSources() {
}
Setup createNext() { return new LowPassFilter1Setup(); }
}
class LowPassFilter1Setup extends Setup {
String getName() { return "Low-Pass Filter 1"; }
void select() {
if (resBar.getValue() < 43)
setResolution(43);
fixedEndsCheck.setState(false);
int i, j;
for (i = 0; i != windowWidth; i++)
setWall(i+windowOffsetX, windowOffsetY+9);
int cx = gridSizeX/2;
for (i = 1; i <= 4; i++)
for (j = -7; j <= 7; j++)
setWall(cx+j, windowOffsetY+9*i);
for (i = 0; i <= 4; i++)
for (j = -4; j <= 4; j++)
setWall(cx+j, windowOffsetY+9*i, false);
for (i = 0; i != 27; i++) {
setWall(cx+7, windowOffsetY+9+i);
setWall(cx-7, windowOffsetY+9+i);
}
setBrightness(38);
}
Setup createNext() { return new LowPassFilter2Setup(); }
}
class LowPassFilter2Setup extends LowPassFilter1Setup {
String getName() { return "Low-Pass Filter 2"; }
void select() {
super.select();
setFreqBar(17);
}
Setup createNext() { return new HighPassFilter1Setup(); }
}
class HighPassFilter1Setup extends Setup {
String getName() { return "High-Pass Filter 1"; }
void select() {
if (resBar.getValue() < 43)
setResolution(43);
fixedEndsCheck.setState(false);
int i, j;
for (i = 0; i != windowWidth; i++)
for (j = 0; j <= 25; j += 5)
setWall(i+windowOffsetX, windowOffsetY+9+j);
int cx = gridSizeX/2;
for (i = 0; i <= 25; i += 5)
for (j = -4; j <= 4; j++)
setWall(cx+j, windowOffsetY+9+i, false);
setBrightness(62);
// by default we show a freq high enough to be passed
setFreqBar(17);
}
Setup createNext() { return new HighPassFilter2Setup(); }
}
class HighPassFilter2Setup extends HighPassFilter1Setup {
String getName() { return "High-Pass Filter 2"; }
void select() {
super.select();
setFreqBar(7);
}
Setup createNext() { return new BandStopFilter1Setup(); }
}
class BandStopFilter1Setup extends Setup {
String getName() { return "Band-Stop Filter 1"; }
void select() {
if (resBar.getValue() < 43)
setResolution(43);
fixedEndsCheck.setState(false);
int i, j, k;
for (i = 0; i != windowWidth; i++)
setWall(i+windowOffsetX, windowOffsetY+9);
int cx = gridSizeX/2;
for (i = 1; i <= 2; i++)
for (j = -11; j <= 11; j++) {
if (j > -5 && j < 5)
continue;
setWall(cx+j, windowOffsetY+9+9*i);
}
for (i = 0; i <= 1; i++)
for (j = -4; j <= 4; j++)
setWall(cx+j, windowOffsetY+9+i*26, false);
for (i = 0; i <= 18; i++) {
setWall(cx+11, windowOffsetY+9+i);
setWall(cx-11, windowOffsetY+9+i);
}
for (i = 0; i != 3; i++)
for (j = 0; j != 3; j++)
for (k = 9; k <= 18; k += 9) {
setWall(cx+5+i, windowOffsetY+k+j);
setWall(cx+5+i, windowOffsetY+9+k-j);
setWall(cx-5-i, windowOffsetY+k+j);
setWall(cx-5-i, windowOffsetY+9+k-j);
}
setBrightness(38);
setFreqBar(2);
}
Setup createNext() { return new BandStopFilter2Setup(); }
}
class BandStopFilter2Setup extends BandStopFilter1Setup {
String getName() { return "Band-Stop Filter 2"; }
void select() {
super.select();
setFreqBar(10);
}
Setup createNext() { return new BandStopFilter3Setup(); }
}
class BandStopFilter3Setup extends BandStopFilter1Setup {
String getName() { return "Band-Stop Filter 3"; }
void select() {
super.select();
// at this frequency it doesn't pass
setFreqBar(4);
}
Setup createNext() { return new PlanarConvexLensSetup(); }
}
class PlanarConvexLensSetup extends Setup {
String getName() { return "Planar Convex Lens"; }
void select() {
if (resBar.getValue() < 42)
setResolution(42);
sourceChooser.select(SRC_1S1F_PLANE);
// need small wavelengths here to remove diffraction effects
int i, j;
int cx = gridSizeX/2;
int cy = windowHeight/8+windowOffsetY;
int x0 = windowWidth/3-2;
int y0 = 5;
double r = (.75*windowHeight)*.5;
double h = r-y0;
double r2 = r*r;
if (x0 > r)
x0 = (int) r;
for (i = 0; i <= x0; i++) {
int y = 2+(int) (Math.sqrt(r2-i*i)-h+.5);
for (; y >= 0; y--) {
setMedium(cx+i, cy+y, mediumMax/2);
setMedium(cx-i, cy+y, mediumMax/2);
}
}
setFreqBar(19);
setBrightness(6);
}
Setup createNext() { return new BiconvexLensSetup(); }
}
class BiconvexLensSetup extends Setup {
String getName() { return "Biconvex Lens"; }
void select() {
if (resBar.getValue() < 50)
setResolution(50);
setSources();
int i, j;
int cx = gridSizeX/2;
int cy = gridSizeY/2;
int x0 = windowWidth/3-2;
int y0 = 10;
double r = (.75*.5*windowHeight)*.5;
double h = r-y0;
double r2 = r*r;
if (x0 > r)
x0 = (int) r;
for (i = 0; i <= x0; i++) {
int y = 1+(int) (Math.sqrt(r2-i*i)-h+.5);
for (; y >= 0; y--) {
setMedium(cx+i, cy+y, mediumMax/2);
setMedium(cx-i, cy+y, mediumMax/2);
setMedium(cx+i, cy-y, mediumMax/2);
setMedium(cx-i, cy-y, mediumMax/2);
}
}
setFreqBar(19);
setBrightness(66);
sources[0].y = cy-(2+2*(int) r);
}
void doSetupSources() {}
Setup createNext() { return new PlanarConcaveSetup(); }
}
class PlanarConcaveSetup extends Setup {
String getName() { return "Planar Concave Lens"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int cx = gridSizeX/2;
int cy = windowHeight/8+windowOffsetY;
int x0 = windowWidth/5;
int y0 = 5;
double r = (.25*windowHeight)*.5;
double h = r-y0;
double r2 = r*r;
if (x0 > r)
x0 = (int) r;
for (i = 0; i <= x0; i++) {
int y = y0+2-(int) (Math.sqrt(r2-i*i)-h+.5);
for (; y >= 0; y--) {
setMedium(cx+i, cy+y, mediumMax/2);
setMedium(cx-i, cy+y, mediumMax/2);
}
}
for (i = 0; i != windowWidth; i++)
if (medium[windowOffsetX+i+gw*cy] == 0)
setWall(windowOffsetX+i, cy);
setFreqBar(19);
}
Setup createNext() { return new CircularPrismSetup(); }
}
class CircularPrismSetup extends Setup {
String getName() { return "Circular Prism"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int cx = gridSizeX/2;
int cy = gridSizeY/2;
int x0 = windowWidth/3-2;
int y0 = x0;
double r = (x0*x0+y0*y0)/(2.*y0);
double h = r-y0;
double r2 = r*r;
for (i = 0; i < x0; i++) {
int y = (int) (Math.sqrt(r2-i*i)-h+.5);
for (; y >= 0; y--) {
setMedium(cx+i, cy+y, mediumMax);
setMedium(cx-i, cy+y, mediumMax);
setMedium(cx+i, cy-y, mediumMax);
setMedium(cx-i, cy-y, mediumMax);
}
}
for (i = 0; i != windowWidth; i++)
if (medium[windowOffsetX+i+gw*cy] == 0)
setWall(windowOffsetX+i, cy);
setFreqBar(9);
}
Setup createNext() { return new RightAnglePrismSetup(); }
}
class RightAnglePrismSetup extends Setup {
String getName() { return "Right-Angle Prism"; }
void select() {
if (resBar.getValue() < 42)
setResolution(42);
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int cx = gridSizeX/2;
int cy = gridSizeY/2;
int x0 = windowWidth/4;
int y0 = x0;
for (i = -x0; i < x0; i++)
for (j = -y0; j <= i; j++)
setMedium(cx+i, cy+j, mediumMax);
for (i = 0; i != windowWidth; i++)
if (medium[windowOffsetX+i+gw*(cy-y0)] == 0)
setWall(windowOffsetX+i, cy-y0);
setFreqBar(11);
}
Setup createNext() { return new PorroPrismSetup(); }
}
class PorroPrismSetup extends Setup {
String getName() { return "Porro Prism"; }
void select() {
if (resBar.getValue() < 42)
setResolution(42);
sourceChooser.select(SRC_1S1F_PLANE);
setSources();
int i, j;
int cx = gridSizeX/2;
sources[1].x = cx-1;
int x0 = windowWidth/2;
int y0 = x0;
int cy = gridSizeY/2-y0/2;
for (i = -x0; i < x0; i++) {
int j2 = y0+1-((i < 0) ? -i : i);
for (j = 0; j <= j2; j++)
setMedium(cx+i, cy+j, mediumMax);
}
for (i = 0; i != cy; i++)
if (medium[cx+gw*(i+windowOffsetY)] == 0)
setWall(cx, i+windowOffsetY);
setFreqBar(11);
}
void doSetupSources() {}
Setup createNext() { return new ScatteringSetup(); }
}
class ScatteringSetup extends Setup {
String getName() { return "Scattering"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE_PULSE);
int cx = gridSizeX/2;
int cy = gridSizeY/2;
setWall(cx, cy);
setFreqBar(1);
dampingBar.setValue(40);
setBrightness(52);
}
Setup createNext() { return new LloydsMirrorSetup(); }
}
class LloydsMirrorSetup extends Setup {
String getName() { return "Lloyd's Mirror"; }
void select() {
setSources();
sources[0].x = windowOffsetX;
sources[0].y = windowOffsetY + windowHeight*3/4;
setBrightness(75);
setFreqBar(23);
int i;
for (i = 0; i != windowWidth; i++)
setWall(i+windowOffsetX, windowOffsetY+windowHeight-1);
}
void doSetupSources() {}
Setup createNext() { return new TempGradient1(); }
}
class TempGradient1 extends Setup {
String getName() { return "Temperature Gradient 1"; }
void select() {
int i, j;
int j1 = windowOffsetY + windowHeight/2;
int j2 = windowOffsetY + windowHeight*3/4;
int j3 = windowOffsetY + windowHeight*7/8;
for (j = 0; j != gridSizeY; j++) {
int m;
if (j < j1)
m = 0;
else if (j > j2)
m = mediumMax;
else
m = mediumMax*(j-j1)/(j2-j1);
for (i = 0; i != gridSizeX; i++)
setMedium(i, j, m);
}
for (i = j3; i < windowOffsetY+windowHeight; i++)
setWall(gridSizeX/2, i);
setBrightness(33);
}
void doSetupSources() {
setSources();
sources[0].x = windowOffsetX+2;
sources[0].y = windowOffsetY+windowHeight-2;
}
Setup createNext() { return new TempGradient2(); }
}
class TempGradient2 extends Setup {
String getName() { return "Temperature Gradient 2"; }
void select() {
int i, j;
int j1 = windowOffsetY + windowHeight/2 - windowHeight/8;
int j2 = windowOffsetY + windowHeight/2 + windowHeight/8;
for (j = 0; j != gridSizeY; j++) {
int m;
if (j < j1)
m = mediumMax;
else if (j > j2)
m = 0;
else
m = mediumMax*(j2-j)/(j2-j1);
for (i = 0; i != gridSizeX; i++)
setMedium(i, j, m);
}
setBrightness(31);
}
void doSetupSources() {
setSources();
sources[0].x = windowOffsetX+2;
sources[0].y = windowOffsetY+windowHeight/4;
}
Setup createNext() { return new TempGradient3(); }
}
class TempGradient3 extends Setup {
String getName() { return "Temperature Gradient 3"; }
void select() {
int i, j;
int j1 = windowOffsetY + windowHeight/2 - windowHeight/5;
int j2 = windowOffsetY + windowHeight/2 + windowHeight/5;
int j3 = gridSizeY/2;
for (j = 0; j != gridSizeY; j++) {
int m;
if (j < j1 || j > j2)
m = mediumMax;
else if (j > j3)
m = mediumMax*(j-j3)/(j2-j3);
else
m = mediumMax*(j3-j)/(j3-j1);
for (i = 0; i != gridSizeX; i++)
setMedium(i, j, m);
}
setBrightness(31);
}
void doSetupSources() {
setSources();
sources[0].x = windowOffsetX+2;
sources[0].y = windowOffsetY+windowHeight/4;
}
Setup createNext() { return new TempGradient4(); }
}
class TempGradient4 extends TempGradient3 {
String getName() { return "Temperature Gradient 4"; }
void select() {
int i, j;
int j1 = windowOffsetY + windowHeight/2 - windowHeight/5;
int j2 = windowOffsetY + windowHeight/2 + windowHeight/5;
int j3 = gridSizeY/2;
for (j = 0; j != gridSizeY; j++) {
int m;
if (j < j1 || j > j2)
m = 0;
else if (j > j3)
m = mediumMax*(j2-j)/(j2-j3);
else
m = mediumMax*(j-j1)/(j3-j1);
for (i = 0; i != gridSizeX; i++)
setMedium(i, j, m);
}
setBrightness(31);
}
Setup createNext() { return new DispersionSetup(); }
}
class DispersionSetup extends Setup {
String getName() { return "Dispersion"; }
void select() {
sourceChooser.select(SRC_2S2F);
int i, j;
for (i = 0; i != gridSizeY; i++)
setWall(gridSizeX/2, i);
for (i = 0; i != gridSizeX; i++)
for (j = 0; j != gridSizeY; j++)
setMedium(i, j, mediumMax/3);
fixedEndsCheck.setState(false);
setBrightness(16);
}
void doSetupSources() {
setSources();
sources[0].x = gridSizeX/2-2;
sources[1].x = gridSizeX/2+2;
sources[0].y = sources[1].y = windowOffsetY+1;
setFreqBar(7);
auxBar.setValue(30);
}
Setup createNext() { return null; }
}
}
A far higher place must be assigned to Judaism among the competitors for the allegiance of Europe. The cosmopolitan importance at one time assumed by this religion has been considerably obscured, owing to the subsequent devolution of its part to Christianity. It is, however, by no means impossible that, but for the diversion created by the Gospel, and the disastrous consequences of their revolt against Rome, the Jews might have won the world to a purified form of their own monotheism. A few significant circumstances are recorded showing how much influence they had acquired, even in Rome, before the first preaching of Christianity. The first of these is to be found in Cicero¡¯s defence of Flaccus. The latter was accused of appropriating part of the annual contributions sent to the temple at Jerusalem; and, in dealing with this charge, Cicero speaks of the Jews, who were naturally prejudiced against his client, as a powerful faction the hostility of which he is anxious not to provoke.330 Some twenty years later, a great advance has been made. Not only must the material interests of the Jews be respected, but a certain conformity to their religious prescriptions is considered a mark of good breeding, In one of his most amusing satires, Horace tells us how, being anxious to shake off a bore, he appeals for help to his friend Aristius Fuscus, and reminds him of217 some private business which they had to discuss together. Fuscus sees his object, and being mischievously determined to defeat it, answers: ¡®Yes, I remember perfectly, but we must wait for some better opportunity; this is the thirtieth Sabbath, do you wish to insult the circumcised Jews?¡¯ ¡®I have no scruples on that point,¡® replies the impatient poet. ¡®But I have,¡¯ rejoins Fuscus,¡ª¡®a little weak-minded, one of the many, you know¡ªexcuse me, another time.¡®331 Nor were the Jews content with the countenance thus freely accorded them. The same poet elsewhere intimates that whenever they found themselves in a majority, they took advantage of their superior strength to make proselytes by force.¡¯332 And they pursued the good work to such purpose that a couple of generations later we find Seneca bitterly complaining that the vanquished had given laws to the victors, and that the customs of this abominable race were established over the whole earth.333 Evidence to the same effect is given by Philo Judaeus and Josephus, who inform us that the Jewish laws and customs were admired, imitated, and obeyed over the whole earth.334 Such assertions might be suspected of exaggeration, were they not, to a certain extent, confirmed by the references already quoted, to which others of the same kind may be added from later writers showing that it was a common practice among the Romans to abstain from work on the Sabbath, and even to celebrate it by praying, fasting, and lighting lamps, to visit the synagogues, to study the law of Moses, and to pay the yearly contribution of two drachmas to the temple at Jerusalem.335 Jeff¡¯s hand was quietly coming down. ¡°What happened to you?¡± begged Sandy. ¡°Something new has come up, sir. I was waiting there by my ship a good while back, and I heard another one cruising and spiraling, shooting the field, I guess, because he came in and set down. My crate, just the way you ordered, was down by the grove, not in plain sight in the middle of the course. But Jeff set his ship down, left the engine running, and went off. I stayed hid to see what would happen, but when he didn¡¯t come back, I thought I¡¯d better go and find you¡ªand see if it meant anything to you.¡± She stood alone, with the sticky, wet knife in her hand, catching her breath, coming out of the madness. Then she stooped, and pushing the branches aside felt about for her pistol. It lay at the root of a tree, and[Pg 80] when she had picked it up and put it back in the holster, there occurred to her for the first time the thought that the shot in the dead stillness must have roused the camp. And now she was sincerely frightened. If she were found here, it would be more than disagreeable for Landor. They must not find her. She started at a swift, long-limbed run, making a wide detour, to avoid the sentries, bending low, and flying silently among the bushes and across the shadowy sands. The year 1756 opened with menaces to England of the most serious nature. The imbecility of the Ministry was beginning to tell in the neglect of its colonies and its defences. France threatened to invade us, and a navy of fifty thousand men was suddenly voted, and an army of thirty-four thousand two hundred and sixty-three of native troops; but as these were not ready, it was agreed to bring over eight thousand Hessians and Hanoverians. To pay for all this it was necessary to grant excessive supplies, and lay on new duties and taxes. In presenting the money bills in the month of May, Speaker Onslow could not avoid remarking that there were two circumstances which tended to create alarm¡ªforeign subsidies and foreign troops introduced, and nothing but their confidence in his Majesty could allay their fears, or give them confidence that their burdens would be soon reduced. There was, in fact, no chance for any such reduction, for wars, troubles, and disgraces were gathering around from various quarters. The first reverse came from the Mediterranean. MUCH to their amazement, the boys waked up the next morning in Nashville, and found that they had passed through the "dark and bloody ground" of Kentucky absolutely without adventure. After drawing and dividing the rations and cartridges. Si gave the boys the necessary instruction about having their things ready so that they could get them in the dark the next morning, and ordered them to disregard the bonfires and mirth-making, and lie down to get all the sleep they could, in preparation for the hard work of the next day. Then, like the rest of the experienced men, who saw that the campaign was at length really on, and this would be the last opportunity for an indefinite while to write, he sat down to write short letters to his mother and to Annabel. "Bully for the Wild Wanderers of the Wabash," Shorty joined in. "They're the boss regiment in the army o' the Cumberland, and the Army o' the Cumberland's the boss army on earth. Hooray for US Co. Le's have a speech. Where's Monty Scruggs?" "Bring a light, do¡ªI can't abide this dark." Albert suddenly began to look uneasy. After all he was not really drunk, only a little fuddled. He walked straight, and his roll was natural to him, while though he was exceedingly cheerful, and often burst into song, his words were not jumbled, and he generally seemed to have a fair idea of what he was saying. "But I heard what the doctor said to you." "A purty accident¡ªwud them stacks no more dry than a ditch. 'Twas a clear case of 'bustion¡ªfireman said so to me; as wicked and tedious a bit o' wark as ever I met in my life." Calverley stept from the shadow of the cliff, and beheld a meteor in the sky, brightening and expanding, as the clouds opened, until it assumed the appearance of a brilliant star, of astonishing magnitude, encircled by dazzling rays, which, in a singular manner, were all inclined in one direction, and pointing to that part of the horizon where lay the rival of England¡ªFrance. The foreman's face assumed a deeper hue than usual: he looked fiercely at the galleyman, but there was a determination in the weather-beaten face that made him pause ere he spoke. "Galleyman," he at length said, "you knew the business before you came: if you be so fond of saving old witches' lives, why didn't you say so, that I might not now be in this dilemma?" "No, no, not the boy," replied Merritt, rather impatiently. HoMEÁíÀàС˵ߣɫ
ENTER NUMBET 0017
www.botooa.com.cn
www.guiye7.com.cn
www.ganbi0.com.cn
www.tumao9.com.cn
www.dexin2.net.cn
www.bacun4.net.cn
zhcyge.com.cn
www.9cc.com.cn
www.51fhb.net.cn
huaba2.com.cn