// EMWave2.java (c) 2002 by Paul Falstad, www.falstad.com
import java.io.InputStream;
import java.awt.*;
import java.awt.image.*;
import java.applet.Applet;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.File;
import java.util.Random;
import java.util.Arrays;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.Math;
import java.awt.event.*;
class EMWave2Canvas extends Canvas {
EMWave2Frame pg;
EMWave2Canvas(EMWave2Frame p) {
pg = p;
}
public Dimension getPreferredSize() {
return new Dimension(300,400);
}
public void update(Graphics g) {
pg.updateEMWave2(g);
}
public void paint(Graphics g) {
pg.updateEMWave2(g);
}
};
class EMWave2Layout implements LayoutManager {
public EMWave2Layout() {}
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* 2/3;
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 EMWave2 extends Applet implements ComponentListener {
static EMWave2Frame 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 EMWave2Frame(null);
ogf.init();
}
void showFrame() {
if (ogf == null) {
started = true;
ogf = new EMWave2Frame(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
ogf.show();
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 EMWave2Frame 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 windowWidth = 50;
int windowHeight = 50;
int windowOffsetX = 0;
int windowOffsetY = 0;
public static final int sourceRadius = 7;
public static final double freqMult = .0233333/2;
public String getAppletInfo() {
return "EMWave2 by Paul Falstad";
}
Button clearButton;
Button ClearAllButton;
Checkbox stoppedCheck;
Choice modeChooser;
Choice viewChooser;
Choice sourceChooser;
Choice setupChooser;
Vector setupList;
Setup setup;
Scrollbar speedBar;
Scrollbar forceBar;
Scrollbar resBar;
Scrollbar brightnessBar;
Scrollbar lineDensityBar;
Scrollbar auxBar;
Scrollbar adjustBar;
Label auxLabel;
Label adjustLabel;
double forceTimeZero;
double sourceMult;
static final double pi = 3.14159265358979323846;
OscElement grid[];
int gw;
OscSource sources[];
static final int MODE_PERF_CONDUCTOR = 0;
static final int MODE_GOOD_CONDUCTOR = 1;
static final int MODE_FAIR_CONDUCTOR = 2;
static final int MODE_J_POS = 3;
static final int MODE_J_NEG = 4;
static final int MODE_FERROMAG = 5;
static final int MODE_DIAMAG = 6;
static final int MODE_MEDIUM = 7;
static final int MODE_M_DOWN = 8;
static final int MODE_M_UP = 9;
static final int MODE_M_LEFT = 10;
static final int MODE_M_RIGHT = 11;
static final int MODE_RESONANT = 12;
static final int MODE_CLEAR = 13;
static final int MODE_ADJUST = 14; // same as next one
static final int MODE_ADJ_CONDUCT = 14;
static final int MODE_ADJ_PERM = 15;
static final int MODE_ADJ_J = 16;
static final int MODE_ADJ_MEDIUM = 17;
static final int MODE_ADJ_MAG_DIR = 18;
static final int MODE_ADJ_MAG_STR = 19;
static final int VIEW_E = 0;
static final int VIEW_B = 1;
static final int VIEW_B_LINES = 2;
static final int VIEW_B_STRENGTH = 3;
static final int VIEW_J = 4;
static final int VIEW_E_B = 5;
static final int VIEW_E_B_LINES = 6;
static final int VIEW_E_B_J = 7;
static final int VIEW_E_B_LINES_J = 8;
static final int VIEW_H = 9;
static final int VIEW_M = 10;
static final int VIEW_TYPE = 11;
static final int VIEW_A = 12;
static final int VIEW_POYNTING = 13;
static final int VIEW_ENERGY = 14;
static final int VIEW_POYNTING_ENERGY = 15;
static final int VIEW_FORCE = 16;
static final int VIEW_EFF_CUR = 17;
static final int VIEW_MAG_CHARGE = 18;
static final int VIEW_CURL_E = 19;
static final int VIEW_BX = 20;
static final int VIEW_BY = 21;
static final int VIEW_HX = 22;
static final int VIEW_HY = 23;
static final int VIEW_NONE = -1;
static final int TYPE_CONDUCTOR = 1;
static final int TYPE_DIAMAGNET = 2;
static final int TYPE_FERROMAGNET = 3;
static final int TYPE_MAGNET = 4;
static final int TYPE_CURRENT = 5;
static final int TYPE_MEDIUM = 6;
static final int TYPE_NONE = 0;
// this fudge factor was found by trial and error
static final double mhmult = 12;
int dragX, dragY;
int selectedSource;
int forceBarValue;
boolean dragging;
boolean dragClear;
boolean dragSet;
double t;
int pause;
MemoryImageSource imageSource;
int pixels[];
int sourceCount = -1;
boolean sourcePlane = false;
int sourceFreqCount = -1;
int sourceWaveform = SWF_SIN;
int auxFunction;
int adjustSelectX1, adjustSelectY1, adjustSelectX2, adjustSelectY2;
static final int mediumMax = 191;
static final double mediumMaxIndex = .5;
static final int SWF_SIN = 0;
static final int SWF_PACKET = 1;
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_PACKET = 7;
static final int SRC_1S1F_PLANE = 8;
static final int SRC_2S1F_PLANE = 10;
static final int SRC_1S1F_PLANE_PACKET = 12;
int getrand(int x) {
int q = random.nextInt();
if (q < 0) q = -q;
return q % x;
}
EMWave2Canvas cv;
EMWave2 applet;
EMWave2Frame(EMWave2 a) {
super("TM Electrodynamics Applet v1.4b");
applet = a;
}
boolean useBufferedImage = false;
public void init() {
String jv = System.getProperty("java.class.version");
double jvf = new Double(jv).doubleValue();
if (jvf >= 48)
useBufferedImage = true;
setupList = new Vector();
Setup s = new SingleSourceSetup();
int i = 0;
while (s != null) {
setupList.addElement(s);
s = s.createNext();
if (i++ > 300) {
System.out.print("setup loop?\n");
return;
}
}
String os = System.getProperty("os.name");
sources = new OscSource[4];
setLayout(new EMWave2Layout());
cv = new EMWave2Canvas(this);
cv.addComponentListener(this);
cv.addMouseMotionListener(this);
cv.addMouseListener(this);
add(cv);
setupChooser = new Choice();
for (i = 0; i != setupList.size(); i++)
setupChooser.add("Setup: " +
((Setup) setupList.elementAt(i)).getName());
setup = (Setup) setupList.elementAt(0);
setupChooser.addItemListener(this);
add(setupChooser);
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 (Packet)");
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 (Packet)");
sourceChooser.select(SRC_1S1F);
sourceChooser.addItemListener(this);
add(sourceChooser);
modeChooser = new Choice();
modeChooser.add("Mouse = Add Perf. Conductor");
modeChooser.add("Mouse = Add Good Conductor");
modeChooser.add("Mouse = Add Fair Conductor");
modeChooser.add("Mouse = Add Current (+)");
modeChooser.add("Mouse = Add Current (-)");
modeChooser.add("Mouse = Add Ferromagnet");
modeChooser.add("Mouse = Add Diamagnet");
modeChooser.add("Mouse = Add Dielectric");
modeChooser.add("Mouse = Add Magnet (Down)");
modeChooser.add("Mouse = Add Magnet (Up)");
modeChooser.add("Mouse = Add Magnet (Left)");
modeChooser.add("Mouse = Add Magnet (Right)");
modeChooser.add("Mouse = Add Resonant Medium");
modeChooser.add("Mouse = Clear");
modeChooser.add("Mouse = Adjust Conductivity");
modeChooser.add("Mouse = Adjust Permeability");
modeChooser.add("Mouse = Adjust Current");
modeChooser.add("Mouse = Adjust Dielectric");
modeChooser.add("Mouse = Adjust Mag Dir");
modeChooser.add("Mouse = Adjust Mag Strength");
modeChooser.addItemListener(this);
add(modeChooser);
viewChooser = new Choice();
viewChooser.add("Show Electric Field (E)");
viewChooser.add("Show Magnetic Field (B)");
viewChooser.add("Show B Lines");
viewChooser.add("Show B Strength");
viewChooser.add("Show Current (j)");
viewChooser.add("Show E/B");
viewChooser.add("Show E/B lines");
viewChooser.add("Show E/B/j");
viewChooser.add("Show E/B lines/j");
viewChooser.add("Show Mag. Intensity (H)");
viewChooser.add("Show Magnetization (M)");
viewChooser.add("Show Material Type");
viewChooser.add("Show Vec. Potential");
viewChooser.add("Show Poynting Vector");
viewChooser.add("Show Energy Density");
viewChooser.add("Show Poynting/Energy");
viewChooser.add("Show Force");
viewChooser.add("Show Effective Current");
viewChooser.add("Show Magnetic Charge");
viewChooser.add("Show Curl E");
viewChooser.add("Show Bx");
viewChooser.add("Show By");
viewChooser.add("Show Hx");
viewChooser.add("Show Hy");
viewChooser.addItemListener(this);
add(viewChooser);
viewChooser.select(VIEW_E_B_J);
add(clearButton = new Button("Clear Fields"));
clearButton.addActionListener(this);
add(ClearAllButton = new Button("Clear All"));
ClearAllButton.addActionListener(this);
stoppedCheck = new Checkbox("Stopped");
stoppedCheck.addItemListener(this);
add(stoppedCheck);
add(new Label("Simulation Speed", Label.CENTER));
add(speedBar = new Scrollbar(Scrollbar.HORIZONTAL, 180, 1, 1, 2000));
speedBar.addAdjustmentListener(this);
add(new Label("Resolution", Label.CENTER));
add(resBar = new Scrollbar(Scrollbar.HORIZONTAL, 40, 5, 16, 140));
resBar.addAdjustmentListener(this);
setResolution();
add(new Label("Source Frequency", Label.CENTER));
add(forceBar = new Scrollbar(Scrollbar.HORIZONTAL,
forceBarValue = 10, 1, 1, 40));
forceBar.addAdjustmentListener(this);
add(new Label("Brightness", Label.CENTER));
add(brightnessBar = new Scrollbar(Scrollbar.HORIZONTAL,
10, 1, 1, 2000));
brightnessBar.addAdjustmentListener(this);
add(new Label("Line Density", Label.CENTER));
add(lineDensityBar = new Scrollbar(Scrollbar.HORIZONTAL,
50, 1, 10, 100));
lineDensityBar.addAdjustmentListener(this);
add(auxLabel = new Label("", Label.CENTER));
add(auxBar = new Scrollbar(Scrollbar.HORIZONTAL, 1, 1, 1, 40));
auxBar.addAdjustmentListener(this);
add(adjustLabel = new Label("", Label.CENTER));
add(adjustBar = new Scrollbar(Scrollbar.HORIZONTAL, 50, 1, 0, 102));
adjustBar.addAdjustmentListener(this);
add(new Label(""));
try {
String param = applet.getParameter("PAUSE");
if (param != null)
pause = Integer.parseInt(param);
} catch (Exception e) { }
random = new Random();
reinit();
setup = (Setup) setupList.elementAt(0);
cv.setBackground(Color.black);
cv.setForeground(Color.lightGray);
setModeChooser();
resize(660, 500);
handleResize();
Dimension x = getSize();
Dimension screen = getToolkit().getScreenSize();
setLocation((screen.width - x.width)/2,
(screen.height - x.height)/2);
show();
}
void reinit() {
sourceCount = -1;
adjustSelectX1 = -1;
grid = new OscElement[gridSizeXY];
int i;
for (i = 0; i != gridSizeXY; i++)
grid[i] = new OscElement();
doSetup();
}
void setDamping() {
int i, j;
for (i = 0; i != gridSizeXY; i++) {
grid[i].damp = 1;
// need this to avoid reflections in Dielectric setup
if (grid[i].medium > 0)
grid[i].damp = .99;
}
for (i = 0; i != windowOffsetX; i++)
for (j = 0; j != gridSizeX; j++) {
double da = Math.exp(-(windowOffsetX-i)*.002);
grid[i+j*gw].damp = grid[gridSizeX-1-i+gw*j].damp =
grid[j+i*gw].damp = grid[j+gw*(gridSizeY-1-i)].damp = da;
}
}
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) {
applet.destroyFrame();
return true;
}
return super.handleEvent(ev);
}
void doClear() {
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++) {
grid[x].az = grid[x].dazdt = 1e-10;
grid[x].epos = 0;
if (grid[x].resonant)
grid[x].jz = 0;
}
t = 0;
doFilter();
}
void doClearAll() {
int x, y;
for (x = 0; x < gridSizeXY; x++) {
OscElement oe = grid[x];
oe.jz = 0;
oe.az = oe.dazdt = 1e-10f;
oe.boundary = false;
oe.gray = false;
oe.resonant = false;
oe.conductivity = 0;
oe.perm = 1;
oe.medium = 0;
oe.mx = oe.my = 0;
oe.epos = 0;
}
setDamping();
sourceChooser.select(SRC_NONE);
setSources();
}
void calcBoundaries() {
int x, y;
int bound = 0;
// 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++) {
grid[x+gw*y].conductivity = grid[x+gw*windowOffsetY].conductivity;
grid[x+gw*(gridSizeY-y-1)].conductivity =
grid[x+gw*(gridSizeY-windowOffsetY-1)].conductivity;
}
for (y = 0; y < gridSizeY; y++)
for (x = 0; x < windowOffsetX; x++) {
grid[x+gw*y].conductivity = grid[windowOffsetX+gw*y].conductivity;
grid[gridSizeX-x-1+gw*y].conductivity =
grid[gridSizeX-windowOffsetX-1+gw*y].conductivity;
}
for (x = 1; x < gridSizeX-1; x++)
for (y = 1; y < gridSizeY-1; y++) {
int gi = x+gw*y;
OscElement oe = grid[gi];
double perm = oe.perm;
int medium = oe.medium;
double mx = oe.mx;
double my = oe.my;
OscElement e1 = grid[gi-1];
OscElement e2 = grid[gi+1];
OscElement e3 = grid[gi-gw];
OscElement e4 = grid[gi+gw];
oe.gray =
(oe.conductivity > 0 || oe.medium != 0 ||
oe.perm != 1 || oe.mx != 0 || oe.my != 0 ||
oe.resonant);
// mark all grid squares where the permeability, medium,
// or magnetization is different from one of the neighbors
if (e1.perm != perm || e2.perm != perm ||
e3.perm != perm || e4.perm != perm ||
e1.medium != medium || e2.medium != medium ||
e3.medium != medium || e4.medium != medium ||
e1.mx != mx || e2.mx != mx || e3.mx != mx || e4.mx != mx ||
e1.my != my || e2.my != my || e3.my != my || e4.my != my ||
oe.resonant) {
oe.boundary = true;
bound++;
} else
oe.boundary = false;
}
}
int getPanelHeight() { return winSize.height / 3; }
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;
public void updateEMWave2(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 the first time after
// a reboot.
handleResize();
return;
}
double tadd = 0;
if (!stoppedCheck.getState()) {
int val = 5;
tadd = val*.05;
}
int i, j;
boolean stopFunc = dragging;
if (stoppedCheck.getState())
stopFunc = true;
double speedValue = speedBar.getValue()/2.;
if (stopFunc)
lastTime = 0;
else {
if (lastTime == 0)
lastTime = System.currentTimeMillis();
if (speedValue*(System.currentTimeMillis()-lastTime) < 1000)
stopFunc = true;
}
if (!stopFunc) {
int iter;
int mxx = gridSizeX-1;
int mxy = gridSizeY-1;
for (iter = 1; ; iter++) {
doSources(tadd, false);
setup.doStep();
double sinhalfth = 0;
double sinth = 0;
double scaleo = 0;
double tadd2 = tadd;
double forcecoef = 1;
int curMedium = 0;
OscElement oew, oee, oen, oes, oe;
double previ, nexti, prevj, nextj, basis, a, b;
System.out.println("forcecoef " + forcecoef + " tadd2 " + (tadd*tadd));
for (j = 1; j != mxy; j++) {
int gi = j*gw+1;
int giEnd = gi+mxx-1;
oe = grid[gi-1];
oee = grid[gi];
for (; gi != giEnd; gi++) {
oew = oe;
oe = oee;
oee = grid[gi+1];
oen = grid[gi-gw];
oes = grid[gi+gw];
if (oe.conductivity > 0)
oe.jz = 0;
if (oe.boundary) {
// here we may be on the boundary between two
// media, so we have to do some extra work
if (oe.resonant) {
oe.jz = oe.jz*.999 +
-oe.dazdt * .001 - oe.epos * .02;
oe.epos += oe.jz * .2;
}
if (curMedium != oe.medium) {
curMedium = oe.medium;
forcecoef = (1-
(mediumMaxIndex/mediumMax)*curMedium);
forcecoef *= forcecoef;
}
double az = oe.az;
previ = (oew.az-az)/oew.perm;
nexti = (oee.az-az)/oee.perm;
prevj = (oen.az-az)/oen.perm;
nextj = (oes.az-az)/oes.perm;
basis = (nexti+previ+nextj+prevj)*.25;
// calculate effective current
double jz = oew.my - oee.my +
oes.mx - oen.mx + oe.jz;
a = oe.perm*basis + jz;
} else {
// easy way
previ = oew.az;
nexti = oee.az;
prevj = oen.az;
nextj = oes.az;
basis = (nexti+previ+nextj+prevj)*.25;
a = oe.jz - (oe.az - basis);
}
oe.dazdt = (oe.dazdt * oe.damp) + a * forcecoef;
}
}
tadd2 = tadd*tadd;
for (j = 1; j != mxy; j++) {
int gi = j*gw+1;
int giEnd = gi-1+mxx;
for (; gi != giEnd; gi++) {
oe = grid[gi];
if (oe.conductivity > 0) {
a = -oe.dazdt*oe.conductivity;
oe.jz = a;
oe.dazdt += a;
}
oe.az += oe.dazdt * tadd2;
}
}
t += tadd;
filterGrid();
long tm = System.currentTimeMillis();
if (tm-lastTime > 200 ||
iter*1000 >= speedValue*(tm-lastTime)) {
lastTime = tm;
break;
}
}
}
renderGrid();
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);
}
if (adjustSelectX1 != -1) {
int c = getrand(255);
int col = 0x010100 * c + 0xFF000000;
int lx1 = (int) (adjustSelectX1*winSize.width /windowWidth);
int ly1 = (int) (adjustSelectY1*winSize.height/windowHeight);
int lx2 = (int) ((adjustSelectX2+1)*winSize.width /windowWidth);
int ly2 = (int) ((adjustSelectY2+1)*winSize.height/windowHeight);
plotRect(lx1, ly1, lx2-1, ly2-1, col);
}
if (imageSource != null)
imageSource.newPixels();
realg.drawImage(dbimage, 0, 0, this);
if (!stoppedCheck.getState())
cv.repaint(pause);
}
void plotRect(int x1, int y1, int x2, int y2, int col) {
int i;
for (i = x1; i <= x2; i++) {
plotPixel(i, y1, col);
plotPixel(i, y2, col);
}
for (i = y1; i <= y2; i++) {
plotPixel(x1, i, col);
plotPixel(x2, i, col);
}
}
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 = (n == selectedSource) ? 0xFF00FFFF : 0xFFFFFFFF;
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 renderGrid() {
double mult = brightnessBar.getValue() / 50.0;
double emult = 1;
int ix = 0;
int i, j, k, l;
int viewScalar, viewVector, viewScalarCond, viewVectorCond;
int v = viewChooser.getSelectedIndex();
if (v == VIEW_FORCE)
calcForce();
boolean showLines = false;
viewScalar = viewScalarCond =
viewVector = viewVectorCond = VIEW_NONE;
switch (v) {
case VIEW_E:
case VIEW_A:
case VIEW_J:
case VIEW_BX:
case VIEW_BY:
case VIEW_HX:
case VIEW_HY:
case VIEW_EFF_CUR:
case VIEW_MAG_CHARGE:
case VIEW_TYPE:
case VIEW_B_STRENGTH:
case VIEW_ENERGY:
viewScalar = viewScalarCond = v;
break;
case VIEW_B:
case VIEW_POYNTING:
case VIEW_H:
case VIEW_M:
case VIEW_CURL_E:
viewVector = viewVectorCond = v;
break;
case VIEW_B_LINES:
showLines = true;
break;
case VIEW_FORCE:
viewScalar = viewScalarCond = VIEW_E;
viewVector = viewVectorCond = VIEW_FORCE;
break;
case VIEW_E_B:
viewScalar = viewScalarCond = VIEW_E;
viewVector = viewVectorCond = VIEW_B;
emult = .3;
break;
case VIEW_E_B_J:
viewScalar = VIEW_E;
viewScalarCond = VIEW_J;
viewVector = viewVectorCond = VIEW_B;
emult = .3;
break;
case VIEW_E_B_LINES:
viewScalar = viewScalarCond = VIEW_E;
showLines = true;
emult = .3;
break;
case VIEW_E_B_LINES_J:
viewScalar = VIEW_E;
viewScalarCond = VIEW_J;
showLines = true;
emult = .3;
break;
case VIEW_POYNTING_ENERGY:
viewScalar = viewScalarCond = VIEW_ENERGY;
viewVector = viewVectorCond = VIEW_POYNTING;
break;
}
for (j = 0; j != windowHeight; j++) {
ix = winSize.width*(j*winSize.height/windowHeight);
int gi = (j+windowOffsetY)*gw+windowOffsetX;
for (i = 0; i != windowWidth; i++, gi++) {
int x = i*winSize.width/windowWidth;
int y = j*winSize.height/windowHeight;
int x2 = (i+1)*winSize.width/windowWidth;
int y2 = (j+1)*winSize.height/windowHeight;
int i2 = i+windowOffsetX;
int j2 = j+windowOffsetY;
int vs = viewScalar;
int vv = viewVector;
int col_r = 0, col_g = 0, col_b = 0;
OscElement oe = grid[gi];
if (oe.gray || oe.jz != 0) {
col_r = col_g = col_b = 64;
if (oe.conductivity > 0 || (oe.jz != 0 && !oe.resonant)) {
vv = viewVectorCond;
vs = viewScalarCond;
}
}
if (vs != VIEW_NONE) {
double dy = 0;
switch (vs) {
case VIEW_E: dy = -oe.dazdt * emult; break;
case VIEW_A: dy = oe.az * .2; break;
case VIEW_J: dy = oe.jz; break;
case VIEW_BX:
dy = grid[gi-gw].az - grid[gi+gw].az;
break;
case VIEW_BY:
dy = -(grid[gi+1].az - grid[gi-1].az);
break;
case VIEW_HX:
dy = ((grid[gi-gw].az - grid[gi+gw].az)/oe.perm
- oe.mx*mhmult);
break;
case VIEW_HY:
dy = -((grid[gi+1].az - grid[gi-1].az)/oe.perm
- oe.my*mhmult);
break;
case VIEW_EFF_CUR:
dy = getMagY(gi-1) - getMagY(gi+1) +
getMagX(gi+gw) - getMagX(gi-gw);
break;
case VIEW_MAG_CHARGE:
dy = grid[gi-1].mx - grid[gi+1].mx +
grid[gi-gw].my - grid[gi+gw].my;
break;
case VIEW_B_STRENGTH:
{
double dx = grid[gi-gw].az - grid[gi+gw].az;
dy = grid[gi+1].az - grid[gi-1].az;
dy = Math.sqrt(dx*dx+dy*dy);
break;
}
case VIEW_ENERGY:
{
double n = 1/
(1-oe.medium*mediumMaxIndex/mediumMax);
double dielec = n*n;
double dx = grid[gi-gw].az - grid[gi+gw].az;
dy = grid[gi+1].az - grid[gi-1].az;
dy = .4*((dx*dx+dy*dy)/oe.perm +
oe.dazdt * oe.dazdt * dielec);
break;
}
}
dy *= mult;
if (dy < -1)
dy = -1;
if (dy > 1)
dy = 1;
if (vs == VIEW_TYPE) {
double dr = 0, dg = 0, db = 0;
if (oe.resonant) {
dr = 1;
dg = .75;
db = .5;
} else if (oe.perm < 1) {
dr = 1-oe.perm;
} else if (oe.perm > 1) {
dg = (oe.perm-1)/30;
} else if (oe.mx != 0 || oe.my != 0) {
dr = .53; dg = .27; db = .63;
} else if (oe.medium > 0) {
dr = oe.medium/(double) mediumMax;
dg = dr*.5;
} else if (oe.conductivity > 0) {
dg = db = oe.conductivity;
if (oe.conductivity == 1)
dr = 1;
} else if (oe.jz > 0) {
dr = dg = oe.jz*mult;
} else if (oe.jz < 0) {
db = -oe.jz*mult;
}
dr = clamp(dr);
dg = clamp(dg);
db = clamp(db);
col_r = col_r+(int) (dr*(255-col_r));
col_g = col_g+(int) (dg*(255-col_g));
col_b = col_b+(int) (db*(255-col_b));
} else if (vs == VIEW_J || vs == VIEW_EFF_CUR ||
vs == VIEW_ENERGY) {
if (dy < 0)
col_b = col_b+(int) (-dy*(255-col_b));
else {
col_r = col_r+(int) (dy*(255-col_r));
col_g = col_g+(int) (dy*(255-col_g));
}
} else {
if (dy < 0)
col_r = col_r+(int) (-dy*(255-col_r));
else
col_g = col_g+(int) (dy*(255-col_g));
}
}
int col = (255<<24) | (col_r<<16) | (col_g<<8) | col_b;
for (k = 0; k != x2-x; k++, ix++)
for (l = 0; l != y2-y; l++)
pixels[ix+l*winSize.width] = col;
oe.col = col;
if (vv != VIEW_NONE) {
double dx = 0, dy = 0;
switch (vv) {
case VIEW_B:
dx = grid[gi-gw].az - grid[gi+gw].az;
dy = grid[gi+1].az - grid[gi-1].az;
break;
case VIEW_H:
dx = (grid[gi-gw].az - grid[gi+gw].az)/oe.perm -
mhmult*oe.mx;
dy = (grid[gi+1].az - grid[gi-1].az)/oe.perm -
mhmult*oe.my;
break;
case VIEW_M:
{
double mm = 1-1/oe.perm;
dx = (grid[gi-gw].az - grid[gi+gw].az)*mm +
oe.mx;
dy = (grid[gi+1].az - grid[gi-1].az)*mm +
oe.my;
}
break;
case VIEW_POYNTING:
dy = 5*oe.dazdt *
(grid[gi-gw].az - grid[gi+gw].az)/oe.perm;
dx = -5*oe.dazdt *
(grid[gi+1].az - grid[gi-1].az)/oe.perm;
break;
case VIEW_FORCE:
dx = forceVecs[forceMap[i2][j2]][0];
dy = forceVecs[forceMap[i2][j2]][1];
break;
case VIEW_CURL_E:
dx = -5*(grid[gi-gw].dazdt - grid[gi+gw].dazdt);
dy = -5*(grid[gi+1].dazdt - grid[gi-1].dazdt);
break;
}
double dn = Math.sqrt(dx*dx+dy*dy);
if (dn > 0) {
dx /= dn;
dy /= dn;
}
dn *= mult;
if (dn > 1) {
if (dn > 2)
dn = 2;
dn -= 1;
col_g = 255;
col_r = col_r+(int) (dn*(255-col_r));
col_b = col_b+(int) (dn*(255-col_b));
} else
col_g = col_g+(int) (dn*(255-col_g));
col = (255<<24) | (col_r<<16) | (col_g<<8) | col_b;
int sw2 = (x2-x)/2;
int sh2 = (y2-y)/2;
int x1 = x+sw2-(int) (sw2*dx);
int y1 = y+sh2-(int) (sh2*dy);
x2 = x+sw2+(int) (sw2*dx);
y2 = y+sh2+(int) (sh2*dy);
drawLine(x1, y1, x2, y2, col);
int as = 3;
drawLine(x2, y2,
(int) ( dy*as-dx*as+x2),
(int) (-dx*as-dy*as+y2), col);
drawLine(x2, y2,
(int) (-dy*as-dx*as+x2),
(int) ( dx*as-dy*as+y2), col);
}
}
}
if (showLines) {
renderLines();
lineDensityBar.enable();
} else {
lineDensityBar.disable();
}
}
void drawLine(int x1, int y1, int x2, int y2, int col) {
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x2 < 0) x2 = 0;
if (y2 < 0) y2 = 0;
if (x1 >= winSize.width-1) x1 = winSize.width-1;
if (y1 >= winSize.height-1) y1 = winSize.height-1;
if (x2 >= winSize.width-1) x2 = winSize.width-1;
if (y2 >= winSize.height-1) y2 = winSize.height-1;
int dx = abs(x2-x1);
int dy = abs(y2-y1);
if (dx > dy) {
if (x1 > x2) {
int q;
q = x1; x1 = x2; x2 = q;
q = y1; y1 = y2; y2 = q;
}
int x;
for (x = x1; x <= x2; x++)
pixels[x+(y1+(y2-y1)*(x-x1)/dx)*winSize.width] = col;
} else if (dy > 0) {
if (y1 > y2) {
int q;
q = x1; x1 = x2; x2 = q;
q = y1; y1 = y2; y2 = q;
}
int y;
for (y = y1; y <= y2; y++)
pixels[x1+(x2-x1)*(y-y1)/dy+y*winSize.width] = col;
}
}
double getMagX(int gi) {
OscElement oe = grid[gi];
double mm = 1-1/oe.perm;
return (grid[gi-gw].az - grid[gi+gw].az)*mm + oe.mx;
}
double getMagY(int gi) {
OscElement oe = grid[gi];
double mm = 1-1/oe.perm;
return (grid[gi+1].az - grid[gi-1].az)*mm + oe.my;
}
double clamp(double x) {
return (x < 0) ? 0 : (x > 1) ? 1 : x;
}
void doSources(double tadd, boolean clear) {
int i, j;
if (sourceCount == 0)
return;
double w = forceBar.getValue()*(t-forceTimeZero)*freqMult;
double w2 = w;
switch (auxFunction) {
case AUX_FREQ:
w2 = auxBar.getValue()*t*freqMult;
break;
case AUX_PHASE:
{
// scrollbars don't always go all the way to the end,
// so we do some extra work to make sure we can set
// the phase all the way from 0 to pi
int au = auxBar.getValue()-1;
if (au > 38)
au = 38;
w2 = w+au*(pi/38);
break;
}
}
double v = 0;
double v2 = 0;
switch (sourceWaveform) {
case SWF_SIN:
v = Math.sin(w);
if (sourceCount >= 2)
v2 = Math.sin(w2);
else if (sourceFreqCount == 2)
v = (v+Math.sin(w2))*.5;
break;
case SWF_PACKET:
{
w %= pi*2;
double adjw = w/(freqMult*forceBar.getValue());
adjw -= 10;
v = Math.exp(-.01*adjw*adjw)*
Math.sin(adjw*.2);
if (adjw < 0)
doFilter();
}
break;
}
if (clear)
v = v2 = 0;
sources[0].v = sources[2].v = (float) (2*v*sourceMult);
sources[1].v = sources[3].v = (float) (2*v2*sourceMult);
if (sourcePlane) {
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*.1);
}
} else {
for (i = 0; i != sourceCount; i++) {
OscSource src = sources[i];
OscElement oe = grid[src.x+gw*src.y];
oe.jz = src.v;
}
}
}
int abs(int x) {
return x < 0 ? -x : x;
}
void drawPlaneSource(int x1, int y1, int x2, int y2, double v) {
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;
}
// need to draw a line from x1,y1 to x2,y2
if (x1 == x2 && y1 == y2) {
grid[x1+gw*y1].jz = v;
} 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
int sgn = sign(y2-y1);
int x, y;
for (y = y1; y != y2+sgn; y += sgn) {
x = x1+(x2-x1)*(y-y1)/(y2-y1);
grid[x+gw*y].jz = v;
}
} else {
// x difference is greater, so we step along x's
// from min to max x and calculate y for each step
int sgn = sign(x2-x1);
int x, y;
for (x = x1; x != x2+sgn; x += sgn) {
y = y1+(y2-y1)*(x-x1)/(x2-x1);
grid[x+gw*y].jz = v;
}
}
}
int sign(int x) {
return (x < 0) ? -1 : (x == 0) ? 0 : 1;
}
byte linegrid[];
// render electric field lines
void renderLines() {
double x = 0, y = 0;
int lineGridSize = lineDensityBar.getValue();
int lineGridSize2 = lineGridSize*lineGridSize;
if (linegrid == null)
linegrid = new byte[lineGridSize2];
double lspacing = lineGridSize/(double) windowWidth;
double startx = -1, starty = 0;
int linemax = 0;
double mult = brightnessBar.getValue() / 50.0;
boolean doArrow = false;
int dir = 1;
double olddn = -1;
int oldcol = -1;
int gridsearchx = 0, gridsearchy = 0;
int i, j;
for (i = 0; i != lineGridSize2; i++)
linegrid[i] = 0;
int oldcgx = -1, oldcgy = -1;
while (true) {
if (linemax-- == 0 || x == 0) {
if (dir == 1) {
int gi = gridsearchx+lineGridSize*gridsearchy;
while (true) {
if (linegrid[gi] == 0)
break;
if (++gridsearchx == lineGridSize) {
if (++gridsearchy == lineGridSize)
break;
gridsearchx = 0;
}
gi++;
}
if (gridsearchx == lineGridSize && gridsearchy == lineGridSize)
break;
startx = gridsearchx/lspacing;
starty = gridsearchy/lspacing;
}
x = startx+.48/lspacing;
y = starty+.48/lspacing;
linemax = 40; // was 100
dir = -dir;
oldcgx = oldcgy = -1;
}
if (x < 0 || y < 0 || x >= windowWidth || y >= windowHeight) {
x = 0;
continue;
}
int cgx = (int) (x*lspacing);
int cgy = (int) (y*lspacing);
doArrow = true;
if (cgx != oldcgx || cgy != oldcgy) {
int lg = ++linegrid[cgx+lineGridSize*cgy];
if (lg > 2) {
x = 0;
continue;
}
oldcgx = cgx;
oldcgy = cgy;
} else
doArrow = false;
int xi = windowOffsetX+(int) x;
int yi = windowOffsetY+(int) y;
int gi = xi+gw*yi;
OscElement oe = grid[gi];
double dx = grid[gi-gw].az - grid[gi+gw].az;
double dy = grid[gi+1].az - grid[gi-1].az;
double dn = Math.sqrt(dx*dx+dy*dy);
if (dn == 0) {
x = 0;
continue;
}
dx /= dn;
dy /= dn;
double oldx = x;
double oldy = y;
x += .5*dx*dir;
y += .5*dy*dir;
dn *= mult;
int col = grid[gi].col;
if (dn != olddn || col != oldcol) {
int col_r = (col>>16) & 255;
int col_g = (col>> 8) & 255;
int col_b = col & 255;
if (dn > 1) {
if (dn > 2)
dn = 2;
dn -= 1;
col_g = 255;
col_r = col_r+(int) (dn*(255-col_r));
col_b = col_b+(int) (dn*(255-col_b));
} else
col_g = col_g+(int) (dn*(255-col_g));
col = (255<<24) | (col_r<<16) | (col_g<<8) | col_b;
olddn = dn;
oldcol = col;
}
int lx1 = (int) (oldx*winSize.width /windowWidth);
int ly1 = (int) (oldy*winSize.height/windowHeight);
int lx2 = (int) (x*winSize.width /windowWidth);
int ly2 = (int) (y*winSize.height/windowHeight);
drawLine(lx1, ly1, lx2, ly2, col);
if (doArrow && linegrid[cgx+lineGridSize*cgy] == 1) {
if ((cgx & 3) == 0 && (cgy & 3) == 0) {
int as = 5;
drawLine(lx2, ly2,
(int) ( dy*as-dx*as+lx2),
(int) (-dx*as-dy*as+ly2), col);
drawLine(lx2, ly2,
(int) (-dy*as-dx*as+lx2),
(int) ( dx*as-dy*as+ly2), col);
}
}
}
}
byte forceMap[][];
double forceVecs[][];
void calcForce() {
int x, y;
forceMap = new byte[gridSizeX][gridSizeY];
forceVecs = new double[256][2];
byte magno = 1;
for (x = windowOffsetX; x != windowWidth+windowOffsetX; x++)
for (y = windowOffsetY; y != windowHeight+windowOffsetY; y++) {
if (forceMap[x][y] != 0 || !grid[x+gw*y].feelsForce())
continue;
forceVecs[magno][0] = forceVecs[magno][1] = 0;
forceSearch(x, y, magno++);
}
}
void forceSearch(int x, int y, byte magno) {
if (forceMap[x][y] != 0)
return;
if (x < windowOffsetX ||
y < windowOffsetY ||
x >= windowOffsetX+windowWidth ||
y >= windowOffsetY+windowHeight)
return;
int gi = x+y*gw;
double mc = getMagX(gi-1) - getMagX(gi+1) +
getMagY(gi-gw) - getMagY(gi+gw);
double bx = grid[gi-gw].az - grid[gi+gw].az;
double by = grid[gi+1].az - grid[gi-1].az;
forceVecs[magno][0] += mc*bx + grid[gi].jz*by;
forceVecs[magno][1] += mc*by - grid[gi].jz*bx;
if (grid[gi].feelsForce()) {
forceMap[x][y] = magno;
forceSearch(x-1, y, magno);
forceSearch(x+1, y, magno);
forceSearch(x, y-1, magno);
forceSearch(x, y+1, magno);
}
}
int filterCount = 0;
// filter out high-frequency noise
void filterGrid() {
if ((filterCount++ & 3) != 0)
return;
if (filterCount > 200)
return;
// filter less aggressively if there is a source on the screen,
// to avoid damping the waves
double mult1 = (forceBar.getValue() > 7 &&
sourceCount > 0 &&
sourceWaveform == SWF_SIN) ? 40 : 8;
double mult2 = 4+mult1;
int x, y;
for (y = 1; y < gridSizeY-1; y++)
for (x = 1; x < gridSizeX-1; x++) {
int gi = x+y*gw;
OscElement oe = grid[gi];
if (oe.jz != 0 || oe.conductivity > 0)
continue;
if (oe.perm != grid[gi-1].perm ||
oe.perm != grid[gi+1].perm ||
oe.perm != grid[gi-gw].perm ||
oe.perm != grid[gi+gw].perm)
continue;
double jz = grid[gi-1].my - grid[gi+1].my +
grid[gi+gw].mx - grid[gi-gw].mx;
if (jz != 0)
continue;
oe.az = (oe.az*mult1 + grid[gi-1].az + grid[gi+1].az +
grid[gi-gw].az + grid[gi+gw].az)/mult2;
}
}
void noFilter() {
filterCount = 200;
}
void doFilter() {
filterCount %= 4;
}
void edit(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (selectedSource != -1) {
doSources(1, true);
x = x*windowWidth/winSize.width;
y = y*windowHeight/winSize.height;
OscSource s = sources[selectedSource];
if (x >= 0 && y >= 0 && x < windowWidth && y < windowHeight) {
int ox = s.x;
int oy = s.y;
s.x = x+windowOffsetX;
s.y = y+windowOffsetY;
cv.repaint(pause);
}
return;
}
if (modeChooser.getSelectedIndex() >= MODE_ADJUST) {
int xp = x*windowWidth/winSize.width;
int yp = y*windowHeight/winSize.height;
if (adjustSelectX1 == -1) {
adjustSelectX1 = adjustSelectX2 = xp;
adjustSelectY1 = adjustSelectY2 = yp;
adjustBar.enable();
return;
}
adjustSelectX1 = max(0, min(xp, adjustSelectX1));
adjustSelectX2 = min(windowWidth-1, max(xp, adjustSelectX2));
adjustSelectY1 = max(0, min(yp, adjustSelectY1));
adjustSelectY2 = min(windowHeight-1, max(yp, adjustSelectY2));
adjustBar.enable();
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);
}
}
}
calcBoundaries();
cv.repaint(pause);
}
int min(int a, int b) { return (a < b) ? a : b; }
int max(int a, int b) { return (a > b) ? a : b; }
void editFuncPoint(int x, int y) {
int xp = x*windowWidth/winSize.width;
int yp = y*windowHeight/winSize.height;
if (xp < 0 || xp >= windowWidth ||
yp < 0 || yp >= windowHeight)
return;
xp += windowOffsetX;
yp += windowOffsetY;
OscElement oe = grid[xp+gw*yp];
doFilter();
if (!dragSet && !dragClear) {
dragClear = oe.conductivity != 0 || oe.medium != 0 ||
oe.mx != 0 || oe.my != 0 || oe.perm != 1 ||
oe.jz != 0 || oe.resonant;
dragSet = !dragClear;
}
oe.conductivity = 0;
oe.medium = 0;
oe.mx = oe.my = 0;
oe.perm = 1;
oe.jz = 0;
oe.resonant = false;
if (dragClear)
return;
switch (modeChooser.getSelectedIndex()) {
case MODE_J_POS: oe.jz = 1; break;
case MODE_J_NEG: oe.jz = -1; break;
case MODE_FERROMAG: addPerm(xp, yp, 5); break;
case MODE_DIAMAG: addPerm(xp, yp, .5); break;
case MODE_MEDIUM: oe.medium = mediumMax; break;
case MODE_M_DOWN: oe.my = 1; break;
case MODE_M_UP: oe.my = -1; break;
case MODE_M_LEFT: oe.mx = -1; break;
case MODE_M_RIGHT: oe.mx = 1; break;
case MODE_PERF_CONDUCTOR: addConductor(xp, yp, 1); break;
case MODE_GOOD_CONDUCTOR: addConductor(xp, yp, .9); break;
case MODE_FAIR_CONDUCTOR: addConductor(xp, yp, .5); break;
case MODE_RESONANT: oe.resonant = true; break;
}
}
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;
}
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() == clearButton) {
doClear();
cv.repaint();
}
if (e.getSource() == ClearAllButton) {
doClearAll();
cv.repaint();
}
}
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.print(((Scrollbar) e.getSource()).getValue() + "\n");
if (e.getSource() == resBar) {
setResolution();
reinit();
cv.repaint(pause);
}
if (e.getSource() == brightnessBar)
cv.repaint(pause);
if (e.getSource() == lineDensityBar) {
cv.repaint(pause);
linegrid = null;
}
if (e.getSource() == forceBar)
setForce();
if (e.getSource() == adjustBar)
doAdjust();
}
void setForceBar(int x) {
forceBar.setValue(x);
forceBarValue = x;
forceTimeZero = 0;
}
void setForce() {
// adjust time zero to maintain continuity in the force func
// even though the frequency has changed.
double oldfreq = forceBarValue * freqMult;
forceBarValue = forceBar.getValue();
double newfreq = forceBarValue * freqMult;
double adj = newfreq-oldfreq;
forceTimeZero = t-oldfreq*(t-forceTimeZero)/newfreq;
}
void setResolution() {
windowWidth = windowHeight = resBar.getValue();
windowOffsetX = windowOffsetY = 20;
gridSizeX = windowWidth + windowOffsetX*2;
gridSizeY = windowHeight + windowOffsetY*2;
gridSizeXY = gridSizeX*gridSizeY;
gw = gridSizeX;
System.out.println("gridsize " + gridSizeX + " window " + windowWidth);
linegrid = null;
}
void setResolution(int x) {
resBar.setValue(x);
setResolution();
reinit();
}
void doAdjust() {
if (adjustSelectX1 == -1)
return;
int vali = adjustBar.getValue();
if (vali < 1)
vali = 1;
if (vali > 99)
vali = 100;
if (modeChooser.getSelectedIndex() == MODE_ADJ_PERM && vali < 3)
vali = 3;
float val = vali/100.f;
int x, y;
for (y = adjustSelectY1; y <= adjustSelectY2; y++)
for (x = adjustSelectX1; x <= adjustSelectX2; x++) {
OscElement oe = grid[x+windowOffsetX+gw*(y+windowOffsetY)];
switch (modeChooser.getSelectedIndex()) {
case MODE_ADJ_CONDUCT:
if (oe.getType() == TYPE_CONDUCTOR)
oe.conductivity = val;
break;
case MODE_ADJ_PERM:
if (oe.getType() == TYPE_FERROMAGNET)
oe.perm = vali/2.f;
break;
case MODE_ADJ_J:
if (oe.getType() == TYPE_CURRENT)
oe.jz = (oe.jz < 0) ? -val : val;
break;
case MODE_ADJ_MEDIUM:
if (oe.getType() == TYPE_MEDIUM)
oe.medium = (int) (val*mediumMax);
break;
case MODE_ADJ_MAG_DIR:
if (oe.getType() == TYPE_MAGNET) {
double m =
Math.sqrt(oe.mx*oe.mx+oe.my*oe.my);
oe.mx = (float) (Math.cos(val*2*pi)*m);
oe.my = (float) -(Math.sin(val*2*pi)*m);
}
break;
case MODE_ADJ_MAG_STR:
if (oe.getType() == TYPE_MAGNET) {
float mult = (float) (val/Math.
sqrt(oe.mx*oe.mx+oe.my*oe.my));
oe.mx *= mult;
oe.my *= mult;
}
break;
}
}
calcBoundaries();
}
public void mouseDragged(MouseEvent e) {
if (!dragging)
selectSource(e);
dragging = true;
edit(e);
}
public void mouseMoved(MouseEvent e) {
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0)
return;
int x = e.getX();
int y = e.getY();
dragX = x; dragY = y;
selectSource(e);
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
selectedSource = -1;
cv.repaint();
}
public void mousePressed(MouseEvent e) {
if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) == 0)
return;
adjustSelectX1 = -1;
adjustBar.disable();
int x = e.getX();
int y = e.getY();
dragX = x; dragY = y;
if (!dragging)
selectSource(e);
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) {
cv.repaint(pause);
if (e.getItemSelectable() == stoppedCheck)
return;
if (e.getItemSelectable() == sourceChooser) {
setSources();
doFilter();
}
if (e.getItemSelectable() == setupChooser)
doSetup();
if (e.getItemSelectable() == modeChooser)
setModeChooser();
}
void setModeChooser() {
if (modeChooser.getSelectedIndex() < MODE_ADJUST) {
adjustLabel.hide();
adjustBar.hide();
validate();
adjustSelectX1 = -1;
return;
}
switch (modeChooser.getSelectedIndex()) {
case MODE_ADJ_CONDUCT: adjustLabel.setText("Conductivity"); break;
case MODE_ADJ_PERM: adjustLabel.setText("Permeability"); break;
case MODE_ADJ_J: adjustLabel.setText("Current"); break;
case MODE_ADJ_MEDIUM: adjustLabel.setText("Dielectric Constant"); break;
case MODE_ADJ_MAG_DIR: adjustLabel.setText("Direction"); break;
case MODE_ADJ_MAG_STR: adjustLabel.setText("Strength"); break;
}
adjustLabel.show();
adjustBar.show();
if (adjustSelectX1 == -1)
adjustBar.disable();
else
adjustBar.enable();
validate();
}
void doSetup() {
t = 0;
doClearAll();
// don't use previous source positions, use defaults
sourceCount = -1;
filterCount = 0;
sourceChooser.select(SRC_1S1F);
setForceBar(10);
brightnessBar.setValue(100);
auxBar.setValue(1);
setup = (Setup)
setupList.elementAt(setupChooser.getSelectedIndex());
setup.select();
setup.doSetupSources();
calcBoundaries();
setDamping();
}
void addMedium() {
int i, j;
for (i = 0; i != gridSizeX; i++)
for (j = gridSizeY/2; j != gridSizeY; j++)
grid[i+gw*j].medium = mediumMax;
}
void addCondMedium(double cv) {
conductFillRect(0, gridSizeY/2, gridSizeX-1, gridSizeY-1, cv);
}
void addResMedium() {
int i, j;
for (i = 0; i != gridSizeX; i++)
for (j = gridSizeY/2; j != gridSizeY; j++)
grid[i+gw*j].resonant = true;
}
void addUniformField() {
float v = 2f/windowHeight;
int y;
for (y = 0; y != gridSizeY; y++) {
grid[windowOffsetX+gw*y].jz = v;
grid[windowOffsetX+windowWidth-1+gw*y].jz = -v;
}
}
void addSolenoid(int x1, int y1, int x2, int y2, double v) {
int i;
for (i = y1; i <= y2; i++) {
grid[x1+gw*i].jz = v;
grid[x2+gw*i].jz = -v;
}
}
void addMagnet(int x1, int y1, int x2, int y2, double v) {
int i, j;
for (i = y1; i <= y2; i++)
for (j = x1; j <= x2; j++)
grid[j+gw*i].my = (float) v;
}
void addMagnet(int x1, int y1, int x2, int y2, double vx, double vy) {
int i, j;
for (i = y1; i <= y2; i++)
for (j = x1; j <= x2; j++) {
grid[j+gw*i].mx = (float) vx;
grid[j+gw*i].my = (float) vy;
}
}
void setSources() {
if (sourceCount > 0)
doSources(1, true);
sourceMult = 1;
int oldSCount = sourceCount;
boolean oldPlane = sourcePlane;
sourceFreqCount = 1;
sourcePlane = (sourceChooser.getSelectedIndex() >= SRC_1S1F_PLANE);
sourceWaveform = SWF_SIN;
sourceCount = 1;
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_PACKET; break;
case 9: sourceFreqCount = 2; break;
case 10: sourceCount = 2; break;
case 11: sourceCount = sourceFreqCount = 2; break;
case 12: sourceWaveform = SWF_PACKET; break;
}
if (sourceFreqCount >= 2) {
auxFunction = AUX_FREQ;
auxBar.setValue(forceBar.getValue());
if (sourceCount == 2)
auxLabel.setText("Source 2 Frequency");
else
auxLabel.setText("2nd Frequency");
} else if (sourceCount == 2 || sourceCount == 4) {
auxFunction = AUX_PHASE;
auxBar.setValue(1);
auxLabel.setText("Phase Difference");
} 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);
sources[1] = new OscSource(x2, windowOffsetY);
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);
}
}
class OscSource {
int x;
int y;
double 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;
}
};
class OscElement {
// permeability of this square (1 = vacuum)
float perm;
// conductivity (0, vacuum, 1 = perfect)
float conductivity;
// permanent magnetization
float mx, my;
// current
double jz;
// electron position (for resonance)
float epos;
// damping (used to keep waves from reflecting back after going
// off the screen)
double damp;
// z component of vector potential and its first derivative
double az, dazdt;
// dielectric strength (0 = none, up to mediumMax)
int medium;
// temp variable used to store color when drawing field lines
int col;
// true if we are on a boundary between media
boolean boundary;
// true if this is a gray square (some medium)
boolean gray;
// true if this is a resonant medium
boolean resonant;
int getType() {
if (perm < 1)
return TYPE_DIAMAGNET;
else if (perm > 1)
return TYPE_FERROMAGNET;
else if (mx != 0 || my != 0)
return TYPE_MAGNET;
else if (medium > 0)
return TYPE_MEDIUM;
else if (conductivity > 0)
return TYPE_CONDUCTOR;
else if (jz != 0)
return TYPE_CURRENT;
return TYPE_NONE;
}
boolean feelsForce() {
int t = getType();
return (t != TYPE_NONE && t != TYPE_MEDIUM);
}
};
abstract class Setup {
abstract String getName();
void select() {}
void deselect() {}
void valueChanged(Scrollbar s) {}
void doStep() {}
void doSetupSources() { setSources(); }
abstract Setup createNext();
Setup() { }
};
class SingleSourceSetup extends Setup {
String getName() { return "Single Source"; }
void select() {
setForceBar(30);
}
Setup createNext() { return new DoubleSourceSetup(); }
}
class DoubleSourceSetup extends Setup {
String getName() { return "Two Sources"; }
void select() {
setForceBar(30);
}
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 PlaneWaveSetup(); }
}
class PlaneWaveSetup extends Setup {
String getName() { return "Plane Wave"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
brightnessBar.setValue(225);
setForceBar(30);
}
Setup createNext() { return new IntersectingPlaneWavesSetup(); }
}
class IntersectingPlaneWavesSetup extends Setup {
String getName() { return "Intersecting Planes"; }
void select() {
brightnessBar.setValue(70);
setForceBar(34);
}
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 SingleWireSetup(); }
}
class SingleWireSetup extends Setup {
String getName() { return "Single Wire"; }
void select() {
sourceChooser.select(SRC_NONE);
grid[gridSizeX/2+gw*(gridSizeY/2)].jz = 1;
brightnessBar.setValue(200);
}
Setup createNext() { return new DoubleWireSetup(); }
}
class DoubleWireSetup extends Setup {
String getName() { return "Wire Pair"; }
void select() {
sourceChooser.select(SRC_NONE);
grid[gridSizeX/2+gw*(gridSizeY/2-3)].jz = 1;
grid[gridSizeX/2+gw*(gridSizeY/2+3)].jz = 1;
brightnessBar.setValue(200);
}
Setup createNext() { return new DipoleWireSetup(); }
}
class DipoleWireSetup extends Setup {
String getName() { return "Dipole Wire Pair"; }
void select() {
sourceChooser.select(SRC_NONE);
grid[gridSizeX/2+gw*(gridSizeY/2-3)].jz = 1;
grid[gridSizeX/2+gw*(gridSizeY/2+3)].jz = -1;
brightnessBar.setValue(200);
}
Setup createNext() { return new MagnetPairSetup(); }
}
class MagnetPairSetup extends Setup {
String getName() { return "Magnet Pair"; }
void select() {
sourceChooser.select(SRC_NONE);
addMagnet(gridSizeX/2-windowWidth/4-3, gridSizeY/2-2,
gridSizeX/2-windowWidth/4+3, gridSizeY/2+2, -.2);
addMagnet(gridSizeX/2+windowWidth/4-3, gridSizeY/2-2,
gridSizeX/2+windowWidth/4+3, gridSizeY/2+2, -.2);
}
Setup createNext() { return new MagnetPairOppSetup(); }
}
class MagnetPairOppSetup extends Setup {
String getName() { return "Magnet Pair, Opp"; }
void select() {
sourceChooser.select(SRC_NONE);
addMagnet(gridSizeX/2-windowWidth/4-3, gridSizeY/2-2,
gridSizeX/2-windowWidth/4+3, gridSizeY/2+2, -.2);
addMagnet(gridSizeX/2+windowWidth/4-3, gridSizeY/2-2,
gridSizeX/2+windowWidth/4+3, gridSizeY/2+2, .2);
}
Setup createNext() { return new MagnetPairStackedSetup(); }
}
class MagnetPairStackedSetup extends Setup {
String getName() { return "Magnet Pair Stacked"; }
void select() {
sourceChooser.select(SRC_NONE);
addMagnet(gridSizeX/2-3, gridSizeY/2-10,
gridSizeX/2+3, gridSizeY/2-5, -.2);
addMagnet(gridSizeX/2-3, gridSizeY/2+5,
gridSizeX/2+3, gridSizeY/2+10, -.2);
}
Setup createNext() { return new MagnetPairStackedOppSetup(); }
}
class MagnetPairStackedOppSetup extends Setup {
String getName() { return "Magnet Pair Stacked Opp"; }
void select() {
sourceChooser.select(SRC_NONE);
addMagnet(gridSizeX/2-3, gridSizeY/2-10,
gridSizeX/2+3, gridSizeY/2- 5, .2);
addMagnet(gridSizeX/2-3, gridSizeY/2+ 5,
gridSizeX/2+3, gridSizeY/2+10, -.2);
}
Setup createNext() { return new UniformFieldSetup(); }
}
class UniformFieldSetup extends Setup {
String getName() { return "Uniform Field"; }
void select() {
sourceChooser.select(SRC_NONE);
addUniformField();
brightnessBar.setValue(225);
}
Setup createNext() { return new ApertureFieldSetup(); }
}
class ApertureFieldSetup extends Setup {
String getName() { return "Field Near Aperture"; }
void select() {
sourceChooser.select(SRC_NONE);
float v = 2f/windowHeight;
int y;
for (y = 0; y != gridSizeY; y++)
grid[windowOffsetX+gw*y].jz = v;
int r1 = gridSizeX/2-windowWidth/6;
int r2 = gridSizeX/2+windowWidth/6;
conductDrawRect(r1, windowOffsetY,
r1, windowOffsetY+windowHeight-1, 1);
conductDrawRect(r1, gridSizeY/2-6,
r1, gridSizeY/2+6, 0);
brightnessBar.setValue(740);
}
Setup createNext() { return new SolenoidSetup(); }
}
class SolenoidSetup extends Setup {
String getName() { return "Solenoid"; }
void select() {
sourceChooser.select(SRC_NONE);
int h = windowHeight/3;
double v = 2./h;
int cy = gridSizeY/2;
addSolenoid(gridSizeX/2-3, cy-h, gridSizeX/2+3, cy+h, v);
}
Setup createNext() { return new ToroidalSolenoidSetup(); }
}
class ToroidalSolenoidSetup extends Setup {
String getName() { return "Toroidal Solenoid"; }
void select() {
sourceChooser.select(SRC_NONE);
addWireCircle(gridSizeX/2, gridSizeY/2, windowHeight/3,
-30/360., 0, 360);
addWireCircle(gridSizeX/2, gridSizeY/2, windowHeight/6,
30/360., 0, 360);
brightnessBar.setValue(400);
}
Setup createNext() { return new CylinderSetup(); }
}
class CylinderSetup extends Setup {
String getName() { return "Sphere"; }
void select() {
sourceChooser.select(SRC_NONE);
int res = 4;
int cx = gridSizeX/2 * res;
int cy = gridSizeY/2 * res;
int r = windowHeight/5 * res;
double my = -1./(r*r);
int x, y;
for (x = -r; x <= r; x++) {
int yd = (int) Math.sqrt(r*r-x*x);
for (y = -yd; y <= yd; y++)
grid[( x+cx)/res+gw*((y+cy)/res)].my += my;
}
brightnessBar.setValue(450);
}
Setup createNext() { return new ThickWireSetup(); }
}
class ThickWireSetup extends Setup {
String getName() { return "Thick Wire"; }
void select() {
int r = windowWidth/4;
addThickWire(gridSizeX/2, gridSizeY/2, r, 1./(r*r));
sourceChooser.select(SRC_NONE);
}
Setup createNext() { return new HoleInWire1Setup(); }
}
class HoleInWire1Setup extends Setup {
String getName() { return "Hole In Wire 1"; }
void select() {
int r = windowWidth/3;
double j = 1./(r*r);
// avoid rounding error
j = ((int) (j*1024))/1024.;
if (j == 0)
j = 1/1024.;
addThickWire(gridSizeX/2, gridSizeY/2, r, j);
addThickWire(gridSizeX/2, gridSizeY/2, r*2/3, -j);
sourceChooser.select(SRC_NONE);
brightnessBar.setValue(450);
}
Setup createNext() { return new HoleInWire2Setup(); }
}
class HoleInWire2Setup extends Setup {
String getName() { return "Hole In Wire 2"; }
void select() {
int r = windowWidth/3;
double j = 1./(r*r);
// avoid rounding error
j = ((int) (j*1024))/1024.;
if (j == 0)
j = 1/1024.;
addThickWire(gridSizeX/2, gridSizeY/2, r, j);
addThickWire(gridSizeX/2+r/4, gridSizeY/2, r/2, -j);
sourceChooser.select(SRC_NONE);
brightnessBar.setValue(450);
}
Setup createNext() { return new FerromagnetSetup(); }
}
class FerromagnetSetup extends Setup {
String getName() { return "Ferromagnet"; }
void select() {
sourceChooser.select(SRC_NONE);
addSolenoid(gridSizeX/2-2, gridSizeY/2-2,
gridSizeX/2+2, gridSizeY/2+2, .4);
int x1 = windowOffsetX+3;
int x2 = windowOffsetX+windowWidth-4;
permFillRect(x1, gridSizeY/2+4,
x2, gridSizeY/2+8, 5);
brightnessBar.setValue(200);
}
Setup createNext() { return new DiamagnetSetup(); }
}
class DiamagnetSetup extends Setup {
String getName() { return "Diamagnet"; }
void select() {
sourceChooser.select(SRC_NONE);
addSolenoid(gridSizeX/2-2, gridSizeY/2-2,
gridSizeX/2+2, gridSizeY/2+2, .4);
int x1 = windowOffsetX+3;
int x2 = windowOffsetX+windowWidth-4;
permFillRect(x1, gridSizeY/2+4,
x2, gridSizeY/2+8, .5);
brightnessBar.setValue(200);
}
Setup createNext() { return new MeissnerEffectSetup(); }
}
class MeissnerEffectSetup extends Setup {
String getName() { return "Meissner Effect"; }
void select() {
sourceChooser.select(SRC_NONE);
addSolenoid(gridSizeX/2-2, gridSizeY/2-2,
gridSizeX/2+2, gridSizeY/2+2, .4);
int x1 = windowOffsetX+3;
int x2 = windowOffsetX+windowWidth-4;
conductFillRect(x1, gridSizeY/2+4,
x2, gridSizeY/2+8, 1);
brightnessBar.setValue(200);
}
Setup createNext() { return new HorseshoeSetup(); }
}
class HorseshoeSetup extends Setup {
String getName() { return "Horseshoe Magnet"; }
void select() {
sourceChooser.select(SRC_NONE);
int r1 = windowHeight/3;
int r2 = windowHeight/6;
addWireCircle(gridSizeX/2, gridSizeY/2, r1, -30/360., 0, 180);
addWireCircle(gridSizeX/2, gridSizeY/2, r2, 30/360., 0, 180);
int y;
for (y = 0; y != r2; y++) {
int x;
for (x = -r1; x <= r1; x++)
grid[gridSizeX/2+x+gw*(gridSizeY/2+y)].jz =
grid[gridSizeX/2+x+gw*(gridSizeY/2+y-1)].jz;
}
brightnessBar.setValue(400);
}
Setup createNext() { return new Horseshoe2Setup(); }
}
class Horseshoe2Setup extends HorseshoeSetup {
String getName() { return "Horseshoe + Load"; }
void select() {
super.select();
int r1 = windowHeight/3;
int r2 = windowHeight/6;
permFillRect(gridSizeX/2-r1-3, gridSizeY/2+r2,
gridSizeX/2+r1+3, gridSizeY/2+r2*2, 5);
brightnessBar.setValue(225);
}
Setup createNext() { return new MagneticShielding1Setup(); }
}
class MagneticShielding1Setup extends Setup {
String getName() { return "Magnetic Shielding 1"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
addSolenoid(gridSizeX/2-2, gridSizeY/2-2,
gridSizeX/2+2, gridSizeY/2+2, .4);
int x1 = windowOffsetX+3;
int x2 = windowOffsetX+windowWidth-4;
permDrawRect(x1, gridSizeY/2+4,
x2, gridSizeY/2+5, 10);
}
Setup createNext() { return new MagneticShielding2Setup(); }
}
class MagneticShielding2Setup extends Setup {
String getName() { return "Magnetic Shielding 2"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
addSolenoid(gridSizeX/2-2, gridSizeY/2-2,
gridSizeX/2+2, gridSizeY/2+2, .4);
for (i = 6; i <= 8; i++)
permDrawRect(gridSizeX/2-i, gridSizeY/2-i,
gridSizeX/2+i, gridSizeY/2+i, 10);
}
Setup createNext() { return new MagneticShielding3Setup(); }
}
class MagneticShielding3Setup extends Setup {
String getName() { return "Magnetic Shielding 3"; }
void select() {
sourceChooser.select(SRC_NONE);
int cx = gridSizeX/2;
int cy = gridSizeY/2;
addSolenoid(cx-1, cy-1, cx+1, cy+1, 4);
int th;
brightnessBar.setValue(340);
for (th = 0; th != 360; th += 3) {
double r1 = 4.9;
int x = cx+(int) (Math.cos(th*pi/180)*r1);
int y = cy-(int) (Math.sin(th*pi/180)*r1);
addPerm(x, y, 5);
double r2 = 5.9;
x = cx+(int) (Math.cos(th*pi/180)*r2);
y = cy-(int) (Math.sin(th*pi/180)*r2);
addPerm(x, y, 5);
}
}
Setup createNext() { return new MagneticShielding4Setup(); }
}
class MagneticShielding4Setup extends Setup {
String getName() { return "Magnetic Shielding 4"; }
void select() {
sourceChooser.select(SRC_NONE);
int i;
for (i = 6; i <= 8; i++)
permDrawRect(gridSizeX/2-i, gridSizeY/2-i,
gridSizeX/2+i, gridSizeY/2+i, 10);
addUniformField();
brightnessBar.setValue(250);
}
Setup createNext() { return new MagneticCircuit1Setup(); }
}
class MagneticCircuit1Setup extends Setup {
String getName() { return "Magnetic Circuit 1"; }
void select() {
sourceChooser.select(SRC_NONE);
int i;
for (i = 6; i <= 9; i++) {
permDrawRect(gridSizeX/2-i, gridSizeY/2-i,
gridSizeX/2+i, gridSizeY/2+i, 10);
}
addSolenoid(gridSizeX/2+5, gridSizeY/2-1,
gridSizeX/2+10, gridSizeY/2+1, .2);
}
Setup createNext() { return new MagneticCircuit2Setup(); }
}
class MagneticCircuit2Setup extends MagneticCircuit1Setup {
String getName() { return "Magnetic Circuit 2"; }
void select() {
super.select();
permFillRect(gridSizeX/2-9, gridSizeY/2-1,
gridSizeX/2-6, gridSizeY/2+1, 1);
}
Setup createNext() { return new MonopoleAttemptSetup(); }
}
class MonopoleAttemptSetup extends Setup {
String getName() { return "Monopole Attempt"; }
void select() {
sourceChooser.select(SRC_NONE);
int w = windowWidth/5;
int i;
int cx = gridSizeX/2;
int cy = gridSizeY/2;
int j;
for (j = 0; j != 3; j++) {
for (i = -w+1; i < w; i++) {
grid[cx-w+gw*(cy+i)].mx = -1;
grid[cx+w+gw*(cy+i)].mx = 1;
grid[cx+i+gw*(cy-w)].my = -1;
grid[cx+i+gw*(cy+w)].my = 1;
}
w++;
}
}
Setup createNext() { return new QuadrupoleLensSetup(); }
}
class QuadrupoleLensSetup extends Setup {
String getName() { return "Quadrupole Lens"; }
void select() {
sourceChooser.select(SRC_NONE);
int x;
int w = gridSizeX/2-1;
int h = windowWidth/4;
int cx = gridSizeX/2;
int cy = gridSizeY/2;
float str = 1/(float) h;
for (x = -w; x <= w; x++) {
int yd = (int) Math.sqrt(x*x+h*h);
int y;
for (y = yd; y <= w; y++) {
grid[cx+x+gw*(cy+y)].my = -str;
grid[cx+x+gw*(cy-y)].my = str;
grid[cx+y+gw*(cy+x)].mx = str;
grid[cx-y+gw*(cy+x)].mx = -str;
}
}
}
Setup createNext() { return new HalbachArraySetup(); }
}
class HalbachArraySetup extends Setup {
String getName() { return "Halbach Array"; }
void select() {
brightnessBar.setValue(80);
sourceChooser.select(SRC_NONE);
int sz = 5;
int y1 = gridSizeY/2-sz/2;
int y2 = gridSizeY/2+sz/2;
int fx = gridSizeX/2 -sz/2 -2*sz;
int s1 = sz-1;
addMagnet(fx, y1, fx+s1, y2, -.2, 0); fx += sz;
addMagnet(fx, y1, fx+s1, y2, 0, -.2); fx += sz;
addMagnet(fx, y1, fx+s1, y2, .2, 0); fx += sz;
addMagnet(fx, y1, fx+s1, y2, 0, .2); fx += sz;
addMagnet(fx, y1, fx+s1, y2, -.2, 0); fx += sz;
}
Setup createNext() { return new HalbachArray2Setup(); }
}
class HalbachArray2Setup extends Setup {
String getName() { return "Halbach Array (long)"; }
void select() {
brightnessBar.setValue(80);
sourceChooser.select(SRC_NONE);
int sz = 3;
int y1 = gridSizeY/2-1;
int y2 = gridSizeY/2+1;
int fx = windowOffsetX + (windowWidth-windowWidth/sz*sz)/2;
int s1 = sz-1;
int i;
double dx = -.2; double dy = 0;
for (i = 0; i != windowWidth/sz; i++) {
addMagnet(fx, y1, fx+s1, y2, dx, dy);
fx += sz;
double dq = dx; dx = -dy; dy = dq;
}
}
Setup createNext() { return new HalbachArray3Setup(); }
}
class HalbachArray3Setup extends Setup {
String getName() { return "Halbach Array (dipole)"; }
void select() {
brightnessBar.setValue(47);
sourceChooser.select(SRC_NONE);
int i;
int r2 = windowWidth/3;
int r1 = r2/2;
int x, y;
for (x = -r2; x <= r2; x++)
for (y = -r2; y <= r2; y++) {
double r = Math.sqrt(x*x+y*y);
if (r > r2+.9 || r < r1)
continue;
double a = Math.atan2(y, x)*180/pi + 22.5 + 45;
if (a < 0)
a += 360;
int ai = (int) (a/45);
float dq = ((ai & 2) == 0) ? .2f : -.2f;
float dx = 0, dy = 0;
if ((ai & 1) == 0)
dx = dq;
else
dy = dq;
grid[gridSizeX/2+x+gw*(gridSizeY/2+y)].mx = dx;
grid[gridSizeX/2+x+gw*(gridSizeY/2+y)].my = dy;
}
}
Setup createNext() { return new HalbachArray4Setup(); }
}
class HalbachArray4Setup extends Setup {
String getName() { return "Halbach Array (quadrupole)"; }
void select() {
brightnessBar.setValue(255);
sourceChooser.select(SRC_NONE);
int i;
int r2 = windowWidth/3;
int r1 = r2*2/3;
int x, y;
for (x = -r2; x <= r2; x++)
for (y = -r2; y <= r2; y++) {
double r = Math.sqrt(x*x+y*y);
if (r > r2+.9 || r < r1)
continue;
double a = Math.atan2(y, x)*180/pi + 11.25;
if (a < 0)
a += 360;
int ai = (int) (a/22.5);
double da = -pi/2 + (pi*3/2)*ai/4.;
float dx = (float) Math.cos(da);
float dy = (float) Math.sin(da);
float d0 = -.06f;
grid[gridSizeX/2+x+gw*(gridSizeY/2+y)].mx = dx*d0;
grid[gridSizeX/2+x+gw*(gridSizeY/2+y)].my = dy*d0;
}
}
Setup createNext() { return new DielectricSetup(); }
}
class DielectricSetup extends Setup {
String getName() { return "Dielectric"; }
void select() {
sourceChooser.select(SRC_1S1F_PACKET);
addMedium();
setForceBar(4);
brightnessBar.setValue(1000);
noFilter();
}
Setup createNext() { return new ConductReflectSetup(); }
}
class ConductReflectSetup extends Setup {
String getName() { return "Fair Conductor Reflection"; }
void select() {
sourceChooser.select(SRC_1S1F_PACKET);
addCondMedium(.5);
setForceBar(4);
brightnessBar.setValue(800);
}
Setup createNext() { return new Conduct2ReflectSetup(); }
}
class Conduct2ReflectSetup extends Setup {
String getName() { return "Poor Conductor Reflection"; }
void select() {
sourceChooser.select(SRC_1S1F_PACKET);
addCondMedium(.1);
setForceBar(4);
brightnessBar.setValue(800);
}
Setup createNext() { return new SkinEffect1Setup(); }
}
class SkinEffect1Setup extends Setup {
String getName() { return "Skin Effect 1"; }
void select() {
sourceChooser.select(SRC_1S1F);
addCondMedium(.33);
setForceBar(6);
brightnessBar.setValue(800);
}
Setup createNext() { return new SkinEffect2Setup(); }
}
class SkinEffect2Setup extends Setup {
String getName() { return "Skin Effect 2"; }
void select() {
sourceChooser.select(SRC_1S1F);
addCondMedium(.33);
setForceBar(40);
brightnessBar.setValue(800);
}
Setup createNext() { return new ResonantAbsSetup(); }
}
class ResonantAbsSetup extends Setup {
String getName() { return "Resonant Absorption"; }
void select() {
addResMedium();
setForceBar(23);
brightnessBar.setValue(200);
noFilter();
}
Setup createNext() { return new Dispersion1Setup(); }
}
class Dispersion1Setup extends ResonantAbsSetup {
String getName() { return "Dispersion 1"; }
void select() {
super.select();
setForceBar(14);
}
Setup createNext() { return new Dispersion2Setup(); }
}
class Dispersion2Setup extends ResonantAbsSetup {
String getName() { return "Dispersion 2"; }
void select() {
super.select();
setForceBar(21);
}
Setup createNext() { return new Dispersion3Setup(); }
}
class Dispersion3Setup extends ResonantAbsSetup {
String getName() { return "Dispersion 3"; }
void select() {
super.select();
setForceBar(25);
}
Setup createNext() { return new Dispersion4Setup(); }
}
class Dispersion4Setup extends ResonantAbsSetup {
String getName() { return "Dispersion 4"; }
void select() {
super.select();
setForceBar(39);
}
Setup createNext() { return new DiffusionSetup(); }
}
class DiffusionSetup extends Setup {
String getName() { return "Magnetic Diffusion"; }
void select() {
sourceChooser.select(SRC_NONE);
conductFillRect(1, 1, gridSizeX-2, gridSizeY-2, .2);
addConductor(gridSizeX/2, gridSizeY/2, 0);
grid[gridSizeX/2+gw*(gridSizeY/2)].jz = 1;
brightnessBar.setValue(800);
}
Setup createNext() { return new OscRingSetup(); }
}
class OscRingSetup extends Setup {
String getName() { return "Oscillating Ring"; }
void doSetupSources() {
sourceChooser.select(SRC_2S1F);
setSources();
sources[0].y = sources[1].y = gridSizeY/2;
sources[0].x = gridSizeX/2 - 4;
sources[1].x = gridSizeX/2 + 4;
auxBar.setValue(40);
}
void select() {
setForceBar(26);
brightnessBar.setValue(86);
}
Setup createNext() { return new OscRingPairSetup(); }
}
class OscRingPairSetup extends Setup {
String getName() { return "Oscillating Ring Pair"; }
void doSetupSources() {
sourceChooser.select(SRC_4S1F);
setSources();
sources[0].y = sources[1].y = gridSizeY/2-2;
sources[2].y = sources[3].y = gridSizeY/2+2;
sources[0].x = sources[3].x = gridSizeX/2 - 2;
sources[1].x = sources[2].x = gridSizeX/2 + 2;
auxBar.setValue(40);
}
void select() {
setForceBar(26);
brightnessBar.setValue(86);
}
Setup createNext() { return new OscRingInductionSetup(); }
}
class OscRingInductionSetup extends Setup {
String getName() { return "Ring Induction"; }
void doSetupSources() {
sourceChooser.select(SRC_2S1F);
setSources();
sources[0].y = sources[1].y = gridSizeY/2-2;
sources[0].x = gridSizeX/2 - 4;
sources[1].x = gridSizeX/2 + 4;
auxBar.setValue(40);
}
void select() {
setForceBar(12);
brightnessBar.setValue(140);
addConductor(gridSizeX/2-4, gridSizeY/2+2, .5);
addConductor(gridSizeX/2+4, gridSizeY/2+2, .5);
}
Setup createNext() { return new WireInductionSetup(); }
}
class WireInductionSetup extends Setup {
String getName() { return "Wire Induction"; }
void doSetupSources() {
setForceBar(12);
sourceChooser.select(SRC_1S1F);
setSources();
sources[0].y = gridSizeY/2-2;
sources[0].x = gridSizeX/2;
}
void select() {
brightnessBar.setValue(140);
addConductor(gridSizeX/2, gridSizeY/2+2, .5);
}
Setup createNext() { return new OscRingEddy1Setup(); }
}
class OscRingEddy1Setup extends OscRingSetup {
String getName() { return "Ring + Fair Conductor"; }
void select() {
brightnessBar.setValue(280);
setForceBar(3);
conductFillRect(0, gridSizeY/2+3,
gridSizeX-1, gridSizeY/2+5, .5);
}
Setup createNext() { return new OscRingEddy2Setup(); }
}
class OscRingEddy2Setup extends OscRingSetup {
String getName() { return "Ring + Poor Conductor"; }
void select() {
brightnessBar.setValue(280);
setForceBar(3);
conductFillRect(0, gridSizeY/2+3,
gridSizeX-1, gridSizeY/2+5, .1);
}
Setup createNext() { return new WireEddy1Setup(); }
}
class WireEddy1Setup extends Setup {
String getName() { return "Wire + Fair Conductor"; }
void doSetupSources() {
setForceBar(3);
sourceChooser.select(SRC_1S1F);
setSources();
sources[0].y = gridSizeY/2;
sources[0].x = gridSizeX/2;
}
void select() {
brightnessBar.setValue(280);
conductFillRect(0, gridSizeY/2+3,
gridSizeX-1, gridSizeY/2+5, .5);
}
Setup createNext() { return new WireEddy2Setup(); }
}
class WireEddy2Setup extends WireEddy1Setup {
String getName() { return "Wire + Poor Conductor"; }
void select() {
brightnessBar.setValue(280);
conductFillRect(0, gridSizeY/2+3,
gridSizeX-1, gridSizeY/2+5, .1);
}
Setup createNext() { return new OscRingPermSetup(); }
}
class OscRingPermSetup extends Setup {
String getName() { return "Rings + Ferromagnet"; }
void doSetupSources() {
sourceChooser.select(SRC_2S1F);
setSources();
sources[0].y = sources[1].y = gridSizeY/2;
sources[0].x = gridSizeX/2 - 4;
sources[1].x = gridSizeX/2 + 4;
auxBar.setValue(40);
}
void select() {
setForceBar(6);
brightnessBar.setValue(94);
addConductor(gridSizeX/2-4, gridSizeY/2+10, .5);
addConductor(gridSizeX/2+4, gridSizeY/2+10, .5);
addConductor(gridSizeX/2-4, gridSizeY/2-10, .5);
addConductor(gridSizeX/2+4, gridSizeY/2-10, .5);
permFillRect(gridSizeX/2-2, gridSizeY/2-1,
gridSizeX/2+2, windowOffsetY+windowHeight-1, 50);
conductFillRect(gridSizeX/2-2, gridSizeY/2-1,
gridSizeX/2+2, windowOffsetY+windowHeight-1, .05);
}
Setup createNext() { return new SolenoidOscSetup(); }
}
class SolenoidOscSetup extends Setup {
String getName() { return "Osc. Solenoid"; }
void select() {
sourceChooser.select(SRC_2S1F_PLANE);
setSources();
int h = windowHeight/3;
int cy = gridSizeY/2;
sources[0].x = sources[1].x = gridSizeX/2-3;
sources[2].x = sources[3].x = gridSizeX/2+3;
sources[0].y = sources[2].y = cy-h;
sources[1].y = sources[3].y = cy+h;
auxBar.setValue(40);
setForceBar(9);
}
void doSetupSources() {}
Setup createNext() { return new TransformerSetup(); }
}
class TransformerSetup extends SolenoidOscSetup {
String getName() { return "Transformer"; }
void select() {
super.select();
int h = windowHeight/3;
int cy = gridSizeY/2;
conductDrawRect(gridSizeX/2-5, cy-h, gridSizeX/2-5, cy+h, .9);
conductDrawRect(gridSizeX/2+5, cy-h, gridSizeX/2+5, cy+h, .9);
brightnessBar.setValue(340);
}
Setup createNext() { return new ToroidalSolenoidOscSetup(); }
}
class ToroidalSolenoidOscSetup extends Setup {
String getName() { return "Osc Toroidal Solenoid"; }
void select() {
setSources();
sources[0].x = windowOffsetX;
sources[0].y = windowOffsetY;
sourceChooser.select(SRC_NONE);
brightnessBar.setValue(300);
setForceBar(8);
}
void doSetupSources() {}
void doStep() {
double val = grid[windowOffsetX+gw*windowOffsetY].jz * 30;
int i, j;
for (i = 0; i != windowWidth; i++)
for (j = 0; j != windowHeight; j++)
grid[i+windowOffsetX+gw*(j+windowOffsetY)].jz = 0;
addWireCircle(gridSizeX/2, gridSizeY/2, windowHeight/3,
-val/360., 0, 360);
addWireCircle(gridSizeX/2, gridSizeY/2, windowHeight/6,
val/360., 0, 360);
}
Setup createNext() { return new CoaxCableSetup(); }
}
class CoaxCableSetup extends Setup {
String getName() { return "Coaxial Cable"; }
void select() {
setSources();
sources[0].x = windowOffsetX;
sources[0].y = windowOffsetY;
brightnessBar.setValue(300);
setForceBar(8);
}
void doSetupSources() {}
void doStep() {
double val = grid[windowOffsetX+gw*windowOffsetY].jz * 30;
int i, j;
for (i = 0; i != windowWidth; i++)
for (j = 0; j != windowHeight; j++)
grid[i+windowOffsetX+gw*(j+windowOffsetY)].jz = 0;
int sz = 3;
addWireCircle(gridSizeX/2, gridSizeY/2, sz, -val/360., 0, 360);
grid[gridSizeX/2+gw*(gridSizeY/2)].jz = val/16;
}
Setup createNext() { return new CondInOscFieldSetup(); }
}
class CondInOscFieldSetup extends Setup {
String getName() { return "Cond. in Osc. Field"; }
void doSetupSources() {}
void select() {
sourceChooser.select(SRC_2S1F_PLANE);
setSources();
int h = windowHeight/3;
int cy = gridSizeY/2;
sources[0].x = sources[1].x = windowOffsetX;
sources[2].x = sources[3].x = windowOffsetX+windowWidth-1;
sources[0].y = sources[2].y = 0;
sources[1].y = sources[3].y = gridSizeY-1;
conductFillRect(gridSizeX/2-4, gridSizeY/2-4,
gridSizeX/2+4, gridSizeY/2+4, .4);
setForceBar(2);
auxBar.setValue(40);
}
Setup createNext() { return new MovingWireSetup(); }
}
class MovingWireSetup extends Setup {
String getName() { return "Moving Wire"; }
double y;
int dir, delay;
void select() {
sourceChooser.select(SRC_NONE);
y = windowOffsetY;
dir = 1;
delay = 0;
stopDelay = 200;
brightnessBar.setValue(200);
}
int stopDelay;
void doStep() {
if (delay > 0) {
delay--;
filt();
return;
}
int yi = (int) y;
int i;
for (i = 0; i != 2; i++) {
int gi = gridSizeX/2+i+gw*yi;
grid[gi].jz = 0;
grid[gi+gw].jz = 0;
grid[gi+gw+gw].jz = 0;
}
y += dir*.06;
int yi2 = (int) y;
if (yi != yi2) {
if (yi2 == gridSizeY/2)
delay = stopDelay;
if (yi2 == windowOffsetY ||
yi2 == windowOffsetY+windowHeight-3) {
dir = -dir;
delay = stopDelay;
}
}
yi = yi2;
float yfrac = (float) (y-yi);
for (i = 0; i != 2; i++) {
int gi = gridSizeX/2+i+gw*yi;
grid[gi].jz = (1-yfrac)*.25;
grid[gi+gw].jz = .25;
grid[gi+gw+gw].jz = yfrac*.25;
}
filt();
calcBoundaries();
}
int filtstep = 0;
void filt() {
// do filtering around the moving wire
int xi = gridSizeX/2;
int yi = (int) y;
int x, y;
int r = 10;
for (y = yi-r; y <= yi+r; y++)
for (x = xi-r; x <= xi+r; x++) {
int gi = x+y*gw;
OscElement oe = grid[gi];
if (oe.jz != 0 || oe.conductivity > 0)
continue;
double rr = Math.sqrt((y-yi)*(y-yi)+
(x-xi)*(x-xi));
double mult1 = 8+rr;
double mult2 = 4+mult1;
oe.az = (oe.az*mult1 + grid[gi-1].az + grid[gi+1].az +
grid[gi-gw].az + grid[gi+gw].az)/mult2;
}
}
Setup createNext() { return new MovingWireTubeSetup(); }
}
class MovingWireTubeSetup extends MovingWireSetup {
String getName() { return "Moving Wire in Tube"; }
void select() {
super.select();
int w = 4;
conductFillRect(gridSizeX/2-w, windowOffsetY,
gridSizeX/2-w, windowOffsetY+windowHeight, .6);
w++;
conductFillRect(gridSizeX/2+w, windowOffsetY,
gridSizeX/2+w, windowOffsetY+windowHeight, .6);
stopDelay = 500;
brightnessBar.setValue(500);
}
Setup createNext() { return new MovingMagnetSetup(); }
}
class MovingMagnetSetup extends Setup {
String getName() { return "Moving Magnet in Tube"; }
double y;
int dir, delay;
void select() {
sourceChooser.select(SRC_NONE);
int w = 5;
conductFillRect(gridSizeX/2-w, windowOffsetY,
gridSizeX/2-w, windowOffsetY+windowHeight, .6);
conductFillRect(gridSizeX/2+w, windowOffsetY,
gridSizeX/2+w, windowOffsetY+windowHeight, .6);
y = windowOffsetY;
dir = 1;
delay = 0;
brightnessBar.setValue(250);
}
void doStep() {
if (delay > 0) {
delay--;
filt();
return;
}
int yi = (int) y;
int x, i;
for (x = -3; x <= 3; x++) {
for (i = 0; i <= 2; i++)
grid[gridSizeX/2+x+gw*(yi+i)].my = 0;
}
y += dir*.06;
int yi2 = (int) y;
if (yi != yi2) {
if (yi2 == gridSizeY/2)
delay = 500;
if (yi2 == windowOffsetY ||
yi2 == windowOffsetY+windowHeight-3) {
dir = -dir;
delay = 500;
}
}
yi = yi2;
float yfrac = (float) (y-yi);
for (x = -3; x <= 3; x++) {
int gi = gridSizeX/2 + x + gw*yi;
grid[gi].my = -(1-yfrac);
grid[gi+gw].my = -1;
grid[gi+gw+gw].my = -yfrac;
}
calcBoundaries();
/*for (x = -4; x <= 4; x++)
for (i = -1; i <= 3; i++)
grid[gridSizeX/2+x][yi+i].boundary = true;*/
filt();
}
int filtstep = 0;
void filt() {
// run a filter around the moving wire
int xi = gridSizeX/2;
int yi = (int) y;
int x, y;
int r = 12;
double mult1 = 8;
double mult2 = 4+mult1;
for (y = yi-r; y <= yi+r; y++)
for (x = xi-r; x <= xi+r; x++) {
int gi = x+gw*y;
OscElement oe = grid[gi];
if (oe.jz != 0 || oe.conductivity > 0)
continue;
double jz = grid[gi-1].my - grid[gi+1].my +
grid[gi+gw].mx - grid[gi-gw].mx;
if (jz != 0)
continue;
oe.az = (oe.az*mult1 + grid[gi-1].az + grid[gi+1].az +
grid[gi-gw].az + grid[gi+gw].az)/mult2;
}
}
Setup createNext() { return new RotatingMagnet1Setup(); }
}
class RotatingMagnet1Setup extends Setup {
String getName() { return "Rotating Magnet 1"; }
double mt;
void select() {
sourceChooser.select(SRC_NONE);
grid[gridSizeX/2+gw*(gridSizeY/2)].mx = 1;
calcBoundaries();
setForceBar(10);
mt = 0;
brightnessBar.setValue(500);
}
void doStep() {
mt += forceBar.getValue() * .003;
grid[gridSizeX/2+gw*(gridSizeY/2)].mx =
(float) Math.cos(mt);
grid[gridSizeX/2+gw*(gridSizeY/2)].my =
(float) -Math.sin(mt);
doFilter();
}
Setup createNext() { return new RotatingMagnet2Setup(); }
}
class RotatingMagnet2Setup extends RotatingMagnet1Setup {
String getName() { return "Rotating Magnet 2"; }
void doStep() {
mt += forceBar.getValue() * .003;
grid[gridSizeX/2+gw*(gridSizeY/2)].mx =
(float) Math.cos(mt);
grid[gridSizeX/2+gw*(gridSizeY/2)].my =
(float) -Math.abs(Math.sin(mt));
doFilter();
brightnessBar.setValue(500);
}
Setup createNext() { return new Scattering1Setup(); }
}
class Scattering1Setup extends Setup {
String getName() { return "Scattering 1"; }
int ctr;
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
brightnessBar.setValue(100);
setForceBar(23);
int i, j;
for (i = gridSizeX/2-1; i <= gridSizeX/2+1; i++)
for (j = gridSizeY/2-1; j <= gridSizeY/2+1; j++)
grid[i+gw*j].resonant = true;
}
void doStep() {
ctr++;
if (ctr >= 600 && ctr <= 700) {
double c = (ctr-600)*.01;
sourceMult = 1-c;
} else if (ctr >= 1100) {
double c = (ctr-1100)*.01;
sourceMult = c;
if (ctr == 1200)
ctr = 0;
}
}
Setup createNext() { return new Scattering2Setup(); }
}
class Scattering2Setup extends Scattering1Setup {
String getName() { return "Scattering 2"; }
int ctr;
void select() {
super.select();
setForceBar(16);
}
Setup createNext() { return new BigModeSetup(); }
}
class BigModeSetup extends Setup {
String getName() { return "Big TM11 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 = 1; i != 4; i++)
conductDrawRect(x-i, y-i, x+n+i-1, y+n+i-1, 1);
setupMode(x, y, n, n, 1, 1);
brightnessBar.setValue(200);
}
Setup createNext() { return new OneByOneModesSetup(); }
}
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++) {
grid[i+x+gw*(j+y)].az = 2*
(Math.sin(pi*nx*(i+1)/(sx+1))*
Math.sin(pi*ny*(j+1)/(sy+1)));
grid[i+x+gw*(j+y)].dazdt = 0;
}
noFilter();
}
class OneByOneModesSetup extends Setup {
String getName() { return "TM11 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;
conductDrawRect(x1-1, y1-1, x1+nx, y1+ny, 1);
setupMode(x1, y1, nx, ny, 1, 1);
y += ny+2;
}
}
Setup createNext() { return new OneByNModesSetup(); }
}
class OneByNModesSetup extends Setup {
String getName() { return "TMn1 Modes"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 8;
int nx = windowWidth-2;
int mode = 1;
while (y + ny < windowHeight) {
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
conductDrawRect(x1-1, y1-1, x1+nx, y1+ny, 1);
setupMode(x1, y1, nx, ny, mode, 1);
y += ny+2;
mode++;
}
}
Setup createNext() { return new NByNModesSetup(); }
}
class NByNModesSetup extends Setup {
String getName() { return "TMnn 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+2)*(modey-1);
int y1 = windowOffsetY + 1 + (nx+2)*(modex-1);
conductDrawRect(x1-1, y1-1, x1+nx, y1+ny, 1);
setupMode(x1, y1, nx, ny, modex, modey);
}
}
Setup createNext() { return new OneByNModeCombosSetup(); }
}
class OneByNModeCombosSetup extends Setup {
String getName() { return "TMn1 Mode Combos"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int ny = 8;
int nx = windowWidth-2;
while (y + ny < windowHeight) {
int mode1 = getrand(8)+1;
int mode2;
do
mode2 = getrand(8)+1;
while (mode1 == mode2);
int y1 = y + windowOffsetY;
int x1 = windowOffsetX + 1;
conductDrawRect(x1-1, y1-1, x1+nx, y1+ny, 1);
for (i = 0; i != nx; i++)
for (j = 0; j != ny; j++) {
grid[i+x1+gw*(j+y1)].az = (float) 2*
(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);
grid[i+x1+gw*(j+y1)].dazdt = 0;
}
y += ny+2;
}
noFilter();
}
Setup createNext() { return new NByNModeCombosSetup(); }
}
class NByNModeCombosSetup extends Setup {
String getName() { return "TMnn Mode Combos"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
int y = 1;
int maxmode = 2;
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+2)*(gx-1);
int y1 = windowOffsetY + 1 + (nx+2)*(gy-1);
conductDrawRect(x1-1, y1-1, x1+nx, y1+ny, 1);
for (i = 0; i != nx; i++)
for (j = 0; j != ny; j++) {
grid[i+x1+gw*(j+y1)].az = 2*
(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);
grid[i+x1+gw*(j+y1)].dazdt = 0;
}
}
noFilter();
}
Setup createNext() { return new TriangleModesSetup(); }
}
class TriangleModesSetup extends Setup {
String getName() { return "Triangle Modes"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
for (i = 0; i != 2; i++)
for (j = 0; j != 2; j++) {
int x = windowOffsetX+windowWidth*i/2+1;
int y = windowOffsetY+windowHeight*j/2+1;
int w = windowWidth/2-2;
int h = windowHeight/2-2;
int k;
for (k = 0; k != w; k++)
conductDrawRect(x+k+1, y+k, x+w, y+k, 1);
conductDrawRect(x-1, y-1, x+w, y+h, 1);
int mx = 0, my = 0;
switch (j*2+i) {
case 0: mx = 1; my = 2; break;
case 1: mx = 1; my = 3; break;
case 2: mx = 2; my = 3; break;
case 3: mx = 1; my = 4; break;
}
int xi, yi;
for (yi = 0; yi != h; yi++) {
for (xi = 0; xi <= yi; xi++)
grid[x+xi+gw*(y+yi)].az =
(Math.sin(mx*pi*(xi+1)/(w+2))*
Math.sin(my*pi*(yi+2)/(h+2)) -
Math.sin(my*pi*(xi+1)/(w+2))*
Math.sin(mx*pi*(yi+2)/(h+2)));
grid[x+xi+gw*(y+yi)].dazdt = 0;
}
}
brightnessBar.setValue(114);
noFilter();
}
Setup createNext() { return new CircleModes1Setup(); }
}
class CircleModes1Setup extends Setup {
String getName() { return "Circular Modes 1"; }
void select() {
sourceChooser.select(SRC_NONE);
int i, j;
for (i = 0; i != 2; i++)
for (j = 0; j != 2; j++) {
int x = windowOffsetX+windowWidth*i/2+1;
int y = windowOffsetY+windowHeight*j/2;
int w = windowWidth/2-2;
int h = windowHeight/2-2;
conductFillRect(x-1, y-1, x+w+1, y+h+1, 1);
int k, r = w/2;
double jj[] = new double[3];
double omega = zeroj(i, j+1)/r;
double mult = 1;
switch (j*2+i) {
case 1: mult = 1/.6; break;
case 2: mult = 2; break;
case 3: mult = 5/.6; break;
}
for (k = -r; k <= r; k++) {
int yy = (int) Math.sqrt(r*r-k*k-.00001);
conductFillRect(x+r+k, y+r-yy, x+r+k, y+r+yy, 0);
int l;
for (l = -yy; l <= yy; l++) {
double rr = Math.sqrt(k*k+l*l);
double r0 = rr*omega;
double angfunc = (i == 0) ? 1 : l/rr;
if (rr == 0)
angfunc = (i == 0) ? 1 : 0;
bess(i, r0, jj);
grid[x+r+k+gw*(y+r+l)].az = jj[i+1]*angfunc*mult;
}
}
}
brightnessBar.setValue(200);
}
Setup createNext() { return new CircleModes2Setup(); }
}
class CircleModes2Setup extends Setup {
String getName() { return "Circular Modes 2"; }
void select() {
sourceChooser.select(SRC_NONE);
int x = windowOffsetX+1;
int y = windowOffsetY+1;
int w = windowWidth-2;
int h = windowHeight-2;
conductFillRect(x-1, y-1, x+w+1, y+h+1, 1);
int k, r = w/2;
double jj[] = new double[3];
double omega = zeroj(1, 1)/r;
double tmult = 2*r/16.;
for (k = -r; k <= r; k++) {
int yy = (int) Math.sqrt(r*r-k*k-.00001);
conductFillRect(x+r+k, y+r-yy, x+r+k, y+r+yy, 0);
int l;
for (l = -yy; l <= yy; l++) {
double rr = Math.sqrt(k*k+l*l);
double r0 = rr*omega;
double angfunc1 = l/rr;
double angfunc2 = k/rr;
if (rr == 0)
angfunc1 = angfunc2 = 0;
bess(1, r0, jj);
grid[x+r+k+gw*(y+r+l)].az = jj[2]*angfunc1*tmult;
grid[x+r+k+gw*(y+r+l)].dazdt = jj[2]*angfunc2;
}
}
brightnessBar.setValue(200);
}
Setup createNext() { return new Waveguides1Setup(); }
}
double zeroj( int m_order, int n_zero) {
// Zeros of the Bessel function J(x)
// Inputs
// m_order Order of the Bessel function
// n_zero Index of the zero (first, second, etc.)
// Output
// z The "n_zero"th zero of the Bessel function
//* Use asymtotic formula for initial guess
double beta = (n_zero + 0.5*m_order - 0.25)*(3.141592654);
double mu = 4*m_order*m_order;
double beta8 = 8*beta;
double z = beta - (mu-1)/beta8
- 4*(mu-1)*(7*mu-31)/(3*beta8*beta8*beta8);
//* Use Newton's method to locate the root
double jj[] = new double[m_order+3];
int i; double deriv;
for( i=1; i<=5; i++ ) {
bess( m_order+1, z, jj ); // Remember j(1) is J_0(z)
// Use the recursion relation to evaluate derivative
deriv = -jj[m_order+2] + m_order/z * jj[m_order+1];
z -= jj[m_order+1]/deriv; // Newton's root finding
}
return(z);
}
void bess( int m_max, double x, double jj[] ) {
// Bessel function
// Inputs
// m_max Largest desired order
// x = Value at which Bessel function J(x) is evaluated
// Output
// jj = Vector of J(x) for order m = 0, 1, ..., m_max
//* Perform downward recursion from initial guess
int maxmx = (m_max > x) ? m_max : ((int)x); // Max(m,x)
// Recursion is downward from m_top (which is even)
int m_top = 2*((int)( (maxmx+15)/2 + 1 ));
double j[] = new double[m_top+2];
j[m_top+1] = 0.0;
j[m_top] = 1.0;
double tinyNumber = 1e-16;
int m;
for( m=m_top-2; m>=0; m--) // Downward recursion
j[m+1] = 2*(m+1)/(x+tinyNumber)*j[m+2] - j[m+3];
//* Normalize using identity and return requested values
double norm = j[1]; // NOTE: Be careful, m=0,1,... but
for( m=2; m<=m_top; m+=2 ) // vector goes j(1),j(2),...
norm += 2*j[m+1];
for( m=0; m<=m_max; m++ ) // Send back only the values for
jj[m+1] = j[m+1]/norm; // m=0,...,m_max and discard values
} // for m=m_max+1,...,m_top
class Waveguides1Setup extends Setup {
String getName() { return "Waveguides 1"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i, j;
int x = 1;
int nx = 5;
int y1 = windowOffsetY + 2;
while (x + nx < windowWidth) {
int x1 = x + windowOffsetX;
conductDrawRect(x1-1, y1-1, x1-1, gridSizeY-1, 1);
conductDrawRect(x1+nx, y1-1, x1+nx, gridSizeY-1, 1);
nx += 2;
x += nx;
}
conductDrawRect(x-1+windowOffsetX, y1-1, gridSizeX-1, y1-1, 1);
brightnessBar.setValue(140);
setForceBar(28);
}
Setup createNext() { return new Waveguides2Setup(); }
}
class Waveguides2Setup extends Waveguides1Setup {
String getName() { return "Waveguides 2"; }
void select() {
super.select();
setForceBar(17);
}
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 + 2;
conductDrawRect(windowOffsetX+1, y1-1,
windowOffsetX+windowWidth-1, y1-1, 1);
x = 1;
j = 0;
while (x + nx < windowWidth && j < nx) {
int x1 = x + windowOffsetX;
conductDrawRect(x1-1, y1-1, x1-1, gridSizeY-1, 1);
conductDrawRect(x1+nx, y1-1, x1+nx, gridSizeY-1, 1);
addConductor(x1+j++, y1-1, 0);
x += nx+2;
if (resBar.getValue() == 32 && j == 2)
j++;
}
brightnessBar.setValue(1000);
setForceBar(32);
}
Setup createNext() { return new Waveguides4Setup(); }
}
class Waveguides4Setup extends Waveguides3Setup {
String getName() { return "Waveguides 4"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int i;
int x = 1;
int nx = 9;
int y1 = windowOffsetY + 2;
int ny = windowHeight-1;
x = 1;
while (x + nx < windowWidth) {
int x1 = x + windowOffsetX;
conductDrawRect(x1-1, y1-1, x1-1, y1+ny-2, 1);
conductDrawRect(x1+nx, y1-1, x1+nx, y1+ny-2, 1);
x += nx+2;
}
brightnessBar.setValue(480);
setForceBar(40);
}
void doStep() {
int y = windowOffsetY;
int nx = 9;
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 = n2 = 3; break;
case 4: n1 = 1; n2 = 2; 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++) {
grid[x1+j+gw*y].az = grid[x1+j+gw*y].jz *
(Math.sin(pi*n1*(j+1)/(nx+1)) +
Math.sin(pi*n2*(j+1)/(nx+1)));
grid[x1+j+gw*y].jz = 0;
}
x += nx+2;
g++;
}
}
Setup createNext() { return new ResonantCavitiesSetup(); }
}
class ResonantCavitiesSetup extends Setup {
String getName() { return "Resonant Cavities"; }
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++) {
addConductor(x1- 1, y1+i-1, 1);
addConductor(x1+nx, y1+i-1, 1);
}
for (j = 0; j != nx+2; j++) {
addConductor(x1+j-1, y1-1, 1);
addConductor(x1+j-1, y1+ny, 1);
}
addConductor(x1+nx/2, y1-1, 0);
x += nx+2;
}
x--;
for (; x < windowWidth; x++)
addConductor(x+windowOffsetX, y1-1, 1);
brightnessBar.setValue(300);
setForceBar(38);
}
Setup createNext() { return new SingleSlitSetup(); }
}
class SingleSlitSetup extends Setup {
String getName() { return "Single Slit"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int x = gridSizeX/2;
int y = windowOffsetY+4;
conductFillRect(0, y, gridSizeX-1, y+2, 1);
conductFillRect(x-7, y, x+7, y+2, 0);
brightnessBar.setValue(275);
setForceBar(35);
}
Setup createNext() { return new DoubleSlitSetup(); }
}
class DoubleSlitSetup extends Setup {
String getName() { return "Double Slit"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int x = gridSizeX/2;
int y = windowOffsetY+4;
conductFillRect(0, y, gridSizeX-1, y+2, 1);
conductFillRect(x-7, y, x-5, y+2, 0);
conductFillRect(x+5, y, x+7, y+2, 0);
brightnessBar.setValue(366);
setForceBar(35);
}
Setup createNext() { return new TripleSlitSetup(); }
}
class TripleSlitSetup extends Setup {
String getName() { return "Triple Slit"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int x = gridSizeX/2;
int y = windowOffsetY+4;
conductFillRect(0, y, gridSizeX-1, y+2, 1);
conductFillRect(x-13, y, x-11, y+2, 0);
conductFillRect(x -1, y, x +1, y+2, 0);
conductFillRect(x+11, y, x+13, y+2, 0);
brightnessBar.setValue(310);
setForceBar(35);
}
Setup createNext() { return new ObstacleSetup(); }
}
class ObstacleSetup extends Setup {
String getName() { return "Obstacle"; }
void select() {
sourceChooser.select(SRC_1S1F_PLANE);
int x = gridSizeX/2;
int y = windowOffsetY+6;
conductFillRect(x-7, y, x+7, y+2, 1);
brightnessBar.setValue(400);
setForceBar(35);
}
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;
conductFillRect(windowOffsetX+windowWidth*2/3, windowOffsetY+3,
windowOffsetY+windowWidth-1, windowOffsetY+5, 1);
brightnessBar.setValue(150);
setForceBar(35);
}
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;
brightnessBar.setValue(120);
setForceBar(40);
conductDrawRect(0, windowOffsetY+windowHeight-1,
gridSizeX-1, windowOffsetY+windowHeight-1, 1);
}
void doSetupSources() {}
Setup createNext() { return null; }
}
void addThickWire(int cx, int cy, int r, double j) {
int res = 4;
cx *= res;
cy *= res;
r *= res;
j /= (res*res);
int x, y;
for (x = -r; x <= r; x++) {
int yd = (int) Math.sqrt(r*r-x*x);
for (y = -yd; y <= yd; y++)
grid[( x+cx)/res+gw*((y+cy)/res)].jz += j;
}
}
void addWireCircle(int cx, int cy, int r, double j, int deg1, int deg2) {
int res = 4;
r *= res;
j /= (res*res);
int th;
for (th = deg1; th != deg2; th++) {
int x = cx+(int) (Math.cos(th*pi/180)*r/res);
int y = cy-(int) (Math.sin(th*pi/180)*r/res);
grid[x+gw*y].jz += j;
}
}
void addConductor(int x, int y, double cv) {
OscElement oe = grid[x+gw*y];
oe.conductivity = (float) cv;
if (cv == 1)
oe.az = oe.dazdt = 0;
}
void addPerm(int x, int y, double pm) {
OscElement oe = grid[x+gw*y];
oe.perm = (float) pm;
oe.conductivity = (pm == 1) ? 0 : .5f;
}
void conductFillRect(int x, int y, int x2, int y2, double cv) {
int i, j;
for (i = x; i <= x2; i++)
for (j = y; j <= y2; j++)
addConductor(i, j, (float) cv);
}
void conductDrawRect(int x, int y, int x2, int y2, double cvd) {
int i;
float cv = (float) cvd;
for (i = x; i <= x2; i++) {
addConductor(i, y, cv);
addConductor(i, y2, cv);
}
for (i = y; i <= y2; i++) {
addConductor(x, i, cv);
addConductor(x2, i, cv);
}
}
void permDrawRect(int x, int y, int x2, int y2, double pm) {
int i;
for (i = x; i <= x2; i++) {
addPerm(i, y, pm);
addPerm(i, y2, pm);
}
for (i = y; i <= y2; i++) {
addPerm(x, i, pm);
addPerm(x2, i, pm);
}
}
void permFillRect(int x, int y, int x2, int y2, double pm) {
int i, j;
for (i = x; i <= x2; i++)
for (j = y; j <= y2; j++)
addPerm(i, j, pm);
}
}
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.scgdgs.com.cn
www.yaoqiu8.com.cn
www.wdjp.com.cn
sspw.com.cn
www.xidou5.com.cn
www.suoli1.net.cn
www.shimi9.com.cn
www.9131ych.com.cn
www.alphatrend.com.cn
91cyhd.org.cn