From 9cc0dcb412819126b8d9a69edfa1722f806d50c4 Mon Sep 17 00:00:00 2001 From: STSynthe Date: Wed, 12 Apr 2023 08:08:46 +0900 Subject: [PATCH 1/2] warning squash --- .classpath | 12 +- .../com.gwtplugins.gwt.eclipse.core.prefs | 1 + .../circuitjs1/client/ACRailElm.java | 14 +- .../circuitjs1/client/ACVoltageElm.java | 9 +- .../circuitjs1/client/ADCElm.java | 73 +- .../lushprojects/circuitjs1/client/AMElm.java | 117 +- .../circuitjs1/client/AboutBox.java | 60 +- .../circuitjs1/client/Adjustable.java | 92 +- .../circuitjs1/client/AmmeterElm.java | 369 +- .../circuitjs1/client/AnalogSwitch2Elm.java | 42 +- .../circuitjs1/client/AnalogSwitchElm.java | 79 +- .../circuitjs1/client/AndGateElm.java | 131 +- .../circuitjs1/client/AntennaElm.java | 78 +- .../circuitjs1/client/AudioInputElm.java | 269 +- .../circuitjs1/client/AudioOutputElm.java | 717 +- .../circuitjs1/client/BoxElm.java | 32 +- .../circuitjs1/client/CC2Elm.java | 133 +- .../circuitjs1/client/CCCSElm.java | 416 +- .../circuitjs1/client/CCVSElm.java | 402 +- .../circuitjs1/client/CapacitorElm.java | 383 +- .../circuitjs1/client/Checkbox.java | 34 +- .../client/CheckboxAlignedMenuItem.java | 8 +- .../circuitjs1/client/CheckboxMenuItem.java | 151 +- .../circuitjs1/client/ChipElm.java | 1075 +-- .../circuitjs1/client/Choice.java | 24 +- .../circuitjs1/client/CirSim.java | 7538 +++++++++-------- .../circuitjs1/client/CircuitElm.java | 1214 +-- .../circuitjs1/client/CircuitNode.java | 5 +- .../circuitjs1/client/CircuitNodeLink.java | 6 +- .../circuitjs1/client/ClockElm.java | 24 +- .../lushprojects/circuitjs1/client/Color.java | 105 +- .../circuitjs1/client/ComparatorElm.java | 140 +- .../circuitjs1/client/CompositeElm.java | 103 +- .../circuitjs1/client/Counter2Elm.java | 232 +- .../circuitjs1/client/CounterElm.java | 264 +- .../circuitjs1/client/CrystalElm.java | 268 +- .../circuitjs1/client/CurrentElm.java | 178 +- .../client/CustomCompositeChipElm.java | 88 +- .../circuitjs1/client/CustomCompositeElm.java | 184 +- .../client/CustomCompositeModel.java | 188 +- .../circuitjs1/client/CustomLogicElm.java | 122 +- .../circuitjs1/client/CustomLogicModel.java | 133 +- .../client/CustomTransformerElm.java | 818 +- .../circuitjs1/client/DACElm.java | 72 +- .../circuitjs1/client/DCMotorElm.java | 219 +- .../circuitjs1/client/DCVoltageElm.java | 15 +- .../circuitjs1/client/DFlipFlopElm.java | 241 +- .../circuitjs1/client/DarlingtonElm.java | 46 +- .../circuitjs1/client/DataInputElm.java | 301 +- .../circuitjs1/client/DataRecorderElm.java | 228 +- .../circuitjs1/client/DeMultiplexerElm.java | 146 +- .../circuitjs1/client/DecimalDisplayElm.java | 99 +- .../circuitjs1/client/DelayBufferElm.java | 249 +- .../circuitjs1/client/DiacElm.java | 78 +- .../circuitjs1/client/Dialog.java | 40 +- .../lushprojects/circuitjs1/client/Diode.java | 114 +- .../circuitjs1/client/DiodeElm.java | 177 +- .../circuitjs1/client/DiodeModel.java | 131 +- .../client/EditCompositeModelDialog.java | 576 +- .../circuitjs1/client/EditDialog.java | 526 +- .../circuitjs1/client/EditDialogLoadFile.java | 56 +- .../client/EditDiodeModelDialog.java | 6 +- .../circuitjs1/client/EditInfo.java | 126 +- .../circuitjs1/client/EditOptions.java | 296 +- .../client/EditTransistorModelDialog.java | 12 +- .../client/ExportAsImageDialog.java | 68 +- .../client/ExportAsLocalFileDialog.java | 190 +- .../circuitjs1/client/ExportAsTextDialog.java | 141 +- .../circuitjs1/client/ExportAsUrlDialog.java | 217 +- .../lushprojects/circuitjs1/client/Expr.java | 182 +- .../circuitjs1/client/ExtVoltageElm.java | 96 +- .../lushprojects/circuitjs1/client/FFT.java | 109 +- .../lushprojects/circuitjs1/client/FMElm.java | 139 +- .../lushprojects/circuitjs1/client/Font.java | 28 +- .../circuitjs1/client/FullAdderElm.java | 153 +- .../circuitjs1/client/FuseElm.java | 300 +- .../circuitjs1/client/GateElm.java | 477 +- .../circuitjs1/client/GraphicElm.java | 16 +- .../circuitjs1/client/Graphics.java | 326 +- .../circuitjs1/client/GroundElm.java | 253 +- .../circuitjs1/client/HalfAdderElm.java | 81 +- .../circuitjs1/client/ImportFromDropbox.java | 150 +- .../client/ImportFromDropboxDialog.java | 168 +- .../client/ImportFromTextDialog.java | 90 +- .../circuitjs1/client/Inductor.java | 40 +- .../circuitjs1/client/InductorElm.java | 223 +- .../circuitjs1/client/InverterElm.java | 255 +- .../client/InvertingSchmittElm.java | 344 +- .../circuitjs1/client/JKFlipFlopElm.java | 255 +- .../circuitjs1/client/JfetElm.java | 260 +- .../circuitjs1/client/LDRElm.java | 165 +- .../circuitjs1/client/LEDArrayElm.java | 324 +- .../circuitjs1/client/LEDElm.java | 218 +- .../circuitjs1/client/LabeledNodeElm.java | 109 +- .../circuitjs1/client/LampElm.java | 367 +- .../circuitjs1/client/LatchElm.java | 55 +- .../circuitjs1/client/LineElm.java | 18 +- .../circuitjs1/client/LoadFile.java | 111 +- .../circuitjs1/client/LogicInputElm.java | 285 +- .../circuitjs1/client/LogicOutputElm.java | 247 +- .../circuitjs1/client/MBBSwitchElm.java | 343 +- .../circuitjs1/client/MemristorElm.java | 87 +- .../circuitjs1/client/MonostableElm.java | 171 +- .../circuitjs1/client/MosfetElm.java | 1026 +-- .../circuitjs1/client/MultiplexerElm.java | 239 +- .../circuitjs1/client/MyCommand.java | 22 +- .../circuitjs1/client/NDarlingtonElm.java | 5 +- .../circuitjs1/client/NJfetElm.java | 19 +- .../circuitjs1/client/NMosfetElm.java | 14 +- .../circuitjs1/client/NTransistorElm.java | 17 +- .../circuitjs1/client/NandGateElm.java | 34 +- .../circuitjs1/client/NoiseElm.java | 27 +- .../circuitjs1/client/NorGateElm.java | 34 +- .../circuitjs1/client/OhmMeterElm.java | 110 +- .../circuitjs1/client/OpAmpElm.java | 418 +- .../circuitjs1/client/OpAmpRealElm.java | 311 +- .../circuitjs1/client/OpAmpSwapElm.java | 18 +- .../circuitjs1/client/OptocouplerElm.java | 176 +- .../circuitjs1/client/OrGateElm.java | 166 +- .../circuitjs1/client/OutputElm.java | 198 +- .../circuitjs1/client/PDarlingtonElm.java | 7 +- .../circuitjs1/client/PMosfetElm.java | 14 +- .../circuitjs1/client/PTransistorElm.java | 17 +- .../circuitjs1/client/PhaseCompElm.java | 45 +- .../circuitjs1/client/PisoShiftElm.java | 249 +- .../lushprojects/circuitjs1/client/Point.java | 76 +- .../circuitjs1/client/PolarCapacitorElm.java | 137 +- .../circuitjs1/client/Polygon.java | 83 +- .../circuitjs1/client/PotElm.java | 255 +- .../circuitjs1/client/ProbeElm.java | 461 +- .../circuitjs1/client/PushSwitchElm.java | 14 +- .../circuitjs1/client/QueryParameters.java | 49 +- .../circuitjs1/client/RailElm.java | 83 +- .../circuitjs1/client/Rectangle.java | 237 +- .../circuitjs1/client/RelayElm.java | 296 +- .../circuitjs1/client/ResistorElm.java | 207 +- .../circuitjs1/client/RingCounterElm.java | 231 +- .../circuitjs1/client/RowInfo.java | 21 +- .../circuitjs1/client/SCRElm.java | 140 +- .../circuitjs1/client/SRAMElm.java | 432 +- .../circuitjs1/client/SRAMLoadFile.java | 58 +- .../circuitjs1/client/SchmittElm.java | 144 +- .../lushprojects/circuitjs1/client/Scope.java | 2559 +++--- .../circuitjs1/client/ScopeElm.java | 75 +- .../circuitjs1/client/ScopePopupMenu.java | 39 +- .../client/ScopePropertiesDialog.java | 1024 ++- .../circuitjs1/client/ScrollValuePopup.java | 334 +- .../circuitjs1/client/Scrollbar.java | 544 +- .../circuitjs1/client/SearchDialog.java | 193 +- .../circuitjs1/client/SeqGenElm.java | 341 +- .../circuitjs1/client/SevenSegDecoderElm.java | 237 +- .../circuitjs1/client/SevenSegElm.java | 651 +- .../circuitjs1/client/ShortcutsDialog.java | 212 +- .../circuitjs1/client/SipoShiftElm.java | 167 +- .../circuitjs1/client/SliderDialog.java | 378 +- .../circuitjs1/client/SparkGapElm.java | 48 +- .../circuitjs1/client/SquareRailElm.java | 14 +- .../circuitjs1/client/StopTriggerElm.java | 186 +- .../circuitjs1/client/StringTokenizer.java | 414 +- .../circuitjs1/client/SweepElm.java | 108 +- .../circuitjs1/client/Switch2Elm.java | 349 +- .../circuitjs1/client/SwitchElm.java | 65 +- .../circuitjs1/client/TFlipFlopElm.java | 203 +- .../client/TappedTransformerElm.java | 531 +- .../circuitjs1/client/TestPointElm.java | 625 +- .../circuitjs1/client/TextElm.java | 65 +- .../circuitjs1/client/ThermistorNTCElm.java | 194 +- .../circuitjs1/client/TimeDelayRelayElm.java | 216 +- .../circuitjs1/client/TimerElm.java | 165 +- .../circuitjs1/client/TransLineElm.java | 137 +- .../circuitjs1/client/TransformerElm.java | 551 +- .../circuitjs1/client/TransistorElm.java | 1052 +-- .../circuitjs1/client/TransistorModel.java | 92 +- .../circuitjs1/client/TriStateElm.java | 36 +- .../circuitjs1/client/TriacElm.java | 179 +- .../circuitjs1/client/TriodeElm.java | 148 +- .../circuitjs1/client/TunnelDiodeElm.java | 75 +- .../circuitjs1/client/UnijunctionElm.java | 233 +- .../circuitjs1/client/VCCSElm.java | 404 +- .../circuitjs1/client/VCOElm.java | 190 +- .../circuitjs1/client/VCVSElm.java | 191 +- .../circuitjs1/client/VarRailElm.java | 156 +- .../circuitjs1/client/VaractorElm.java | 82 +- .../circuitjs1/client/VoltageElm.java | 258 +- .../circuitjs1/client/WattmeterElm.java | 98 +- .../circuitjs1/client/WireElm.java | 158 +- .../circuitjs1/client/XorGateElm.java | 64 +- .../circuitjs1/client/ZenerElm.java | 37 +- .../circuitjs1/client/circuitjs1.java | 176 +- .../circuitjs1/client/util/Locale.java | 50 +- .../circuitjs1/client/util/PerfMonitor.java | 144 +- 191 files changed, 25237 insertions(+), 22447 deletions(-) diff --git a/.classpath b/.classpath index 11329e5f..9ab46fe2 100644 --- a/.classpath +++ b/.classpath @@ -2,7 +2,15 @@ - - + + + + + + + + + + diff --git a/.settings/com.gwtplugins.gwt.eclipse.core.prefs b/.settings/com.gwtplugins.gwt.eclipse.core.prefs index 01a247b0..9f5d37bd 100644 --- a/.settings/com.gwtplugins.gwt.eclipse.core.prefs +++ b/.settings/com.gwtplugins.gwt.eclipse.core.prefs @@ -3,3 +3,4 @@ entryPointModules= filesCopiedToWebInfLib=gwt-servlet.jar gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14MWddXT48L3ZtLWFyZ3M+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20ubHVzaHByb2plY3RzLmNpcmN1aXRqczEuY2lyY3VpdGpzMTwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+ gwtSyncCodeServer=true +gwtVersion_C\:\\java\\gwt=2.10.0 diff --git a/src/com/lushprojects/circuitjs1/client/ACRailElm.java b/src/com/lushprojects/circuitjs1/client/ACRailElm.java index a32c294d..41a69cba 100644 --- a/src/com/lushprojects/circuitjs1/client/ACRailElm.java +++ b/src/com/lushprojects/circuitjs1/client/ACRailElm.java @@ -20,7 +20,15 @@ package com.lushprojects.circuitjs1.client; class ACRailElm extends RailElm { - public ACRailElm(int xx, int yy) { super(xx, yy, WF_AC); } - Class getDumpClass() { return RailElm.class; } - int getShortcut() { return 0; } + public ACRailElm(int xx, int yy) { + super(xx, yy, WF_AC); } + + Class getDumpClass() { + return RailElm.class; + } + + int getShortcut() { + return 0; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/ACVoltageElm.java b/src/com/lushprojects/circuitjs1/client/ACVoltageElm.java index aa3ddf03..fdb7057f 100644 --- a/src/com/lushprojects/circuitjs1/client/ACVoltageElm.java +++ b/src/com/lushprojects/circuitjs1/client/ACVoltageElm.java @@ -20,6 +20,11 @@ package com.lushprojects.circuitjs1.client; class ACVoltageElm extends VoltageElm { - public ACVoltageElm(int xx, int yy) { super(xx, yy, WF_AC); } - Class getDumpClass() { return VoltageElm.class; } + public ACVoltageElm(int xx, int yy) { + super(xx, yy, WF_AC); } + + Class getDumpClass() { + return VoltageElm.class; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/ADCElm.java b/src/com/lushprojects/circuitjs1/client/ADCElm.java index 8d1d1e40..06f08b32 100644 --- a/src/com/lushprojects/circuitjs1/client/ADCElm.java +++ b/src/com/lushprojects/circuitjs1/client/ADCElm.java @@ -20,52 +20,77 @@ package com.lushprojects.circuitjs1.client; class ADCElm extends ChipElm { - public ADCElm(int xx, int yy) { super(xx, yy); } - public ADCElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + public ADCElm(int xx, int yy) { + super(xx, yy); + } + + public ADCElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } - String getChipName() { return "ADC"; } - boolean needsBits() { return true; } + + String getChipName() { + return "ADC"; + } + + boolean needsBits() { + return true; + } + void setupPins() { sizeX = 2; sizeY = bits > 2 ? bits : 2; pins = new Pin[getPostCount()]; int i; for (i = 0; i != bits; i++) { - pins[i] = new Pin(bits-1-i, SIDE_E, "D" + i); + pins[i] = new Pin(bits - 1 - i, SIDE_E, "D" + i); pins[i].output = true; } - pins[bits] = new Pin(0, SIDE_W, "In"); - pins[bits+1] = new Pin(sizeY-1, SIDE_W, "V+"); + pins[bits] = new Pin(0, SIDE_W, "In"); + pins[bits + 1] = new Pin(sizeY - 1, SIDE_W, "V+"); allocNodes(); } + void execute() { - int imax = (1<= 2) { - bits = (int)ei.value; - setupPins(); - setPoints(); - } + if (n == 0 && ei.value >= 2) { + bits = (int) ei.value; + setupPins(); + setPoints(); + } } } diff --git a/src/com/lushprojects/circuitjs1/client/AMElm.java b/src/com/lushprojects/circuitjs1/client/AMElm.java index d643f2e5..1ab8fe80 100644 --- a/src/com/lushprojects/circuitjs1/client/AMElm.java +++ b/src/com/lushprojects/circuitjs1/client/AMElm.java @@ -23,50 +23,61 @@ class AMElm extends CircuitElm { static final int FLAG_COS = 2; - double carrierfreq,signalfreq, maxVoltage, freqTimeZero; + double carrierfreq, signalfreq, maxVoltage, freqTimeZero; + public AMElm(int xx, int yy) { super(xx, yy); maxVoltage = 5; carrierfreq = 1000; - signalfreq=40; + signalfreq = 40; reset(); } - public AMElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public AMElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - carrierfreq = new Double(st.nextToken()).doubleValue(); - signalfreq= new Double(st.nextToken()).doubleValue(); - maxVoltage = new Double(st.nextToken()).doubleValue(); + carrierfreq = Double.valueOf(st.nextToken()).doubleValue(); + signalfreq = Double.valueOf(st.nextToken()).doubleValue(); + maxVoltage = Double.valueOf(st.nextToken()).doubleValue(); if ((flags & FLAG_COS) != 0) { flags &= ~FLAG_COS; } reset(); } - int getDumpType() { return 200; } + + int getDumpType() { + return 200; + } + String dump() { - return super.dump() + " " +carrierfreq+" " + signalfreq + " " +maxVoltage; + return super.dump() + " " + carrierfreq + " " + signalfreq + " " + maxVoltage; } - /*void setCurrent(double c) { - current = c; - System.out.print("v current set to " + c + "\n"); - }*/ + /* + * void setCurrent(double c) { current = c; System.out.print("v current set to " + * + c + "\n"); } + */ void reset() { freqTimeZero = 0; curcount = 0; } - int getPostCount() { return 1; } - - void stamp() { - sim.stampVoltageSource(0, nodes[0], voltSource); + + int getPostCount() { + return 1; + } + + void stamp() { + sim.stampVoltageSource(0, nodes[0], voltSource); } + void doStep() { - sim.updateVoltageSource(0, nodes[0], voltSource, getVoltage()); + sim.updateVoltageSource(0, nodes[0], voltSource, getVoltage()); } + double getVoltage() { - double w = 2*pi*(sim.t-freqTimeZero); - return ((Math.sin(w*signalfreq)+1)/2)*Math.sin(w*carrierfreq)*maxVoltage; + double w = 2 * pi * (sim.t - freqTimeZero); + return ((Math.sin(w * signalfreq) + 1) / 2) * Math.sin(w * carrierfreq) * maxVoltage; } + final int circleSize = 17; void draw(Graphics g) { @@ -74,54 +85,61 @@ void draw(Graphics g) { setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); - Font f = new Font("SansSerif", 0, 12); - g.setFont(f); - g.setColor(needsHighlight() ? selectColor : whiteColor); - setPowerColor(g, false); - double v = getVoltage(); - String s = "AM"; - drawCenteredText(g, s, x2, y2, true); - drawWaveform(g, point2); + Font f = new Font("SansSerif", 0, 12); + g.setFont(f); + g.setColor(needsHighlight() ? selectColor : whiteColor); + setPowerColor(g, false); + double v = getVoltage(); + String s = "AM"; + drawCenteredText(g, s, x2, y2, true); + drawWaveform(g, point2); drawPosts(g); curcount = updateDotCount(-current, curcount); if (sim.dragElm != this) drawDots(g, point1, lead1, curcount); } - + void drawWaveform(Graphics g, Point center) { g.setColor(needsHighlight() ? selectColor : Color.gray); setPowerColor(g, false); - int xc = center.x; int yc = center.y; + int xc = center.x; + int yc = center.y; drawThickCircle(g, xc, yc, circleSize); int wl = 8; - adjustBbox(xc-circleSize, yc-circleSize, - xc+circleSize, yc+circleSize); + adjustBbox(xc - circleSize, yc - circleSize, xc + circleSize, yc + circleSize); } - - void setPoints() { + void setPoints() { super.setPoints(); - lead1 = interpPoint(point1, point2, 1-circleSize/dn); + lead1 = interpPoint(point1, point2, 1 - circleSize / dn); } - - double getVoltageDiff() { return volts[0]; } - - boolean hasGroundConnection(int n1) { return true; } - + + double getVoltageDiff() { + return volts[0]; + } + + boolean hasGroundConnection(int n1) { + return true; + } + int getVoltageSourceCount() { return 1; } - double getPower() { return -getVoltageDiff()*current; } + + double getPower() { + return -getVoltageDiff() * current; + } + void getInfo(String arr[]) { - + arr[0] = "AM Source"; arr[1] = "I = " + getCurrentText(getCurrent()); - arr[2] = "V = " + - getVoltageText(getVoltageDiff()); - arr[3] = "cf = " + getUnitText(carrierfreq, "Hz"); - arr[4] = "sf = " + getUnitText(signalfreq, "Hz"); - arr[5] = "Vmax = " + getVoltageText(maxVoltage); + arr[2] = "V = " + getVoltageText(getVoltageDiff()); + arr[3] = "cf = " + getUnitText(carrierfreq, "Hz"); + arr[4] = "sf = " + getUnitText(signalfreq, "Hz"); + arr[5] = "Vmax = " + getVoltageText(maxVoltage); } + public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Max Voltage", maxVoltage, -20, 20); @@ -129,15 +147,16 @@ public EditInfo getEditInfo(int n) { return new EditInfo("Carrier Frequency (Hz)", carrierfreq, 4, 500); if (n == 2) return new EditInfo("Signal Frequency (Hz)", signalfreq, 4, 500); - + return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) maxVoltage = ei.value; if (n == 1) carrierfreq = ei.value; if (n == 2) - signalfreq=ei.value; + signalfreq = ei.value; } } diff --git a/src/com/lushprojects/circuitjs1/client/AboutBox.java b/src/com/lushprojects/circuitjs1/client/AboutBox.java index 39618f10..a84ffe35 100644 --- a/src/com/lushprojects/circuitjs1/client/AboutBox.java +++ b/src/com/lushprojects/circuitjs1/client/AboutBox.java @@ -28,34 +28,34 @@ import com.google.gwt.user.client.ui.Button; public class AboutBox extends PopupPanel { - - VerticalPanel vp; - Button okButton; - - AboutBox(String version) { - super(); - - // Add versionString variable to SessionStorage for iFrame in AboutBox - Storage sstor = Storage.getSessionStorageIfSupported(); - sstor.setItem("versionString", version); - - vp = new VerticalPanel(); - setWidget(vp); - vp.setWidth("400px"); - vp.add(new HTML("
")); - - - vp.add(okButton = new Button("OK")); - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - close(); - } - }); - center(); - show(); - } - - public void close() { - hide(); - } + + VerticalPanel vp; + Button okButton; + + AboutBox(String version) { + super(); + + // Add versionString variable to SessionStorage for iFrame in AboutBox + Storage sstor = Storage.getSessionStorageIfSupported(); + sstor.setItem("versionString", version); + + vp = new VerticalPanel(); + setWidget(vp); + vp.setWidth("400px"); + vp.add(new HTML( + "
")); + + vp.add(okButton = new Button("OK")); + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + close(); + } + }); + center(); + show(); + } + + public void close() { + hide(); + } } diff --git a/src/com/lushprojects/circuitjs1/client/Adjustable.java b/src/com/lushprojects/circuitjs1/client/Adjustable.java index c910de33..888f1418 100644 --- a/src/com/lushprojects/circuitjs1/client/Adjustable.java +++ b/src/com/lushprojects/circuitjs1/client/Adjustable.java @@ -12,30 +12,31 @@ public class Adjustable implements Command { double minValue, maxValue; int flags; String sliderText; - - // null if this Adjustable has its own slider, non-null if it's sharing another one. + + // null if this Adjustable has its own slider, non-null if it's sharing another + // one. Adjustable sharedSlider; - + final int FLAG_SHARED = 1; - + // index of value in getEditInfo() list that this slider controls int editItem; - + Label label; Scrollbar slider; boolean settingValue; - + Adjustable(CircuitElm ce, int item) { minValue = 1; maxValue = 1000; flags = 0; elm = ce; editItem = item; - EditInfo ei = ce.getEditInfo(editItem); - if (ei != null && ei.maxVal > 0) { - minValue = ei.minVal; - maxValue = ei.maxVal; - } + EditInfo ei = ce.getEditInfo(editItem); + if (ei != null && ei.maxVal > 0) { + minValue = ei.minVal; + maxValue = ei.maxVal; + } } // undump @@ -46,12 +47,13 @@ public class Adjustable implements Command { try { String ei = st.nextToken(); - // forgot to dump a "flags" field in the initial code, so we have to do this to support backward compatibility + // forgot to dump a "flags" field in the initial code, so we have to do this to + // support backward compatibility if (ei.startsWith("F")) { flags = Integer.parseInt(ei.substring(1)); ei = st.nextToken(); } - + editItem = Integer.parseInt(ei); minValue = Double.parseDouble(st.nextToken()); maxValue = Double.parseDouble(st.nextToken()); @@ -60,12 +62,14 @@ public class Adjustable implements Command { sharedSlider = ano == -1 ? null : sim.adjustables.get(ano); } sliderText = CustomLogicModel.unescape(st.nextToken()); - } catch (Exception ex) {} + } catch (Exception ex) { + } try { elm = sim.getElm(e); - } catch (Exception ex) {} + } catch (Exception ex) { + } } - + boolean createSlider(CirSim sim) { if (elm == null) return false; @@ -82,10 +86,10 @@ boolean createSlider(CirSim sim) { } void createSlider(CirSim sim, double value) { - sim.addWidgetToVerticalPanel(label = new Label(Locale.LS(sliderText))); - label.addStyleName("topSpace"); - int intValue = (int) ((value-minValue)*100/(maxValue-minValue)); - sim.addWidgetToVerticalPanel(slider = new Scrollbar(Scrollbar.HORIZONTAL, intValue, 1, 0, 101, this, elm)); + sim.addWidgetToVerticalPanel(label = new Label(Locale.LS(sliderText))); + label.addStyleName("topSpace"); + int intValue = (int) ((value - minValue) * 100 / (maxValue - minValue)); + sim.addWidgetToVerticalPanel(slider = new Scrollbar(Scrollbar.HORIZONTAL, intValue, 1, 0, 101, this, elm)); } void setSliderValue(double value) { @@ -93,12 +97,12 @@ void setSliderValue(double value) { sharedSlider.setSliderValue(value); return; } - int intValue = (int) ((value-minValue)*100/(maxValue-minValue)); - settingValue = true; // don't recursively set value again in execute() - slider.setValue(intValue); - settingValue = false; + int intValue = (int) ((value - minValue) * 100 / (maxValue - minValue)); + settingValue = true; // don't recursively set value again in execute() + slider.setValue(intValue); + settingValue = false; } - + public void execute() { if (settingValue) return; @@ -110,32 +114,33 @@ public void execute() { adj.executeSlider(); } } - + void executeSlider() { - elm.sim.analyzeFlag = true; + CircuitElm.sim.analyzeFlag = true; EditInfo ei = elm.getEditInfo(editItem); ei.value = getSliderValue(); elm.setEditValue(editItem, ei); - elm.sim.repaint(); + CircuitElm.sim.repaint(); } - + double getSliderValue() { double val = sharedSlider == null ? slider.getValue() : sharedSlider.slider.getValue(); - return minValue + (maxValue-minValue)*val/100; + return minValue + (maxValue - minValue) * val / 100; } - + void deleteSlider(CirSim sim) { try { sim.removeWidgetFromVerticalPanel(label); sim.removeWidgetFromVerticalPanel(slider); - } catch (Exception e) {} + } catch (Exception e) { + } } - + void setMouseElm(CircuitElm e) { if (slider != null) slider.draw(); } - + boolean sliderBeingShared() { int i; for (i = 0; i != CirSim.theSim.adjustables.size(); i++) { @@ -145,19 +150,22 @@ boolean sliderBeingShared() { } return false; } - + String dump() { int ano = -1; if (sharedSlider != null) ano = CirSim.theSim.adjustables.indexOf(sharedSlider); - - return elm.sim.locateElm(elm) + " F1 " + editItem + " " + minValue + " " + maxValue + " " + ano + " " + - CustomLogicModel.escape(sliderText); + + return CircuitElm.sim.locateElm(elm) + " F1 " + editItem + " " + minValue + " " + maxValue + " " + ano + " " + + CustomLogicModel.escape(sliderText); } - - // reorder adjustables so that items with sliders come first in the list, followed by items that reference them. - // this simplifies the UI code, and also makes it much easier to dump/undump the adjustables list, since we will - // always be undumping the adjustables with sliders first, then the adjustables that reference them. + + // reorder adjustables so that items with sliders come first in the list, + // followed by items that reference them. + // this simplifies the UI code, and also makes it much easier to dump/undump the + // adjustables list, since we will + // always be undumping the adjustables with sliders first, then the adjustables + // that reference them. static void reorderAdjustables() { Vector newList = new Vector(); Vector oldList = CirSim.theSim.adjustables; diff --git a/src/com/lushprojects/circuitjs1/client/AmmeterElm.java b/src/com/lushprojects/circuitjs1/client/AmmeterElm.java index b3ad9cc6..738bc1ba 100644 --- a/src/com/lushprojects/circuitjs1/client/AmmeterElm.java +++ b/src/com/lushprojects/circuitjs1/client/AmmeterElm.java @@ -25,196 +25,219 @@ import com.lushprojects.circuitjs1.client.util.Locale; class AmmeterElm extends CircuitElm { - - int meter; - int scale; - final int AM_VOL = 0; - final int AM_RMS = 1; - int zerocount=0; - double rmsI=0, total, count; - double maxI=0, lastMaxI; - double minI=0, lastMinI; - double selectedValue=0; - - double currents[]; - boolean increasingI=true, decreasingI=true; - - public AmmeterElm(int xx, int yy) { - super(xx, yy); - flags = FLAG_SHOWCURRENT; - scale = SCALE_AUTO; - } - public AmmeterElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - scale = SCALE_AUTO; - meter = Integer.parseInt(st.nextToken()); - try { - scale = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + + int meter; + int scale; + final int AM_VOL = 0; + final int AM_RMS = 1; + int zerocount = 0; + double rmsI = 0, total, count; + double maxI = 0, lastMaxI; + double minI = 0, lastMinI; + double selectedValue = 0; + + double currents[]; + boolean increasingI = true, decreasingI = true; + + public AmmeterElm(int xx, int yy) { + super(xx, yy); + flags = FLAG_SHOWCURRENT; + scale = SCALE_AUTO; } + + public AmmeterElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + scale = SCALE_AUTO; + meter = Integer.parseInt(st.nextToken()); + try { + scale = Integer.parseInt(st.nextToken()); + } catch (Exception e) { + } + } + String dump() { - return super.dump() + " " + meter + " " + scale; - } - String getMeter(){ - switch (meter) { - case AM_VOL: - return "I"; - case AM_RMS: - return "Irms"; - } - return ""; - } - void setPoints(){ - super.setPoints(); - mid = interpPoint(point1,point2,0.6); - arrowPoly = calcArrow(point1, mid, 14, 7); + return super.dump() + " " + meter + " " + scale; } + + String getMeter() { + switch (meter) { + case AM_VOL: + return "I"; + case AM_RMS: + return "Irms"; + } + return ""; + } + + void setPoints() { + super.setPoints(); + mid = interpPoint(point1, point2, 0.6); + arrowPoly = calcArrow(point1, mid, 14, 7); + } + Point mid; static final int FLAG_SHOWCURRENT = 1; - void stepFinished(){ - count++;//how many counts are in a cycle - total += current*current; //sum of squares - if (current>maxI && increasingI){ - maxI = current; - increasingI = true; - decreasingI = false; - } - if (currentminI && decreasingI){ //change of direction I now going up - lastMinI=minI; //capture last minimum - - maxI = current; - increasingI = true; - decreasingI = false; - - //rms data - total = total/count; - rmsI = Math.sqrt(total); - if (Double.isNaN(rmsI)) - rmsI=0; - count=0; - total=0; - - - } - //need to zero the rms value if it stays at 0 for a while - if (current==0){ - zerocount++; - if (zerocount > 5){ - total=0; - rmsI=0; - maxI=0; - minI=0; - } - }else{ - zerocount=0; - } - switch (meter) { - case AM_VOL: - selectedValue = current; - break; - case AM_RMS: - selectedValue = rmsI; - break; - } + + void stepFinished() { + count++;// how many counts are in a cycle + total += current * current; // sum of squares + if (current > maxI && increasingI) { + maxI = current; + increasingI = true; + decreasingI = false; + } + if (current < maxI && increasingI) {// change of direction I now going down - at start of waveform + lastMaxI = maxI; // capture last maximum + // capture time between + minI = current; // track minimum value + increasingI = false; + decreasingI = true; + + // rms data + total = total / count; + rmsI = Math.sqrt(total); + if (Double.isNaN(rmsI)) + rmsI = 0; + count = 0; + total = 0; + + } + if (current < minI && decreasingI) { // I going down, track minimum value + minI = current; + increasingI = false; + decreasingI = true; + } + + if (current > minI && decreasingI) { // change of direction I now going up + lastMinI = minI; // capture last minimum + + maxI = current; + increasingI = true; + decreasingI = false; + + // rms data + total = total / count; + rmsI = Math.sqrt(total); + if (Double.isNaN(rmsI)) + rmsI = 0; + count = 0; + total = 0; + + } + // need to zero the rms value if it stays at 0 for a while + if (current == 0) { + zerocount++; + if (zerocount > 5) { + total = 0; + rmsI = 0; + maxI = 0; + minI = 0; + } + } else { + zerocount = 0; + } + switch (meter) { + case AM_VOL: + selectedValue = current; + break; + case AM_RMS: + selectedValue = rmsI; + break; + } } - + Polygon arrowPoly; + void draw(Graphics g) { - super.draw(g);//BC required for highlighting - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, point2); - g.fillPolygon(arrowPoly); - doDots(g); - setBbox(point1, point2, 3); - String s = "A"; - switch (meter) { - case AM_VOL: - s = getUnitTextWithScale(getCurrent(), "A", scale); - break; - case AM_RMS: - s = getUnitTextWithScale(rmsI, "A(rms)", scale); - break; - } - - drawValues(g, s, 4); - drawPosts(g); - } - int getDumpType() { return 370; } + super.draw(g);// BC required for highlighting + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, point2); + g.fillPolygon(arrowPoly); + doDots(g); + setBbox(point1, point2, 3); + String s = "A"; + switch (meter) { + case AM_VOL: + s = getUnitTextWithScale(getCurrent(), "A", scale); + break; + case AM_RMS: + s = getUnitTextWithScale(rmsI, "A(rms)", scale); + break; + } + + drawValues(g, s, 4); + drawPosts(g); + } + + int getDumpType() { + return 370; + } + void stamp() { - sim.stampVoltageSource(nodes[0], nodes[1], voltSource, 0); + sim.stampVoltageSource(nodes[0], nodes[1], voltSource, 0); } + boolean mustShowCurrent() { - return (flags & FLAG_SHOWCURRENT) != 0; + return (flags & FLAG_SHOWCURRENT) != 0; } - int getVoltageSourceCount() { return 1; } + + int getVoltageSourceCount() { + return 1; + } + void getInfo(String arr[]) { - arr[0] = "Ammeter"; - switch (meter) { - case AM_VOL: - arr[1] = "I = " + getUnitText(current, "A"); - break; - case AM_RMS: - arr[1] = "Irms = " + getUnitText(rmsI, "A"); - break; - } - } - double getPower() { return 0; } - double getVoltageDiff() { return volts[0]; } - + arr[0] = "Ammeter"; + switch (meter) { + case AM_VOL: + arr[1] = "I = " + getUnitText(current, "A"); + break; + case AM_RMS: + arr[1] = "Irms = " + getUnitText(rmsI, "A"); + break; + } + } + + double getPower() { + return 0; + } + + double getVoltageDiff() { + return volts[0]; + } + // do not optimize out, even though isWireEquivalent() is true - // (because we need current calculated every timestep) - boolean isWireEquivalent() { return true; } - + // (because we need current calculated every timestep) + boolean isWireEquivalent() { + return true; + } + public EditInfo getEditInfo(int n) { - if (n==0){ - EditInfo ei = new EditInfo("Value", selectedValue, -1, -1); - ei.choice = new Choice(); - ei.choice.add("Current"); - ei.choice.add("RMS Current"); - ei.choice.select(meter); - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("Scale", 0); - ei.choice = new Choice(); - ei.choice.add("Auto"); - ei.choice.add("A"); - ei.choice.add("mA"); - ei.choice.add(Locale.muString + "A"); - ei.choice.select(scale); - return ei; - } - return null; + if (n == 0) { + EditInfo ei = new EditInfo("Value", selectedValue, -1, -1); + ei.choice = new Choice(); + ei.choice.add("Current"); + ei.choice.add("RMS Current"); + ei.choice.select(meter); + return ei; + } + if (n == 1) { + EditInfo ei = new EditInfo("Scale", 0); + ei.choice = new Choice(); + ei.choice.add("Auto"); + ei.choice.add("A"); + ei.choice.add("mA"); + ei.choice.add(Locale.muString + "A"); + ei.choice.select(scale); + return ei; + } + return null; } + public void setEditValue(int n, EditInfo ei) { - if (n==0) - meter = ei.choice.getSelectedIndex(); - if (n==1) - scale = ei.choice.getSelectedIndex(); + if (n == 0) + meter = ei.choice.getSelectedIndex(); + if (n == 1) + scale = ei.choice.getSelectedIndex(); } } - diff --git a/src/com/lushprojects/circuitjs1/client/AnalogSwitch2Elm.java b/src/com/lushprojects/circuitjs1/client/AnalogSwitch2Elm.java index 301ea781..cc21554d 100644 --- a/src/com/lushprojects/circuitjs1/client/AnalogSwitch2Elm.java +++ b/src/com/lushprojects/circuitjs1/client/AnalogSwitch2Elm.java @@ -23,23 +23,27 @@ class AnalogSwitch2Elm extends AnalogSwitchElm { public AnalogSwitch2Elm(int xx, int yy) { super(xx, yy); } - public AnalogSwitch2Elm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public AnalogSwitch2Elm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } final int openhs = 16; Point swposts[], swpoles[], ctlPoint; + void setPoints() { super.setPoints(); calcLeads(32); swposts = newPointArray(2); swpoles = newPointArray(2); - interpPoint2(lead1, lead2, swpoles[0], swpoles[1], 1, openhs); + interpPoint2(lead1, lead2, swpoles[0], swpoles[1], 1, openhs); interpPoint2(point1, point2, swposts[0], swposts[1], 1, openhs); ctlPoint = interpPoint(point1, point2, .5, openhs); } - int getPostCount() { return 4; } + + int getPostCount() { + return 4; + } void draw(Graphics g) { setBbox(point1, point2, openhs); @@ -51,7 +55,7 @@ void draw(Graphics g) { // draw second lead setVoltageColor(g, volts[1]); drawThickLine(g, swpoles[0], swposts[0]); - + // draw third lead setVoltageColor(g, volts[2]); drawThickLine(g, swpoles[1], swposts[1]); @@ -60,30 +64,34 @@ void draw(Graphics g) { g.setColor(lightGrayColor); int position = (open) ? 1 : 0; drawThickLine(g, lead1, swpoles[position]); - + updateDotCount(); drawDots(g, point1, lead1, curcount); drawDots(g, swpoles[position], swposts[position], curcount); drawPosts(g); } - + Point getPost(int n) { - return (n == 0) ? point1 : (n == 3) ? ctlPoint : swposts[n-1]; + return (n == 0) ? point1 : (n == 3) ? ctlPoint : swposts[n - 1]; + } + + int getDumpType() { + return 160; } - int getDumpType() { return 160; } void calculateCurrent() { if (open) - current = (volts[0]-volts[2])/r_on; + current = (volts[0] - volts[2]) / r_on; else - current = (volts[0]-volts[1])/r_on; + current = (volts[0] - volts[1]) / r_on; } - + void stamp() { sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); sim.stampNonLinear(nodes[2]); } + void doStep() { open = (volts[3] < 2.5); if ((flags & FLAG_INVERT) != 0) @@ -96,24 +104,24 @@ void doStep() { sim.stampResistor(nodes[0], nodes[2], r_off); } } - + boolean getConnection(int n1, int n2) { if (n1 == 3 || n2 == 3) return false; return true; } + void getInfo(String arr[]) { arr[0] = "analog switch (SPDT)"; arr[1] = "I = " + getCurrentDText(getCurrent()); } - + double getCurrentIntoNode(int n) { if (n == 0) return -current; int position = (open) ? 1 : 0; - if (n == position+1) + if (n == position + 1) return current; return 0; - } + } } - diff --git a/src/com/lushprojects/circuitjs1/client/AnalogSwitchElm.java b/src/com/lushprojects/circuitjs1/client/AnalogSwitchElm.java index 36538478..b72d6932 100644 --- a/src/com/lushprojects/circuitjs1/client/AnalogSwitchElm.java +++ b/src/com/lushprojects/circuitjs1/client/AnalogSwitchElm.java @@ -22,68 +22,79 @@ class AnalogSwitchElm extends CircuitElm { final int FLAG_INVERT = 1; double resistance, r_on, r_off; + public AnalogSwitchElm(int xx, int yy) { super(xx, yy); r_on = 20; r_off = 1e10; } - public AnalogSwitchElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public AnalogSwitchElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); r_on = 20; r_off = 1e10; try { - r_on = new Double(st.nextToken()).doubleValue(); - r_off = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { } - + r_on = Double.valueOf(st.nextToken()).doubleValue(); + r_off = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { + } + } + String dump() { return super.dump() + " " + r_on + " " + r_off; } - - int getDumpType() { return 159; } + + int getDumpType() { + return 159; + } + boolean open; - + Point ps, point3, lead3; + void setPoints() { super.setPoints(); calcLeads(32); ps = new Point(); int openhs = 16; point3 = interpPoint(point1, point2, .5, -openhs); - lead3 = interpPoint(point1, point2, .5, -openhs/2); + lead3 = interpPoint(point1, point2, .5, -openhs / 2); } - + void draw(Graphics g) { int openhs = 16; int hs = (open) ? openhs : 0; setBbox(point1, point2, openhs); draw2Leads(g); - + g.setColor(lightGrayColor); interpPoint(lead1, lead2, ps, 1, hs); drawThickLine(g, lead1, ps); setVoltageColor(g, volts[2]); drawThickLine(g, point3, lead3); - + if (!open) doDots(g); drawPosts(g); } + void calculateCurrent() { - current = (volts[0]-volts[1])/resistance; + current = (volts[0] - volts[1]) / resistance; } - + // we need this to be able to change the matrix for each step - boolean nonLinear() { return true; } + boolean nonLinear() { + return true; + } void stamp() { sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); } + void doStep() { open = (volts[2] < 2.5); if ((flags & FLAG_INVERT) != 0) @@ -91,24 +102,31 @@ void doStep() { resistance = (open) ? r_off : r_on; sim.stampResistor(nodes[0], nodes[1], resistance); } + void drag(int xx, int yy) { xx = sim.snapGrid(xx); yy = sim.snapGrid(yy); - if (abs(x-xx) < abs(y-yy)) + if (abs(x - xx) < abs(y - yy)) xx = x; else yy = y; - int q1 = abs(x-xx)+abs(y-yy); - int q2 = (q1/2) % sim.gridSize; + int q1 = abs(x - xx) + abs(y - yy); + int q2 = (q1 / 2) % sim.gridSize; if (q2 != 0) return; - x2 = xx; y2 = yy; + x2 = xx; + y2 = yy; setPoints(); } - int getPostCount() { return 3; } + + int getPostCount() { + return 3; + } + Point getPost(int n) { return (n == 0) ? point1 : (n == 1) ? point2 : point3; } + void getInfo(String arr[]) { arr[0] = "analog switch"; arr[1] = open ? "open" : "closed"; @@ -116,6 +134,7 @@ void getInfo(String arr[]) { arr[3] = "I = " + getCurrentDText(getCurrent()); arr[4] = "Vc = " + getVoltageText(volts[2]); } + // we have to just assume current will flow either way, even though that // might cause singular matrix errors boolean getConnection(int n1, int n2) { @@ -123,11 +142,11 @@ boolean getConnection(int n1, int n2) { return false; return true; } + public EditInfo getEditInfo(int n) { if (n == 0) { EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Normally closed", - (flags & FLAG_INVERT) != 0); + ei.checkbox = new Checkbox("Normally closed", (flags & FLAG_INVERT) != 0); return ei; } if (n == 1) @@ -136,23 +155,21 @@ public EditInfo getEditInfo(int n) { return new EditInfo("Off Resistance (ohms)", r_off, 0, 0); return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) - flags = (ei.checkbox.getState()) ? - (flags | FLAG_INVERT) : - (flags & ~FLAG_INVERT); + flags = (ei.checkbox.getState()) ? (flags | FLAG_INVERT) : (flags & ~FLAG_INVERT); if (n == 1 && ei.value > 0) r_on = ei.value; if (n == 2 && ei.value > 0) r_off = ei.value; } - + double getCurrentIntoNode(int n) { - if (n==2) + if (n == 2) return 0; - if (n==0) + if (n == 0) return -current; return current; - } + } } - diff --git a/src/com/lushprojects/circuitjs1/client/AndGateElm.java b/src/com/lushprojects/circuitjs1/client/AndGateElm.java index dc199167..572326ae 100644 --- a/src/com/lushprojects/circuitjs1/client/AndGateElm.java +++ b/src/com/lushprojects/circuitjs1/client/AndGateElm.java @@ -21,68 +21,83 @@ import com.google.gwt.canvas.dom.client.Context2d; - class AndGateElm extends GateElm { - public AndGateElm(int xx, int yy) { super(xx, yy); } - public AndGateElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - } - - String getGateText() { return "&"; } - - public final native void ellipse(Context2d g, double x, double y, double rx, double ry, double ro, double sa, double ea, boolean ccw) /*-{ +class AndGateElm extends GateElm { + public AndGateElm(int xx, int yy) { + super(xx, yy); + } + + public AndGateElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + } + + String getGateText() { + return "&"; + } + + public final native void ellipse(Context2d g, double x, double y, double rx, double ry, double ro, double sa, + double ea, boolean ccw) /*-{ g.ellipse(x, y, rx, ry, ro, sa, ea, ccw); }-*/; - void drawGatePolygon(Graphics g) { - g.setLineWidth(3.0); - g.context.beginPath(); - g.context.moveTo(gatePoly.xpoints[0], gatePoly.ypoints[0]); - double ang1 = -Math.PI/2 * sign(dx); - double ang2 = Math.PI/2 * sign(dx); - boolean ccw = false; - double rx = ww; - double ry = hs2; - if (dx == 0) { - ang1 = (dy > 0) ? 0 : Math.PI; - ang2 = (dy > 0) ? Math.PI : 0; - rx = hs2; - ry = ww; - } - ellipse(g.context, gatePoly.xpoints[2], gatePoly.ypoints[2], rx, ry, 0, ang1, ang2, ccw); - g.context.lineTo(gatePoly.xpoints[4], gatePoly.ypoints[4]); - g.context.closePath(); - g.context.stroke(); - g.setLineWidth(1.0); + void drawGatePolygon(Graphics g) { + g.setLineWidth(3.0); + g.context.beginPath(); + g.context.moveTo(gatePoly.xpoints[0], gatePoly.ypoints[0]); + double ang1 = -Math.PI / 2 * sign(dx); + double ang2 = Math.PI / 2 * sign(dx); + boolean ccw = false; + double rx = ww; + double ry = hs2; + if (dx == 0) { + ang1 = (dy > 0) ? 0 : Math.PI; + ang2 = (dy > 0) ? Math.PI : 0; + rx = hs2; + ry = ww; } - - void setPoints() { - super.setPoints(); - - if (useEuroGates()) { - createEuroGatePolygon(); - } else { - // 0=topleft, 1 = top of curve, 2 = center, 3=bottom of curve, - // 4 = bottom left - Point triPoints[] = newPointArray(5); - interpPoint2(lead1, lead2, triPoints[0], triPoints[4], 0, hs2); - interpPoint2(lead1, lead2, triPoints[1], triPoints[3], .5, hs2); - interpPoint(lead1, lead2, triPoints[2], .5); - gatePoly = createPolygon(triPoints); - } - if (isInverting()) { - pcircle = interpPoint(point1, point2, .5+(ww+4)/dn); - lead2 = interpPoint(point1, point2, .5+(ww+8)/dn); - } + ellipse(g.context, gatePoly.xpoints[2], gatePoly.ypoints[2], rx, ry, 0, ang1, ang2, ccw); + g.context.lineTo(gatePoly.xpoints[4], gatePoly.ypoints[4]); + g.context.closePath(); + g.context.stroke(); + g.setLineWidth(1.0); + } + + void setPoints() { + super.setPoints(); + + if (useEuroGates()) { + createEuroGatePolygon(); + } else { + // 0=topleft, 1 = top of curve, 2 = center, 3=bottom of curve, + // 4 = bottom left + Point triPoints[] = newPointArray(5); + interpPoint2(lead1, lead2, triPoints[0], triPoints[4], 0, hs2); + interpPoint2(lead1, lead2, triPoints[1], triPoints[3], .5, hs2); + interpPoint(lead1, lead2, triPoints[2], .5); + gatePoly = createPolygon(triPoints); } - String getGateName() { return "AND gate"; } - boolean calcFunction() { - int i; - boolean f = true; - for (i = 0; i != inputCount; i++) - f &= getInput(i); - return f; + if (isInverting()) { + pcircle = interpPoint(point1, point2, .5 + (ww + 4) / dn); + lead2 = interpPoint(point1, point2, .5 + (ww + 8) / dn); } - int getDumpType() { return 150; } - int getShortcut() { return '2'; } } + + String getGateName() { + return "AND gate"; + } + + boolean calcFunction() { + int i; + boolean f = true; + for (i = 0; i != inputCount; i++) + f &= getInput(i); + return f; + } + + int getDumpType() { + return 150; + } + + int getShortcut() { + return '2'; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/AntennaElm.java b/src/com/lushprojects/circuitjs1/client/AntennaElm.java index 9f29234d..f5a2c9d5 100644 --- a/src/com/lushprojects/circuitjs1/client/AntennaElm.java +++ b/src/com/lushprojects/circuitjs1/client/AntennaElm.java @@ -19,39 +19,47 @@ package com.lushprojects.circuitjs1.client; - class AntennaElm extends RailElm { - public AntennaElm(int xx, int yy) { super(xx, yy, WF_AC); } - public AntennaElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - waveform = WF_AC; - } - double fmphase; - - void drawRail(Graphics g) { - drawRailText(g, "Ant"); - } - - double getVoltage() { - double fm = 3*Math.sin(fmphase); - return Math.sin(2*pi*sim.t*3000)*(1.3+Math.sin(2*pi*sim.t*12))*3 + - Math.sin(2*pi*sim.t*2710)*(1.3+Math.sin(2*pi*sim.t*13))*3 + - Math.sin(2*pi*sim.t*2433)*(1.3+Math.sin(2*pi*sim.t*14))*3 + fm; - } - - void stepFinished() { - fmphase += 2*pi*(2200+Math.sin(2*pi*sim.t*13)*100)*sim.timeStep; - } - - int getDumpType() { return 'A'; } - int getShortcut() { return 0; } - - void getInfo(String arr[]) { - super.getInfo(arr); - arr[0] = "Antenna (amplified)"; - } - - public EditInfo getEditInfo(int n) { - return null; - } +class AntennaElm extends RailElm { + public AntennaElm(int xx, int yy) { + super(xx, yy, WF_AC); } + + public AntennaElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + waveform = WF_AC; + } + + double fmphase; + + void drawRail(Graphics g) { + drawRailText(g, "Ant"); + } + + double getVoltage() { + double fm = 3 * Math.sin(fmphase); + return Math.sin(2 * pi * sim.t * 3000) * (1.3 + Math.sin(2 * pi * sim.t * 12)) * 3 + + Math.sin(2 * pi * sim.t * 2710) * (1.3 + Math.sin(2 * pi * sim.t * 13)) * 3 + + Math.sin(2 * pi * sim.t * 2433) * (1.3 + Math.sin(2 * pi * sim.t * 14)) * 3 + fm; + } + + void stepFinished() { + fmphase += 2 * pi * (2200 + Math.sin(2 * pi * sim.t * 13) * 100) * sim.timeStep; + } + + int getDumpType() { + return 'A'; + } + + int getShortcut() { + return 0; + } + + void getInfo(String arr[]) { + super.getInfo(arr); + arr[0] = "Antenna (amplified)"; + } + + public EditInfo getEditInfo(int n) { + return null; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/AudioInputElm.java b/src/com/lushprojects/circuitjs1/client/AudioInputElm.java index c35442b5..3b85bd6d 100644 --- a/src/com/lushprojects/circuitjs1/client/AudioInputElm.java +++ b/src/com/lushprojects/circuitjs1/client/AudioInputElm.java @@ -32,123 +32,128 @@ class AudioFileEntry { } class AudioInputElm extends RailElm { - JsArrayNumber data; - double timeOffset; - int samplingRate; - int fileNum; - String fileName; - double maxVoltage; - double startPosition; - - static int lastSamplingRate; - - // cache to preserve audio data when doing cut/paste, or undo/redo - static int fileNumCounter = 1; - static HashMap audioFileMap = new HashMap(); - - public AudioInputElm(int xx, int yy) { - super(xx, yy, WF_AC); - maxVoltage = 5; - } - - public AudioInputElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - waveform = WF_AC; - maxVoltage = Double.parseDouble(st.nextToken()); - startPosition = Double.parseDouble(st.nextToken()); - fileNum = Integer.parseInt(st.nextToken()); - - AudioFileEntry ent = audioFileMap.get(fileNum); - if (ent != null) { - fileName = ent.fileName; - data = ent.data; - } - samplingRate = lastSamplingRate; + JsArrayNumber data; + double timeOffset; + int samplingRate; + int fileNum; + String fileName; + double maxVoltage; + double startPosition; + + static int lastSamplingRate; + + // cache to preserve audio data when doing cut/paste, or undo/redo + static int fileNumCounter = 1; + static HashMap audioFileMap = new HashMap(); + + public AudioInputElm(int xx, int yy) { + super(xx, yy, WF_AC); + maxVoltage = 5; + } + + public AudioInputElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + waveform = WF_AC; + maxVoltage = Double.parseDouble(st.nextToken()); + startPosition = Double.parseDouble(st.nextToken()); + fileNum = Integer.parseInt(st.nextToken()); + + AudioFileEntry ent = audioFileMap.get(fileNum); + if (ent != null) { + fileName = ent.fileName; + data = ent.data; } - - double fmphase; - - String dump() { - // add a file number to the dump so we can preserve the audio file data when doing cut and paste, or undo/redo. - // we don't save the entire file in the dump because it would be huge. - if (data != null) { - if (fileNum == 0) - fileNum = fileNumCounter++; - AudioFileEntry ent = new AudioFileEntry(); - ent.fileName = fileName; - ent.data = data; - audioFileMap.put(fileNum, ent); - } - return super.dump() + " " + maxVoltage + " " + startPosition + " " + fileNum; + samplingRate = lastSamplingRate; + } + + double fmphase; + + String dump() { + // add a file number to the dump so we can preserve the audio file data when + // doing cut and paste, or undo/redo. + // we don't save the entire file in the dump because it would be huge. + if (data != null) { + if (fileNum == 0) + fileNum = fileNumCounter++; + AudioFileEntry ent = new AudioFileEntry(); + ent.fileName = fileName; + ent.data = data; + audioFileMap.put(fileNum, ent); } - - void reset() { + return super.dump() + " " + maxVoltage + " " + startPosition + " " + fileNum; + } + + void reset() { + timeOffset = startPosition; + } + + void drawRail(Graphics g) { + drawRailText(g, fileName == null ? "No file" : fileName); + } + + String getRailText() { + return fileName == null ? "No file" : fileName; + } + + void setSamplingRate(int sr) { + samplingRate = sr; + } + + double getVoltage() { + if (data == null) + return 0; + if (timeOffset < startPosition) timeOffset = startPosition; + int ptr = (int) (timeOffset * samplingRate); + if (ptr >= data.length()) { + ptr = 0; + timeOffset = 0; } - - void drawRail(Graphics g) { - drawRailText(g, fileName == null ? "No file" : fileName); - } - - String getRailText() { - return fileName == null ? "No file" : fileName; - } - - void setSamplingRate(int sr) { - samplingRate = sr; - } - - double getVoltage() { - if (data == null) - return 0; - if (timeOffset < startPosition) - timeOffset = startPosition; - int ptr = (int) (timeOffset * samplingRate); - if (ptr >= data.length()) { - ptr = 0; - timeOffset = 0; - } - return data.get(ptr) * maxVoltage; - } - - void stepFinished() { - timeOffset += sim.timeStep; - } - - int getDumpType() { return 411; } - int getShortcut() { return 0; } - - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - final AudioInputElm thisElm = this; - final FileUpload file = new FileUpload(); - ei.widget = file; - file.addChangeHandler(new ChangeHandler() { - public void onChange(ChangeEvent event) { - fileName = file.getFilename().replaceAll("^.*\\\\", "").replaceAll("\\.[^.]*$", ""); - AudioInputElm.fetchLoadFileData(thisElm, file.getElement()); - } - }); - return ei; - } - if (n == 1) - return new EditInfo("Max Voltage", maxVoltage); - if (n == 2) - return new EditInfo("Start Position (s)", startPosition); - return null; - } - - public void setEditValue(int n, EditInfo ei) { - if (n == 1) - maxVoltage = ei.value; - if (n == 2) - startPosition = ei.value; + return data.get(ptr) * maxVoltage; + } + + void stepFinished() { + timeOffset += sim.timeStep; + } + + int getDumpType() { + return 411; + } + + int getShortcut() { + return 0; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + final AudioInputElm thisElm = this; + final FileUpload file = new FileUpload(); + ei.widget = file; + file.addChangeHandler(new ChangeHandler() { + public void onChange(ChangeEvent event) { + fileName = file.getFilename().replaceAll("^.*\\\\", "").replaceAll("\\.[^.]*$", ""); + AudioInputElm.fetchLoadFileData(thisElm, file.getElement()); + } + }); + return ei; } - - // fetch audio data for a selected file - static native String fetchLoadFileData(AudioInputElm elm, Element uploadElement) /*-{ + if (n == 1) + return new EditInfo("Max Voltage", maxVoltage); + if (n == 2) + return new EditInfo("Start Position (s)", startPosition); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 1) + maxVoltage = ei.value; + if (n == 2) + startPosition = ei.value; + } + + // fetch audio data for a selected file + static native String fetchLoadFileData(AudioInputElm elm, Element uploadElement) /*-{ var oFiles = uploadElement.files; var context = new (window.AudioContext || window.webkitAudioContext)(); elm.@com.lushprojects.circuitjs1.client.AudioInputElm::setSamplingRate(I)(context.sampleRate); @@ -165,26 +170,26 @@ static native String fetchLoadFileData(AudioInputElm elm, Element uploadElement) reader.readAsArrayBuffer(oFiles[0]); } }-*/; - - void gotAudioData(JsArrayNumber d) { - data = d; - lastSamplingRate = samplingRate; - AudioOutputElm.lastSamplingRate = samplingRate; - } - void getInfo(String arr[]) { - arr[0] = "audio input"; - if (data == null) { - arr[1] = "no file loaded"; - return; - } - arr[1] = "V = " + getVoltageText(volts[0]); - arr[2] = "pos = " + getUnitText(timeOffset, "s"); - double dur = data.length() / (double)samplingRate; - arr[3] = "dur = " + getUnitText(dur, "s"); - } - - public static void clearCache() { - audioFileMap.clear(); + void gotAudioData(JsArrayNumber d) { + data = d; + lastSamplingRate = samplingRate; + AudioOutputElm.lastSamplingRate = samplingRate; + } + + void getInfo(String arr[]) { + arr[0] = "audio input"; + if (data == null) { + arr[1] = "no file loaded"; + return; } + arr[1] = "V = " + getVoltageText(volts[0]); + arr[2] = "pos = " + getUnitText(timeOffset, "s"); + double dur = data.length() / (double) samplingRate; + arr[3] = "dur = " + getUnitText(dur, "s"); } + + public static void clearCache() { + audioFileMap.clear(); + } +} diff --git a/src/com/lushprojects/circuitjs1/client/AudioOutputElm.java b/src/com/lushprojects/circuitjs1/client/AudioOutputElm.java index 3a5be31c..6192a5cc 100644 --- a/src/com/lushprojects/circuitjs1/client/AudioOutputElm.java +++ b/src/com/lushprojects/circuitjs1/client/AudioOutputElm.java @@ -23,372 +23,387 @@ public class AudioOutputElm extends CircuitElm { double dataStart; static int lastSamplingRate = 8000; static boolean okToChangeTimeStep; - - public AudioOutputElm(int xx, int yy) { - super(xx, yy); - duration = 1; - samplingRate = lastSamplingRate; - labelNum = getNextLabelNum(); - setDataCount(); - createButton(); - } - public AudioOutputElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - duration = Double.parseDouble(st.nextToken()); - samplingRate = Integer.parseInt(st.nextToken()); - labelNum = Integer.parseInt(st.nextToken()); - setDataCount(); - createButton(); - } - String dump() { - return super.dump() + " " + duration + " " + samplingRate + " " + labelNum; - } - - void draggingDone() { - setTimeStep(); - } - - // get next unused labelNum value - int getNextLabelNum() { - int i; - int num = 1; - if (sim.elmList == null) - return 0; - for (i = 0; i != sim.elmList.size(); i++) { - CircuitElm ce = sim.getElm(i); - if (!(ce instanceof AudioOutputElm)) - continue; - int ln = ((AudioOutputElm)ce).labelNum; - if (ln >= num) - num = ln+1; - } - return num; + + public AudioOutputElm(int xx, int yy) { + super(xx, yy); + duration = 1; + samplingRate = lastSamplingRate; + labelNum = getNextLabelNum(); + setDataCount(); + createButton(); + } + + public AudioOutputElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + duration = Double.parseDouble(st.nextToken()); + samplingRate = Integer.parseInt(st.nextToken()); + labelNum = Integer.parseInt(st.nextToken()); + setDataCount(); + createButton(); + } + + String dump() { + return super.dump() + " " + duration + " " + samplingRate + " " + labelNum; + } + + void draggingDone() { + setTimeStep(); + } + + // get next unused labelNum value + int getNextLabelNum() { + int i; + int num = 1; + if (sim.elmList == null) + return 0; + for (i = 0; i != sim.elmList.size(); i++) { + CircuitElm ce = sim.getElm(i); + if (!(ce instanceof AudioOutputElm)) + continue; + int ln = ((AudioOutputElm) ce).labelNum; + if (ln >= num) + num = ln + 1; } - - int getDumpType() { return 211; } - int getPostCount() { return 1; } - void reset() { - dataPtr = 0; - dataFull = false; + return num; + } + + int getDumpType() { + return 211; + } + + int getPostCount() { + return 1; + } + + void reset() { + dataPtr = 0; + dataFull = false; + dataSampleCount = 0; + nextDataSample = 0; + dataSample = 0; + } + + void setPoints() { + super.setPoints(); + lead1 = new Point(); + } + + void draw(Graphics g) { + g.save(); + boolean selected = (needsHighlight()); + Font f = new Font("SansSerif", selected ? Font.BOLD : 0, 14); + String s = "Audio Out"; + if (labelNum > 1) + s = "Audio " + labelNum; + g.setFont(f); + int textWidth = (int) g.context.measureText(s).getWidth(); + g.setColor(Color.darkGray); + int pct = (dataFull) ? textWidth : textWidth * dataPtr / dataCount; + g.fillRect(x2 - textWidth / 2, y2 - 10, pct, 20); + g.setColor(selected ? selectColor : whiteColor); + interpPoint(point1, point2, lead1, 1 - (textWidth / 2. + 8) / dn); + setBbox(point1, lead1, 0); + drawCenteredText(g, s, x2, y2, true); + setVoltageColor(g, volts[0]); + if (selected) + g.setColor(selectColor); + drawThickLine(g, point1, lead1); + drawPosts(g); + g.restore(); + } + + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "audio output"; + arr[1] = "V = " + getVoltageText(volts[0]); + int ct = (dataFull ? dataCount : dataPtr); + double dur = sampleStep * ct; + arr[2] = "start = " + getUnitText(dataFull ? sim.t - duration : dataStart, "s"); + arr[3] = "dur = " + getUnitText(dur, "s"); + arr[4] = "samples = " + ct + (dataFull ? "" : "/" + dataCount); + } + + int dataSampleCount = 0; + double nextDataSample = 0; + double dataSample; + + void stepFinished() { + dataSample += volts[0]; + dataSampleCount++; + if (sim.t >= nextDataSample) { + nextDataSample += sampleStep; + data[dataPtr++] = dataSample / dataSampleCount; dataSampleCount = 0; - nextDataSample = 0; dataSample = 0; + if (dataPtr >= dataCount) { + dataPtr = 0; + dataFull = true; + } } - void setPoints() { - super.setPoints(); - lead1 = new Point(); - } - void draw(Graphics g) { - g.save(); - boolean selected = (needsHighlight()); - Font f = new Font("SansSerif", selected ? Font.BOLD : 0, 14); - String s = "Audio Out"; - if (labelNum > 1) - s = "Audio " + labelNum; - g.setFont(f); - int textWidth = (int)g.context.measureText(s).getWidth(); - g.setColor(Color.darkGray); - int pct = (dataFull) ? textWidth : textWidth*dataPtr/dataCount; - g.fillRect(x2-textWidth/2, y2-10, pct, 20); - g.setColor(selected ? selectColor : whiteColor); - interpPoint(point1, point2, lead1, 1-(textWidth/2.+8)/dn); - setBbox(point1, lead1, 0); - drawCenteredText(g, s, x2, y2, true); - setVoltageColor(g, volts[0]); - if (selected) - g.setColor(selectColor); - drawThickLine(g, point1, lead1); - drawPosts(g); - g.restore(); - } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = "audio output"; - arr[1] = "V = " + getVoltageText(volts[0]); - int ct = (dataFull ? dataCount : dataPtr); - double dur = sampleStep * ct; - arr[2] = "start = " + getUnitText(dataFull ? sim.t-duration : dataStart, "s"); - arr[3] = "dur = " + getUnitText(dur, "s"); - arr[4] = "samples = " + ct + (dataFull ? "" : "/" + dataCount); + } + + void setDataCount() { + dataCount = (int) (samplingRate * duration); + data = new double[dataCount]; + dataStart = sim.t; + dataPtr = 0; + dataFull = false; + sampleStep = 1. / samplingRate; + nextDataSample = sim.t + sampleStep; + } + + int samplingRateChoices[] = { 8000, 11025, 16000, 22050, 44100, 48000 }; + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("Duration (s)", duration, 0, 5); + return ei; } - - int dataSampleCount = 0; - double nextDataSample = 0; - double dataSample; - - void stepFinished() { - dataSample += volts[0]; - dataSampleCount++; - if (sim.t >= nextDataSample) { - nextDataSample += sampleStep; - data[dataPtr++] = dataSample/dataSampleCount; - dataSampleCount = 0; - dataSample = 0; - if (dataPtr >= dataCount) { - dataPtr = 0; - dataFull = true; - } + if (n == 1) { + EditInfo ei = new EditInfo("Sampling Rate", 0, -1, -1); + ei.choice = new Choice(); + int i; + for (i = 0; i != samplingRateChoices.length; i++) { + ei.choice.add(samplingRateChoices[i] + ""); + if (samplingRateChoices[i] == samplingRate) + ei.choice.select(i); } + return ei; } - - void setDataCount() { - dataCount = (int) (samplingRate * duration); - data = new double[dataCount]; - dataStart = sim.t; - dataPtr = 0; - dataFull = false; - sampleStep = 1./samplingRate; - nextDataSample = sim.t+sampleStep; + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + String url = getLastBlob(); + if (url == null) + return null; + Date date = new Date(); + DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); + String fname = "audio-" + dtf.format(date) + ".circuitjs.wav"; + Anchor a = new Anchor(Locale.LS("Download last played audio"), url); + a.getElement().setAttribute("Download", fname); + ei.widget = a; + return ei; } - - int samplingRateChoices[] = { 8000, 11025, 16000, 22050, 44100, 48000 }; - - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("Duration (s)", duration, 0, 5); - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("Sampling Rate", 0, -1, -1); - ei.choice = new Choice(); - int i; - for (i = 0; i != samplingRateChoices.length; i++) { - ei.choice.add(samplingRateChoices[i] + ""); - if (samplingRateChoices[i] == samplingRate) - ei.choice.select(i); - } - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - String url=getLastBlob(); - if (url == null) - return null; - Date date = new Date(); - DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); - String fname = "audio-"+ dtf.format(date) + ".circuitjs.wav"; - Anchor a=new Anchor(Locale.LS("Download last played audio"), url); - a.getElement().setAttribute("Download", fname); - ei.widget = a; - return ei; - } - - return null; + + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) { + duration = ei.value; + setDataCount(); } - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) { - duration = ei.value; + if (n == 1) { + int nsr = samplingRateChoices[ei.choice.getSelectedIndex()]; + if (nsr != samplingRate) { + samplingRate = nsr; + lastSamplingRate = nsr; setDataCount(); - } - if (n == 1) { - int nsr = samplingRateChoices[ei.choice.getSelectedIndex()]; - if (nsr != samplingRate) { - samplingRate = nsr; - lastSamplingRate = nsr; - setDataCount(); - setTimeStep(); - } + setTimeStep(); } } - - void setTimeStep() { - /* - // timestep must be smaller than 1/sampleRate - if (sim.timeStep > sampleStep) - sim.timeStep = sampleStep; - else { - // make sure sampleStep/timeStep is an integer. otherwise we get distortion -// int frac = (int)Math.round(sampleStep/sim.timeStep); -// sim.timeStep = sampleStep / frac; - - // actually, just make timestep = 1/sampleRate - sim.timeStep = sampleStep; - } - */ - -// int frac = (int)Math.round(Math.max(sampleStep*33000, 1)); - double target = sampleStep/8; - if (sim.maxTimeStep != target) { - if (okToChangeTimeStep || Window.confirm(Locale.LS("Adjust timestep for best audio quality and performance?"))) { - sim.maxTimeStep = target; - okToChangeTimeStep = true; - } + } + + void setTimeStep() { + /* + * // timestep must be smaller than 1/sampleRate if (sim.timeStep > sampleStep) + * sim.timeStep = sampleStep; else { // make sure sampleStep/timeStep is an + * integer. otherwise we get distortion // int frac = + * (int)Math.round(sampleStep/sim.timeStep); // sim.timeStep = sampleStep / + * frac; + * + * // actually, just make timestep = 1/sampleRate sim.timeStep = sampleStep; } + */ + + // int frac = (int)Math.round(Math.max(sampleStep*33000, 1)); + double target = sampleStep / 8; + if (sim.maxTimeStep != target) { + if (okToChangeTimeStep + || Window.confirm(Locale.LS("Adjust timestep for best audio quality and performance?"))) { + sim.maxTimeStep = target; + okToChangeTimeStep = true; } } - - void createButton() { - String label = "▶ " + Locale.LS("Play Audio"); - if (labelNum > 1) - label += " " + labelNum; - sim.addWidgetToVerticalPanel(button = new Button(label)); - button.setStylePrimaryName("topButton"); - button.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - play(); - } - }); - - } - void delete() { - sim.removeWidgetFromVerticalPanel(button); - super.delete(); - } - - public static native void playJS(JsArrayInteger samples, int sampleRate) - /*-{ - var Wav = function(opt_params){ - this._sampleRate = opt_params && opt_params.sampleRate ? opt_params.sampleRate : 44100; - this._channels = opt_params && opt_params.channels ? opt_params.channels : 2; - this._eof = true; - this._bufferNeedle = 0; - this._buffer; - - }; - - Wav.prototype.setBuffer = function(buffer){ - this._buffer = this.getWavInt16Array(buffer); - this._bufferNeedle = 0; - this._internalBuffer = ''; - this._hasOutputHeader = false; - this._eof = false; - }; - - Wav.prototype.getBuffer = function(len){ - - var rt; - if( this._bufferNeedle + len >= this._buffer.length ){ - rt = new Int16Array(this._buffer.length - this._bufferNeedle); - this._eof = true; - } - else { - rt = new Int16Array(len); - } - - for(var i=0; i> 16; // RIFF size - - intBuffer[4] = 0x4157; // "WA" - intBuffer[5] = 0x4556; // "VE" - - intBuffer[6] = 0x6d66; // "fm" - intBuffer[7] = 0x2074; // "t " - - intBuffer[8] = 0x0012; // fmt chunksize: 18 - intBuffer[9] = 0x0000; // - - intBuffer[10] = 0x0001; // format tag : 1 - intBuffer[11] = this._channels; // channels: 2 - - intBuffer[12] = this._sampleRate & 0x0000ffff; // sample per sec - intBuffer[13] = (this._sampleRate & 0xffff0000) >> 16; // sample per sec - - intBuffer[14] = (2*this._channels*this._sampleRate) & 0x0000ffff; // byte per sec - intBuffer[15] = ((2*this._channels*this._sampleRate) & 0xffff0000) >> 16; // byte per sec - - intBuffer[16] = 0x0004; // block align - intBuffer[17] = 0x0010; // bit per sample - intBuffer[18] = 0x0000; // cb size - intBuffer[19] = 0x6164; // "da" - intBuffer[20] = 0x6174; // "ta" - intBuffer[21] = (2*buffer.length) & 0x0000ffff; // data size[byte] - intBuffer[22] = ((2*buffer.length) & 0xffff0000) >> 16; // data size[byte] - - for (var i = 0; i < buffer.length; i++) - intBuffer[i+23] = buffer[i]; - - return intBuffer; - }; - var i=0, - wav = new Wav({sampleRate: sampleRate, channels: 1}); - wav.setBuffer(samples); - - var srclist = []; - while( !wav.eof() ){ - srclist.push(wav.getBuffer(1000)); - } - - var oldblob = $doc.audioBlob; - var oldobj = $doc.audioObject; - // remove old blob and audio obj if any. We should do this when audio is done playing, but this is easier - if (oldblob) { - oldobj.parentNode.removeChild(oldobj); - URL.revokeObjectURL(oldblob); - } + } + + void createButton() { + String label = "▶ " + Locale.LS("Play Audio"); + if (labelNum > 1) + label += " " + labelNum; + sim.addWidgetToVerticalPanel(button = new Button(label)); + button.setStylePrimaryName("topButton"); + button.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + play(); + } + }); + + } - var b = new Blob(srclist, {type:'audio/wav'}); -// var URLObject = $wnd.webkitURL || $wnd.URL; -// var url = URLObject.createObjectURL(b); - var url = URL.createObjectURL(b); - $doc.audioBlob = url; -// console.log(url); - var audio = $doc.createElement("audio"); - $doc.audioObject = audio; - audio.src = url; - $doc.body.appendChild(audio); - audio.play(); -}-*/; - - static native String getLastBlob() /*-{ + void delete() { + sim.removeWidgetFromVerticalPanel(button); + super.delete(); + } + + public static native void playJS(JsArrayInteger samples, int sampleRate) + /*-{ + var Wav = function(opt_params){ + this._sampleRate = opt_params && opt_params.sampleRate ? opt_params.sampleRate : 44100; + this._channels = opt_params && opt_params.channels ? opt_params.channels : 2; + this._eof = true; + this._bufferNeedle = 0; + this._buffer; + + }; + + Wav.prototype.setBuffer = function(buffer){ + this._buffer = this.getWavInt16Array(buffer); + this._bufferNeedle = 0; + this._internalBuffer = ''; + this._hasOutputHeader = false; + this._eof = false; + }; + + Wav.prototype.getBuffer = function(len){ + + var rt; + if( this._bufferNeedle + len >= this._buffer.length ){ + rt = new Int16Array(this._buffer.length - this._bufferNeedle); + this._eof = true; + } + else { + rt = new Int16Array(len); + } + + for(var i=0; i> 16; // RIFF size + + intBuffer[4] = 0x4157; // "WA" + intBuffer[5] = 0x4556; // "VE" + + intBuffer[6] = 0x6d66; // "fm" + intBuffer[7] = 0x2074; // "t " + + intBuffer[8] = 0x0012; // fmt chunksize: 18 + intBuffer[9] = 0x0000; // + + intBuffer[10] = 0x0001; // format tag : 1 + intBuffer[11] = this._channels; // channels: 2 + + intBuffer[12] = this._sampleRate & 0x0000ffff; // sample per sec + intBuffer[13] = (this._sampleRate & 0xffff0000) >> 16; // sample per sec + + intBuffer[14] = (2*this._channels*this._sampleRate) & 0x0000ffff; // byte per sec + intBuffer[15] = ((2*this._channels*this._sampleRate) & 0xffff0000) >> 16; // byte per sec + + intBuffer[16] = 0x0004; // block align + intBuffer[17] = 0x0010; // bit per sample + intBuffer[18] = 0x0000; // cb size + intBuffer[19] = 0x6164; // "da" + intBuffer[20] = 0x6174; // "ta" + intBuffer[21] = (2*buffer.length) & 0x0000ffff; // data size[byte] + intBuffer[22] = ((2*buffer.length) & 0xffff0000) >> 16; // data size[byte] + + for (var i = 0; i < buffer.length; i++) + intBuffer[i+23] = buffer[i]; + + return intBuffer; + }; + var i=0, + wav = new Wav({sampleRate: sampleRate, channels: 1}); + wav.setBuffer(samples); + + var srclist = []; + while( !wav.eof() ){ + srclist.push(wav.getBuffer(1000)); + } + + var oldblob = $doc.audioBlob; + var oldobj = $doc.audioObject; + // remove old blob and audio obj if any. We should do this when audio is done playing, but this is easier + if (oldblob) { + oldobj.parentNode.removeChild(oldobj); + URL.revokeObjectURL(oldblob); + } + + var b = new Blob(srclist, {type:'audio/wav'}); + // var URLObject = $wnd.webkitURL || $wnd.URL; + // var url = URLObject.createObjectURL(b); + var url = URL.createObjectURL(b); + $doc.audioBlob = url; + // console.log(url); + var audio = $doc.createElement("audio"); + $doc.audioObject = audio; + audio.src = url; + $doc.body.appendChild(audio); + audio.play(); + }-*/; + + static native String getLastBlob() /*-{ return $doc.audioBlob; }-*/; - - void play() { - int i; - JsArrayInteger arr = (JsArrayInteger)JsArrayInteger.createArray(); - int ct = dataPtr; - int base = 0; - if (dataFull) { - ct = dataCount; - base = dataPtr; - } - if (ct * sampleStep < .05) { - Window.alert(Locale.LS("Audio data is not ready yet. Increase simulation speed to make data ready sooner.")); - return; - } - - // rescale data to maximize - double max = -1e8; - double min = 1e8; - for (i = 0; i != ct; i++) { - if (data[i] > max) max = data[i]; - if (data[i] < min) min = data[i]; - } - - double adj = -(max+min)/2; - double mult = (.25*32766)/(max+adj); - - // fade in over 1/20 sec - int fadeLen = samplingRate/20; - int fadeOut = ct-fadeLen; - - double fadeMult = mult/fadeLen; - for (i = 0; i != ct; i++) { - double fade = (i < fadeLen) ? i*fadeMult : (i > fadeOut) ? (ct-i)*fadeMult : mult; - int s = (int)((data[(i+base)%dataCount]+adj)*fade); - arr.push(s); - } - playJS(arr, samplingRate); - } + + void play() { + int i; + JsArrayInteger arr = (JsArrayInteger) JsArrayInteger.createArray(); + int ct = dataPtr; + int base = 0; + if (dataFull) { + ct = dataCount; + base = dataPtr; + } + if (ct * sampleStep < .05) { + Window.alert( + Locale.LS("Audio data is not ready yet. Increase simulation speed to make data ready sooner.")); + return; + } + + // rescale data to maximize + double max = -1e8; + double min = 1e8; + for (i = 0; i != ct; i++) { + if (data[i] > max) + max = data[i]; + if (data[i] < min) + min = data[i]; + } + + double adj = -(max + min) / 2; + double mult = (.25 * 32766) / (max + adj); + + // fade in over 1/20 sec + int fadeLen = samplingRate / 20; + int fadeOut = ct - fadeLen; + + double fadeMult = mult / fadeLen; + for (i = 0; i != ct; i++) { + double fade = (i < fadeLen) ? i * fadeMult : (i > fadeOut) ? (ct - i) * fadeMult : mult; + int s = (int) ((data[(i + base) % dataCount] + adj) * fade); + arr.push(s); + } + playJS(arr, samplingRate); + } } diff --git a/src/com/lushprojects/circuitjs1/client/BoxElm.java b/src/com/lushprojects/circuitjs1/client/BoxElm.java index 8d1368be..020d76b0 100644 --- a/src/com/lushprojects/circuitjs1/client/BoxElm.java +++ b/src/com/lushprojects/circuitjs1/client/BoxElm.java @@ -28,8 +28,7 @@ public BoxElm(int xx, int yy) { setBbox(x, y, x2, y2); } - public BoxElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + public BoxElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); x2 = xb; y2 = yb; @@ -40,7 +39,9 @@ String dump() { return super.dump(); } - int getDumpType() { return 'b'; } + int getDumpType() { + return 'b'; + } void drag(int xx, int yy) { x2 = xx; @@ -48,22 +49,22 @@ void drag(int xx, int yy) { } boolean creationFailed() { - return Math.abs(x2-x) < 32 || Math.abs(y2-y) < 32; + return Math.abs(x2 - x) < 32 || Math.abs(y2 - y) < 32; } - + void draw(Graphics g) { - //g.setColor(needsHighlight() ? selectColor : lightGrayColor); + // g.setColor(needsHighlight() ? selectColor : lightGrayColor); g.setColor(needsHighlight() ? selectColor : Color.GRAY); setBbox(x, y, x2, y2); g.setLineDash(16, 6); - if ( x < x2 && y < y2 ) - g.drawRect(x,y, x2-x, y2-y); - else if ( x > x2 && y < y2 ) - g.drawRect(x2,y, x-x2, y2-y); - else if ( x < x2 && y > y2 ) - g.drawRect(x, y2, x2-x, y-y2); + if (x < x2 && y < y2) + g.drawRect(x, y, x2 - x, y2 - y); + else if (x > x2 && y < y2) + g.drawRect(x2, y, x - x2, y2 - y); + else if (x < x2 && y > y2) + g.drawRect(x, y2, x2 - x, y - y2); else - g.drawRect(x2, y2, x-x2, y-y2); + g.drawRect(x2, y2, x - x2, y - y2); g.setLineDash(0, 0); } @@ -78,6 +79,7 @@ void getInfo(String arr[]) { } @Override - int getShortcut() { return 0; } + int getShortcut() { + return 0; + } } - diff --git a/src/com/lushprojects/circuitjs1/client/CC2Elm.java b/src/com/lushprojects/circuitjs1/client/CC2Elm.java index 0f853f0a..328923d7 100644 --- a/src/com/lushprojects/circuitjs1/client/CC2Elm.java +++ b/src/com/lushprojects/circuitjs1/client/CC2Elm.java @@ -19,56 +19,91 @@ package com.lushprojects.circuitjs1.client; - class CC2Elm extends ChipElm { - double gain; - public CC2Elm(int xx, int yy) { super(xx, yy); gain = 1; } - public CC2Elm(int xx, int yy, int g) { super(xx, yy); gain = g; } - public CC2Elm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - gain = new Double(st.nextToken()).doubleValue(); - } - String dump() { - return super.dump() + " " + gain; - } - String getChipName() { return "CC2"; } - void setupPins() { - sizeX = 2; - sizeY = 3; - pins = new Pin[3]; - pins[0] = new Pin(0, SIDE_W, "X"); - pins[0].output = true; - pins[1] = new Pin(2, SIDE_W, "Y"); - pins[2] = new Pin(1, SIDE_E, "Z"); - } - void getInfo(String arr[]) { - arr[0] = (gain == 1) ? "CCII+~" : "CCII-~"; // ~ is for localization - arr[1] = "X,Y = " + getVoltageText(volts[0]); - arr[2] = "Z = " + getVoltageText(volts[2]); - arr[3] = "I = " + getCurrentText(pins[0].current); - } - //boolean nonLinear() { return true; } - @Override boolean isDigitalChip() { return false; } - void stamp() { - // X voltage = Y voltage - sim.stampVoltageSource(0, nodes[0], pins[0].voltSource); - sim.stampVCVS(0, nodes[1], 1, pins[0].voltSource); - // Z current = gain * X current - sim.stampCCCS(0, nodes[2], pins[0].voltSource, gain); - } - void calculateCurrent() { - super.calculateCurrent(); - pins[2].current = pins[0].current * gain; - } - void draw(Graphics g) { - drawChip(g); - } - int getPostCount() { return 3; } - int getVoltageSourceCount() { return 1; } - int getDumpType() { return 179; } +class CC2Elm extends ChipElm { + double gain; + + public CC2Elm(int xx, int yy) { + super(xx, yy); + gain = 1; + } + + public CC2Elm(int xx, int yy, int g) { + super(xx, yy); + gain = g; + } + + public CC2Elm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + gain = Double.valueOf(st.nextToken()).doubleValue(); + } + + String dump() { + return super.dump() + " " + gain; + } + + String getChipName() { + return "CC2"; + } + + void setupPins() { + sizeX = 2; + sizeY = 3; + pins = new Pin[3]; + pins[0] = new Pin(0, SIDE_W, "X"); + pins[0].output = true; + pins[1] = new Pin(2, SIDE_W, "Y"); + pins[2] = new Pin(1, SIDE_E, "Z"); + } + + void getInfo(String arr[]) { + arr[0] = (gain == 1) ? "CCII+~" : "CCII-~"; // ~ is for localization + arr[1] = "X,Y = " + getVoltageText(volts[0]); + arr[2] = "Z = " + getVoltageText(volts[2]); + arr[3] = "I = " + getCurrentText(pins[0].current); + } + + // boolean nonLinear() { return true; } + @Override + boolean isDigitalChip() { + return false; } + void stamp() { + // X voltage = Y voltage + sim.stampVoltageSource(0, nodes[0], pins[0].voltSource); + sim.stampVCVS(0, nodes[1], 1, pins[0].voltSource); + // Z current = gain * X current + sim.stampCCCS(0, nodes[2], pins[0].voltSource, gain); + } + + void calculateCurrent() { + super.calculateCurrent(); + pins[2].current = pins[0].current * gain; + } + + void draw(Graphics g) { + drawChip(g); + } + + int getPostCount() { + return 3; + } + + int getVoltageSourceCount() { + return 1; + } + + int getDumpType() { + return 179; + } +} + class CC2NegElm extends CC2Elm { - public CC2NegElm(int xx, int yy) { super(xx, yy, -1); } - Class getDumpClass() { return CC2Elm.class; } + public CC2NegElm(int xx, int yy) { + super(xx, yy, -1); + } + + Class getDumpClass() { + return CC2Elm.class; + } } diff --git a/src/com/lushprojects/circuitjs1/client/CCCSElm.java b/src/com/lushprojects/circuitjs1/client/CCCSElm.java index acd23f32..8a27f97b 100644 --- a/src/com/lushprojects/circuitjs1/client/CCCSElm.java +++ b/src/com/lushprojects/circuitjs1/client/CCCSElm.java @@ -22,208 +22,228 @@ import java.util.Vector; class CCCSElm extends VCCSElm { - static int FLAG_SPICE = 2; - VoltageElm voltageSources[]; - - public CCCSElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); -// exprString = CustomLogicModel.unescape(st.nextToken()); -// inputCount = 2; -// parseExpr(); - setupPins(); + static int FLAG_SPICE = 2; + VoltageElm voltageSources[]; + + public CCCSElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + // exprString = CustomLogicModel.unescape(st.nextToken()); + // inputCount = 2; + // parseExpr(); + setupPins(); + } + + public CCCSElm(int xx, int yy) { + super(xx, yy); + exprString = "2*a"; + parseExpr(); + // setupPins(); + } + + int inputPairCount; + + void setupPins() { + sizeX = 2; + sizeY = inputCount > 2 ? inputCount : 2; + pins = new Pin[inputCount + 2]; + inputPairCount = inputCount / 2; + int i; + for (i = 0; i != inputPairCount; i++) { + pins[i * 2] = new Pin(i * 2, SIDE_W, Character.toString((char) ('A' + i)) + "+"); + pins[i * 2 + 1] = new Pin(i * 2 + 1, SIDE_W, Character.toString((char) ('A' + i)) + "-"); + pins[i * 2 + 1].output = true; } - public CCCSElm(int xx, int yy) { - super(xx, yy); - exprString = "2*a"; - parseExpr(); -// setupPins(); + pins[i * 2] = new Pin(0, SIDE_E, "O+"); + pins[i * 2].output = true; + pins[i * 2 + 1] = new Pin(1, SIDE_E, "O-"); + exprState = new ExprState(inputPairCount); + lastCurrents = new double[inputPairCount]; + allocNodes(); + } + + String getChipName() { + return "CCCS"; + } + + void stamp() { + int i; + if (isSpiceStyle()) { + for (i = 0; i != inputCount; i += 2) + pins[i + 1].voltSource = voltageSources[i / 2].getVoltageSource(); + } else { + // voltage sources (0V) between C+ and C- so we can measure current + for (i = 0; i != inputCount; i += 2) { + int vn1 = pins[i + 1].voltSource; + sim.stampVoltageSource(nodes[i], nodes[i + 1], vn1, 0); + } } - - int inputPairCount; - - void setupPins() { - sizeX = 2; - sizeY = inputCount > 2 ? inputCount : 2; - pins = new Pin[inputCount+2]; - inputPairCount = inputCount/2; - int i; - for (i = 0; i != inputPairCount; i++) { - pins[i*2 ] = new Pin(i*2, SIDE_W, Character.toString((char)('A'+i)) + "+"); - pins[i*2+1] = new Pin(i*2+1, SIDE_W, Character.toString((char)('A'+i)) + "-"); - pins[i*2+1].output = true; - } - pins[i*2] = new Pin(0, SIDE_E, "O+"); - pins[i*2].output = true; - pins[i*2+1] = new Pin(1, SIDE_E, "O-"); - exprState = new ExprState(inputPairCount); - lastCurrents = new double[inputPairCount]; - allocNodes(); - } - String getChipName() { return "CCCS"; } - void stamp() { - int i; - if (isSpiceStyle()) { - for (i = 0; i != inputCount; i += 2) - pins[i+1].voltSource = voltageSources[i/2].getVoltageSource(); - } else { - // voltage sources (0V) between C+ and C- so we can measure current - for (i = 0; i != inputCount; i += 2) { - int vn1 = pins[i+1].voltSource; - sim.stampVoltageSource(nodes[i], nodes[i+1], vn1, 0); - } - } - - sim.stampNonLinear(nodes[inputCount]); - sim.stampNonLinear(nodes[inputCount+1]); + + sim.stampNonLinear(nodes[inputCount]); + sim.stampNonLinear(nodes[inputCount + 1]); + } + + double lastCurrents[]; + + void doStep() { + // no current path? give up + if (broken) { + pins[inputCount].current = 0; + pins[inputCount + 1].current = 0; + // avoid singular matrix errors + sim.stampResistor(nodes[inputCount], nodes[inputCount + 1], 1e8); + return; + } + + // converged yet? + double convergeLimit = getConvergeLimit() * .1; + + int i; + if (isSpiceStyle()) { + // get current from connected voltage sources + for (i = 0; i != inputPairCount; i++) + pins[i * 2 + 1].current = voltageSources[i].getCurrent(); } - double lastCurrents[]; - - void doStep() { - // no current path? give up - if (broken) { - pins[inputCount].current = 0; - pins[inputCount+1].current = 0; - // avoid singular matrix errors - sim.stampResistor(nodes[inputCount], nodes[inputCount+1], 1e8); - return; - } - - // converged yet? - double convergeLimit = getConvergeLimit()*.1; - - int i; - if (isSpiceStyle()) { - // get current from connected voltage sources - for (i = 0; i != inputPairCount; i++) - pins[i*2+1].current = voltageSources[i].getCurrent(); - } - - for (i = 0; i != inputPairCount; i++) { - double cur = pins[i*2+1].current; - if (Math.abs(cur-lastCurrents[i]) > convergeLimit) - sim.converged = false; - } - - if (expr != null) { - // calculate output - for (i = 0; i != inputPairCount; i++) - setCurrentExprValue(i, pins[i*2+1].current); - exprState.t = sim.t; - double v0 = expr.eval(exprState); - double rs = v0; - - pins[inputCount ].current = v0; - pins[inputCount+1].current = -v0; - - for (i = 0; i != inputPairCount; i++) { - double cur = pins[i*2+1].current; - double dv = cur-lastCurrents[i]; - if (Math.abs(dv) < 1e-6) - dv = 1e-6; - setCurrentExprValue(i, cur); - double v = expr.eval(exprState); - setCurrentExprValue(i, cur-dv); - double v2 = expr.eval(exprState); - double dx = (v-v2)/dv; - if (Math.abs(dx) < 1e-6) - dx = sign(dx, 1e-6); - sim.stampCCCS(nodes[inputCount+1], nodes[inputCount], pins[i*2+1].voltSource, dx); - - // adjust right side - rs -= dx*cur; -// if (sim.subIterations > 1) -// sim.console("ccedx " + i + " " + cur + " " + dx + " " + rs + " " + sim.subIterations + " " + sim.t); - setCurrentExprValue(i, cur); - } - - sim.stampCurrentSource(nodes[inputCount+1], nodes[inputCount], rs); - } - - for (i = 0; i != inputPairCount; i++) - lastCurrents[i] = pins[i*2+1].current; - } - - void stepFinished() { - exprState.updateLastValues(pins[inputCount].current); - } - - void setCurrentExprValue(int n, double cur) { - // set i to current for backward compatibility - if (n == 0 && inputPairCount < 9) - exprState.values[8] = cur; - exprState.values[n] = cur; - } - - int getPostCount() { return inputCount+2; } - int getVoltageSourceCount() { return isSpiceStyle() ? 0 : inputPairCount; } - int getDumpType() { return 215; } - boolean getConnection(int n1, int n2) { - return (n1/2 == n2/2); + for (i = 0; i != inputPairCount; i++) { + double cur = pins[i * 2 + 1].current; + if (Math.abs(cur - lastCurrents[i]) > convergeLimit) + sim.converged = false; + } + + if (expr != null) { + // calculate output + for (i = 0; i != inputPairCount; i++) + setCurrentExprValue(i, pins[i * 2 + 1].current); + exprState.t = sim.t; + double v0 = expr.eval(exprState); + double rs = v0; + + pins[inputCount].current = v0; + pins[inputCount + 1].current = -v0; + + for (i = 0; i != inputPairCount; i++) { + double cur = pins[i * 2 + 1].current; + double dv = cur - lastCurrents[i]; + if (Math.abs(dv) < 1e-6) + dv = 1e-6; + setCurrentExprValue(i, cur); + double v = expr.eval(exprState); + setCurrentExprValue(i, cur - dv); + double v2 = expr.eval(exprState); + double dx = (v - v2) / dv; + if (Math.abs(dx) < 1e-6) + dx = sign(dx, 1e-6); + sim.stampCCCS(nodes[inputCount + 1], nodes[inputCount], pins[i * 2 + 1].voltSource, dx); + + // adjust right side + rs -= dx * cur; + // if (sim.subIterations > 1) + // sim.console("ccedx " + i + " " + cur + " " + dx + " " + rs + " " + + // sim.subIterations + " " + sim.t); + setCurrentExprValue(i, cur); + } + + sim.stampCurrentSource(nodes[inputCount + 1], nodes[inputCount], rs); + } + + for (i = 0; i != inputPairCount; i++) + lastCurrents[i] = pins[i * 2 + 1].current; + } + + void stepFinished() { + exprState.updateLastValues(pins[inputCount].current); + } + + void setCurrentExprValue(int n, double cur) { + // set i to current for backward compatibility + if (n == 0 && inputPairCount < 9) + exprState.values[8] = cur; + exprState.values[n] = cur; + } + + int getPostCount() { + return inputCount + 2; + } + + int getVoltageSourceCount() { + return isSpiceStyle() ? 0 : inputPairCount; + } + + int getDumpType() { + return 215; + } + + boolean getConnection(int n1, int n2) { + return (n1 / 2 == n2 / 2); + } + + boolean hasCurrentOutput() { + return true; + } + + boolean isSpiceStyle() { + return (flags & FLAG_SPICE) != 0; + } + + void setCurrent(int vn, double c) { + int i; + for (i = 0; i != inputCount; i += 2) + if (pins[i + 1].voltSource == vn) { + pins[i].current = -c; + pins[i + 1].current = c; + return; + } + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 1) { + // make sure number of inputs is even + if (ei.value < 0 || ei.value > 8 || (ei.value % 2) == 1) + return; + inputCount = (int) ei.value; + setupPins(); + allocNodes(); + setPoints(); + } else + super.setEditValue(n, ei); + } + + void setParentList(Vector elmList) { + int i, j; + if (!isSpiceStyle()) + return; + + // look for voltage sources across our inputs and use them rather than + // creating our own. this is useful for converting spice subcircuits + voltageSources = new VoltageElm[inputPairCount]; + for (i = 0; i != inputCount; i += 2) { + for (j = 0; j != elmList.size(); j++) { + CircuitElm ce = elmList.get(j); + if (!(ce instanceof VoltageElm)) + continue; + if (ce.getNode(0) == nodes[i] && ce.getNode(1) == nodes[i + 1]) + voltageSources[i / 2] = (VoltageElm) ce; + } } - boolean hasCurrentOutput() { return true; } - boolean isSpiceStyle() { return (flags & FLAG_SPICE) != 0; } - - void setCurrent(int vn, double c) { - int i; - for (i = 0; i != inputCount; i += 2) - if (pins[i+1].voltSource == vn) { - pins[i].current = -c; - pins[i+1].current = c; - return; - } - } - - public void setEditValue(int n, EditInfo ei) { - if (n == 1) { - // make sure number of inputs is even - if (ei.value < 0 || ei.value > 8 || (ei.value % 2) == 1) - return; - inputCount = (int) ei.value; - setupPins(); - allocNodes(); - setPoints(); - } else - super.setEditValue(n, ei); - } - - void setParentList(Vector elmList) { - int i, j; - if (!isSpiceStyle()) - return; - - // look for voltage sources across our inputs and use them rather than - // creating our own. this is useful for converting spice subcircuits - voltageSources = new VoltageElm[inputPairCount]; - for (i = 0; i != inputCount; i += 2) { - for (j = 0; j != elmList.size(); j++) { - CircuitElm ce = elmList.get(j); - if (!(ce instanceof VoltageElm)) - continue; - if (ce.getNode(0) == nodes[i] && ce.getNode(1) == nodes[i+1]) - voltageSources[i/2] = (VoltageElm)ce; - } - } - } - - void setVoltageSource(int j, int vs) { - if (isSpiceStyle()) - pins[inputCount].voltSource = vs; - else - super.setVoltageSource(j, vs); - } - - void getInfo(String arr[]) { - super.getInfo(arr); - int i = 1; - int j; - for (j = 0; j != inputCount; j += 2) - arr[i++] = pins[j].text + " = " + getCurrentText(-pins[j].current); - arr[i++] = pins[j].text + " = " + getVoltageText(volts[j]) + "; " + pins[j+1].text + " = " + getVoltageText(volts[j+1]); - arr[i++] = "I = " + getCurrentText(pins[j].current); - arr[i++] = null; - } - } + void setVoltageSource(int j, int vs) { + if (isSpiceStyle()) + pins[inputCount].voltSource = vs; + else + super.setVoltageSource(j, vs); + } + + void getInfo(String arr[]) { + super.getInfo(arr); + int i = 1; + int j; + for (j = 0; j != inputCount; j += 2) + arr[i++] = pins[j].text + " = " + getCurrentText(-pins[j].current); + arr[i++] = pins[j].text + " = " + getVoltageText(volts[j]) + "; " + pins[j + 1].text + " = " + + getVoltageText(volts[j + 1]); + arr[i++] = "I = " + getCurrentText(pins[j].current); + arr[i++] = null; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/CCVSElm.java b/src/com/lushprojects/circuitjs1/client/CCVSElm.java index 68d50178..804c3dd1 100644 --- a/src/com/lushprojects/circuitjs1/client/CCVSElm.java +++ b/src/com/lushprojects/circuitjs1/client/CCVSElm.java @@ -22,208 +22,226 @@ import java.util.Vector; class CCVSElm extends VCCSElm { - static int FLAG_SPICE = 2; - VoltageElm voltageSources[]; - int outputVS; - - public CCVSElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); -// exprString = CustomLogicModel.unescape(st.nextToken()); -// inputCount = 2; -// parseExpr(); - setupPins(); + static int FLAG_SPICE = 2; + VoltageElm voltageSources[]; + int outputVS; + + public CCVSElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + // exprString = CustomLogicModel.unescape(st.nextToken()); + // inputCount = 2; + // parseExpr(); + setupPins(); + } + + public CCVSElm(int xx, int yy) { + super(xx, yy); + exprString = "2*a"; + parseExpr(); + // setupPins(); + } + + int inputPairCount; + + void setupPins() { + sizeX = 2; + sizeY = inputCount > 2 ? inputCount : 2; + inputPairCount = inputCount / 2; + pins = new Pin[inputCount + 2]; + int i; + for (i = 0; i != inputPairCount; i++) { + pins[i * 2] = new Pin(i * 2, SIDE_W, Character.toString((char) ('A' + i)) + "+"); + pins[i * 2 + 1] = new Pin(i * 2 + 1, SIDE_W, Character.toString((char) ('A' + i)) + "-"); + pins[i * 2 + 1].output = true; } - public CCVSElm(int xx, int yy) { - super(xx, yy); - exprString = "2*a"; - parseExpr(); -// setupPins(); + pins[i * 2] = new Pin(0, SIDE_E, "V+"); + pins[i * 2].output = true; + pins[i * 2 + 1] = new Pin(1, SIDE_E, "V-"); + exprState = new ExprState(inputPairCount); + lastCurrents = new double[inputPairCount]; + allocNodes(); + } + + String getChipName() { + return "CCVS"; + } + + void stamp() { + int i; + if (isSpiceStyle()) { + for (i = 0; i != inputCount; i += 2) + pins[i + 1].voltSource = voltageSources[i / 2].getVoltageSource(); + } else { + // voltage source (0V) between C+ and C- so we can measure current + for (i = 0; i != inputCount; i += 2) { + int vn1 = pins[i + 1].voltSource; + sim.stampVoltageSource(nodes[i], nodes[i + 1], vn1, 0); + } } - - int inputPairCount; - - void setupPins() { - sizeX = 2; - sizeY = inputCount > 2 ? inputCount : 2; - inputPairCount = inputCount/2; - pins = new Pin[inputCount+2]; - int i; + + // voltage source for outputs + int vn2 = pins[inputCount].voltSource; + outputVS = vn2; + sim.stampNonLinear(vn2 + sim.nodeList.size()); + sim.stampVoltageSource(nodes[inputCount + 1], nodes[inputCount], vn2); + } + + double lastCurrents[]; + + void doStep() { + // converged yet? + double convergeLimit = getConvergeLimit() * .1; + + int i; + if (isSpiceStyle()) { + for (i = 0; i != inputPairCount; i++) + pins[i * 2 + 1].current = voltageSources[i].getCurrent(); + } + + for (i = 0; i != inputPairCount; i++) { + double cur = pins[i * 2 + 1].current; + if (Math.abs(cur - lastCurrents[i]) > convergeLimit) + sim.converged = false; + } + + int vno = outputVS + sim.nodeList.size(); + if (expr != null) { + // calculate output + for (i = 0; i != inputPairCount; i++) + setCurrentExprValue(i, pins[i * 2 + 1].current); + exprState.t = sim.t; + double v0 = expr.eval(exprState); + double rs = v0; + for (i = 0; i != inputPairCount; i++) { - pins[i*2 ] = new Pin(i*2, SIDE_W, Character.toString((char)('A'+i)) + "+"); - pins[i*2+1] = new Pin(i*2+1, SIDE_W, Character.toString((char)('A'+i)) + "-"); - pins[i*2+1].output = true; + double cur = pins[i * 2 + 1].current; + double dv = cur - lastCurrents[i]; + int vni = pins[i * 2 + 1].voltSource + sim.nodeList.size(); + if (Math.abs(dv) < 1e-6) + dv = 1e-6; + setCurrentExprValue(i, cur); + double v = expr.eval(exprState); + setCurrentExprValue(i, cur - dv); + double v2 = expr.eval(exprState); + double dx = (v - v2) / dv; + if (Math.abs(dx) < 1e-6) + dx = sign(dx, 1e-6); + sim.stampMatrix(vno, vni, -dx); + // adjust right side + rs -= dx * cur; + // if (sim.subIterations > 1) + // sim.console("ccedx " + i + " " + cur + " " + dx + " " + rs + " " + + // sim.subIterations + " " + sim.t); + setCurrentExprValue(i, cur); } - pins[i*2] = new Pin(0, SIDE_E, "V+"); - pins[i*2].output = true; - pins[i*2+1] = new Pin(1, SIDE_E, "V-"); - exprState = new ExprState(inputPairCount); - lastCurrents = new double[inputPairCount]; - allocNodes(); + sim.stampRightSide(vno, rs); } - - String getChipName() { return "CCVS"; } - - void stamp() { - int i; - if (isSpiceStyle()) { - for (i = 0; i != inputCount; i += 2) - pins[i+1].voltSource = voltageSources[i/2].getVoltageSource(); - } else { - // voltage source (0V) between C+ and C- so we can measure current - for (i = 0; i != inputCount; i += 2) { - int vn1 = pins[i+1].voltSource; - sim.stampVoltageSource(nodes[i], nodes[i+1], vn1, 0); + + for (i = 0; i != inputPairCount; i++) + lastCurrents[i] = pins[i * 2 + 1].current; + } + + void stepFinished() { + exprState.updateLastValues(volts[inputCount] - volts[inputCount + 1]); + } + + void setCurrentExprValue(int n, double cur) { + // set i to current for backward compatibility + if (n == 0 && inputPairCount < 9) + exprState.values[8] = cur; + exprState.values[n] = cur; + } + + int getPostCount() { + return inputCount + 2; + } + + int getVoltageSourceCount() { + return isSpiceStyle() ? 1 : 1 + inputPairCount; + } + + int getDumpType() { + return 214; + } + + boolean getConnection(int n1, int n2) { + return (n1 / 2 == n2 / 2); + } + + boolean hasCurrentOutput() { + return false; + } + + boolean isSpiceStyle() { + return (flags & FLAG_SPICE) != 0; + } + + void setCurrent(int vn, double c) { + int i = 0; + if (!isSpiceStyle()) { + for (i = 0; i != inputCount; i += 2) + if (pins[i + 1].voltSource == vn) { + pins[i].current = -c; + pins[i + 1].current = c; + return; } - } - - // voltage source for outputs - int vn2 = pins[inputCount].voltSource; - outputVS = vn2; - sim.stampNonLinear(vn2 + sim.nodeList.size()); - sim.stampVoltageSource(nodes[inputCount+1], nodes[inputCount], vn2); + } else + i = inputCount; + if (pins[i].voltSource == vn) { + pins[i].current = c; + pins[i + 1].current = -c; } + } - double lastCurrents[]; - - void doStep() { - // converged yet? - double convergeLimit = getConvergeLimit()*.1; - - int i; - if (isSpiceStyle()) { - for (i = 0; i != inputPairCount; i++) - pins[i*2+1].current = voltageSources[i].getCurrent(); - } - - for (i = 0; i != inputPairCount; i++) { - double cur = pins[i*2+1].current; - if (Math.abs(cur-lastCurrents[i]) > convergeLimit) - sim.converged = false; - } - - int vno = outputVS + sim.nodeList.size(); - if (expr != null) { - // calculate output - for (i = 0; i != inputPairCount; i++) - setCurrentExprValue(i, pins[i*2+1].current); - exprState.t = sim.t; - double v0 = expr.eval(exprState); - double rs = v0; - - for (i = 0; i != inputPairCount; i++) { - double cur = pins[i*2+1].current; - double dv = cur-lastCurrents[i]; - int vni = pins[i*2+1].voltSource + sim.nodeList.size(); - if (Math.abs(dv) < 1e-6) - dv = 1e-6; - setCurrentExprValue(i, cur); - double v = expr.eval(exprState); - setCurrentExprValue(i, cur-dv); - double v2 = expr.eval(exprState); - double dx = (v-v2)/dv; - if (Math.abs(dx) < 1e-6) - dx = sign(dx, 1e-6); - sim.stampMatrix(vno, vni, -dx); - // adjust right side - rs -= dx*cur; - //if (sim.subIterations > 1) - //sim.console("ccedx " + i + " " + cur + " " + dx + " " + rs + " " + sim.subIterations + " " + sim.t); - setCurrentExprValue(i, cur); - } - sim.stampRightSide(vno, rs); - } - - for (i = 0; i != inputPairCount; i++) - lastCurrents[i] = pins[i*2+1].current; - } - - void stepFinished() { - exprState.updateLastValues(volts[inputCount]-volts[inputCount+1]); - } - - void setCurrentExprValue(int n, double cur) { - // set i to current for backward compatibility - if (n == 0 && inputPairCount < 9) - exprState.values[8] = cur; - exprState.values[n] = cur; - } - - int getPostCount() { return inputCount+2; } - int getVoltageSourceCount() { return isSpiceStyle() ? 1 : 1+inputPairCount; } - int getDumpType() { return 214; } - boolean getConnection(int n1, int n2) { - return (n1/2 == n2/2); - } - boolean hasCurrentOutput() { return false; } - boolean isSpiceStyle() { return (flags & FLAG_SPICE) != 0; } - - void setCurrent(int vn, double c) { - int i = 0; - if (!isSpiceStyle()) { - for (i = 0; i != inputCount; i += 2) - if (pins[i+1].voltSource == vn) { - pins[i].current = -c; - pins[i+1].current = c; - return; - } - } else - i = inputCount; - if (pins[i].voltSource == vn) { - pins[i].current = c; - pins[i+1].current = -c; - } - } - - public void setChipEditValue(int n, EditInfo ei) { - if (n == 1) { - // make sure number of inputs is even - if (ei.value < 0 || ei.value > 8 || (ei.value % 2) == 1) - return; - inputCount = (int) ei.value; - setupPins(); - allocNodes(); - setPoints(); - } else - super.setChipEditValue(n, ei); - } - - void setParentList(Vector elmList) { - int i, j; - if (!isSpiceStyle()) - return; - - // look for voltage sources across our inputs and use them rather than - // creating our own. this is useful for converting spice subcircuits - voltageSources = new VoltageElm[inputPairCount]; - for (i = 0; i != inputCount; i += 2) { - for (j = 0; j != elmList.size(); j++) { - CircuitElm ce = elmList.get(j); - if (!(ce instanceof VoltageElm)) - continue; - if (ce.getNode(0) == nodes[i] && ce.getNode(1) == nodes[i+1]) - voltageSources[i/2] = (VoltageElm)ce; - } - } - } - - void setVoltageSource(int j, int vs) { - if (isSpiceStyle()) - pins[inputCount].voltSource = vs; - else - super.setVoltageSource(j, vs); + public void setChipEditValue(int n, EditInfo ei) { + if (n == 1) { + // make sure number of inputs is even + if (ei.value < 0 || ei.value > 8 || (ei.value % 2) == 1) + return; + inputCount = (int) ei.value; + setupPins(); + allocNodes(); + setPoints(); + } else + super.setChipEditValue(n, ei); + } + + void setParentList(Vector elmList) { + int i, j; + if (!isSpiceStyle()) + return; + + // look for voltage sources across our inputs and use them rather than + // creating our own. this is useful for converting spice subcircuits + voltageSources = new VoltageElm[inputPairCount]; + for (i = 0; i != inputCount; i += 2) { + for (j = 0; j != elmList.size(); j++) { + CircuitElm ce = elmList.get(j); + if (!(ce instanceof VoltageElm)) + continue; + if (ce.getNode(0) == nodes[i] && ce.getNode(1) == nodes[i + 1]) + voltageSources[i / 2] = (VoltageElm) ce; + } } + } - void getInfo(String arr[]) { - super.getInfo(arr); - int i = 1; - int j; - for (j = 0; j != inputCount; j += 2) - arr[i++] = pins[j].text + " = " + getCurrentText(-pins[j].current); - arr[i++] = pins[j].text + " = " + getVoltageText(volts[j]) + "; " + pins[j+1].text + " = " + getVoltageText(volts[j+1]); - arr[i++] = "I = " + getCurrentText(pins[j].current); - arr[i++] = null; - } + void setVoltageSource(int j, int vs) { + if (isSpiceStyle()) + pins[inputCount].voltSource = vs; + else + super.setVoltageSource(j, vs); + } + void getInfo(String arr[]) { + super.getInfo(arr); + int i = 1; + int j; + for (j = 0; j != inputCount; j += 2) + arr[i++] = pins[j].text + " = " + getCurrentText(-pins[j].current); + arr[i++] = pins[j].text + " = " + getVoltageText(volts[j]) + "; " + pins[j + 1].text + " = " + + getVoltageText(volts[j + 1]); + arr[i++] = "I = " + getCurrentText(pins[j].current); + arr[i++] = null; } +} diff --git a/src/com/lushprojects/circuitjs1/client/CapacitorElm.java b/src/com/lushprojects/circuitjs1/client/CapacitorElm.java index e80f7747..26b074cf 100644 --- a/src/com/lushprojects/circuitjs1/client/CapacitorElm.java +++ b/src/com/lushprojects/circuitjs1/client/CapacitorElm.java @@ -22,190 +22,219 @@ import com.lushprojects.circuitjs1.client.util.Locale; class CapacitorElm extends CircuitElm { - double capacitance; - double compResistance, voltdiff; - double initialVoltage; - Point plate1[], plate2[]; - public static final int FLAG_BACK_EULER = 2; - public CapacitorElm(int xx, int yy) { - super(xx, yy); - capacitance = 1e-5; - initialVoltage = 1e-3; - } - public CapacitorElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - capacitance = new Double(st.nextToken()).doubleValue(); - voltdiff = new Double(st.nextToken()).doubleValue(); - initialVoltage = 1e-3; - try { - initialVoltage = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) {} + double capacitance; + double compResistance, voltdiff; + double initialVoltage; + Point plate1[], plate2[]; + public static final int FLAG_BACK_EULER = 2; + + public CapacitorElm(int xx, int yy) { + super(xx, yy); + capacitance = 1e-5; + initialVoltage = 1e-3; + } + + public CapacitorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + capacitance = Double.valueOf(st.nextToken()).doubleValue(); + voltdiff = Double.valueOf(st.nextToken()).doubleValue(); + initialVoltage = 1e-3; + try { + initialVoltage = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } - boolean isTrapezoidal() { return (flags & FLAG_BACK_EULER) == 0; } - - void reset() { - super.reset(); - current = curcount = curSourceValue = 0; - // put small charge on caps when reset to start oscillators - voltdiff = initialVoltage; + } + + boolean isTrapezoidal() { + return (flags & FLAG_BACK_EULER) == 0; + } + + void reset() { + super.reset(); + current = curcount = curSourceValue = 0; + // put small charge on caps when reset to start oscillators + voltdiff = initialVoltage; + } + + void shorted() { + super.reset(); + voltdiff = current = curcount = curSourceValue = 0; + } + + int getDumpType() { + return 'c'; + } + + String dump() { + return super.dump() + " " + capacitance + " " + voltdiff + " " + initialVoltage; + } + + // used for PolarCapacitorElm + Point platePoints[]; + + void setPoints() { + super.setPoints(); + double f = (dn / 2 - 4) / dn; + // calc leads + lead1 = interpPoint(point1, point2, f); + lead2 = interpPoint(point1, point2, 1 - f); + // calc plates + plate1 = newPointArray(2); + plate2 = newPointArray(2); + interpPoint2(point1, point2, plate1[0], plate1[1], f, 12); + interpPoint2(point1, point2, plate2[0], plate2[1], 1 - f, 12); + } + + void draw(Graphics g) { + int hs = 12; + setBbox(point1, point2, hs); + + // draw first lead and plate + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, lead1); + setPowerColor(g, false); + drawThickLine(g, plate1[0], plate1[1]); + if (sim.powerCheckItem.getState()) + g.setColor(Color.gray); + + // draw second lead and plate + setVoltageColor(g, volts[1]); + drawThickLine(g, point2, lead2); + setPowerColor(g, false); + if (platePoints == null) + drawThickLine(g, plate2[0], plate2[1]); + else { + int i; + for (i = 0; i != platePoints.length - 1; i++) + drawThickLine(g, platePoints[i], platePoints[i + 1]); } - void shorted() { - super.reset(); - voltdiff = current = curcount = curSourceValue = 0; + + updateDotCount(); + if (sim.dragElm != this) { + drawDots(g, point1, lead1, curcount); + drawDots(g, point2, lead2, -curcount); } - int getDumpType() { return 'c'; } - String dump() { - return super.dump() + " " + capacitance + " " + voltdiff + " " + initialVoltage; + drawPosts(g); + if (sim.showValuesCheckItem.getState()) { + String s = getShortUnitText(capacitance, "F"); + drawValues(g, s, hs); } - - // used for PolarCapacitorElm - Point platePoints[]; - - void setPoints() { - super.setPoints(); - double f = (dn/2-4)/dn; - // calc leads - lead1 = interpPoint(point1, point2, f); - lead2 = interpPoint(point1, point2, 1-f); - // calc plates - plate1 = newPointArray(2); - plate2 = newPointArray(2); - interpPoint2(point1, point2, plate1[0], plate1[1], f, 12); - interpPoint2(point1, point2, plate2[0], plate2[1], 1-f, 12); + } + + void stamp() { + if (sim.dcAnalysisFlag) { + // when finding DC operating point, replace cap with a 100M resistor + sim.stampResistor(nodes[0], nodes[1], 1e8); + curSourceValue = 0; + return; } - - void draw(Graphics g) { - int hs = 12; - setBbox(point1, point2, hs); - - // draw first lead and plate - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, lead1); - setPowerColor(g, false); - drawThickLine(g, plate1[0], plate1[1]); - if (sim.powerCheckItem.getState()) - g.setColor(Color.gray); - - // draw second lead and plate - setVoltageColor(g, volts[1]); - drawThickLine(g, point2, lead2); - setPowerColor(g, false); - if (platePoints == null) - drawThickLine(g, plate2[0], plate2[1]); - else { - int i; - for (i = 0; i != platePoints.length-1; i++) - drawThickLine(g, platePoints[i], platePoints[i+1]); - } - - updateDotCount(); - if (sim.dragElm != this) { - drawDots(g, point1, lead1, curcount); - drawDots(g, point2, lead2, -curcount); - } - drawPosts(g); - if (sim.showValuesCheckItem.getState()) { - String s = getShortUnitText(capacitance, "F"); - drawValues(g, s, hs); - } + + // capacitor companion model using trapezoidal approximation + // (Norton equivalent) consists of a current source in + // parallel with a resistor. Trapezoidal is more accurate + // than backward euler but can cause oscillatory behavior + // if RC is small relative to the timestep. + if (isTrapezoidal()) + compResistance = sim.timeStep / (2 * capacitance); + else + compResistance = sim.timeStep / capacitance; + sim.stampResistor(nodes[0], nodes[1], compResistance); + sim.stampRightSide(nodes[0]); + sim.stampRightSide(nodes[1]); + } + + void startIteration() { + if (isTrapezoidal()) + curSourceValue = -voltdiff / compResistance - current; + else + curSourceValue = -voltdiff / compResistance; + } + + void stepFinished() { + voltdiff = volts[0] - volts[1]; + calculateCurrent(); + } + + void setNodeVoltage(int n, double c) { + // do not calculate current, that only gets done in stepFinished(). otherwise + // calculateCurrent() may get + // called while stamping the circuit, which might discharge the cap (since we + // use that current to calculate + // curSourceValue in startIteration) + volts[n] = c; + } + + void calculateCurrent() { + double voltdiff = volts[0] - volts[1]; + if (sim.dcAnalysisFlag) { + current = voltdiff / 1e8; + return; } - void stamp() { - if (sim.dcAnalysisFlag) { - // when finding DC operating point, replace cap with a 100M resistor - sim.stampResistor(nodes[0], nodes[1], 1e8); - curSourceValue = 0; - return; - } - - // capacitor companion model using trapezoidal approximation - // (Norton equivalent) consists of a current source in - // parallel with a resistor. Trapezoidal is more accurate - // than backward euler but can cause oscillatory behavior - // if RC is small relative to the timestep. - if (isTrapezoidal()) - compResistance = sim.timeStep/(2*capacitance); - else - compResistance = sim.timeStep/capacitance; - sim.stampResistor(nodes[0], nodes[1], compResistance); - sim.stampRightSide(nodes[0]); - sim.stampRightSide(nodes[1]); + // we check compResistance because this might get called + // before stamp(), which sets compResistance, causing + // infinite current + if (compResistance > 0) + current = voltdiff / compResistance + curSourceValue; + } + + double curSourceValue; + + void doStep() { + if (sim.dcAnalysisFlag) + return; + sim.stampCurrentSource(nodes[0], nodes[1], curSourceValue); + } + + void getInfo(String arr[]) { + arr[0] = "capacitor"; + getBasicInfo(arr); + arr[3] = "C = " + getUnitText(capacitance, "F"); + arr[4] = "P = " + getUnitText(getPower(), "W"); + // double v = getVoltageDiff(); + // arr[4] = "U = " + getUnitText(.5*capacitance*v*v, "J"); + } + + @Override + String getScopeText(int v) { + return Locale.LS("capacitor") + ", " + getUnitText(capacitance, "F"); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Capacitance (F)", capacitance, 1e-6, 1e-3); + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Trapezoidal Approximation", isTrapezoidal()); + return ei; } - void startIteration() { - if (isTrapezoidal()) - curSourceValue = -voltdiff/compResistance-current; + if (n == 2) + return new EditInfo("Initial Voltage (on Reset)", initialVoltage); + // if you add more things here, check PolarCapacitorElm + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + capacitance = (ei.value > 0) ? ei.value : 1e-12; + if (n == 1) { + if (ei.checkbox.getState()) + flags &= ~FLAG_BACK_EULER; else - curSourceValue = -voltdiff/compResistance; - } - - void stepFinished() { - voltdiff = volts[0]-volts[1]; - calculateCurrent(); - } - - void setNodeVoltage(int n, double c) { - // do not calculate current, that only gets done in stepFinished(). otherwise calculateCurrent() may get - // called while stamping the circuit, which might discharge the cap (since we use that current to calculate - // curSourceValue in startIteration) - volts[n] = c; - } - - void calculateCurrent() { - double voltdiff = volts[0] - volts[1]; - if (sim.dcAnalysisFlag) { - current = voltdiff/1e8; - return; - } - // we check compResistance because this might get called - // before stamp(), which sets compResistance, causing - // infinite current - if (compResistance > 0) - current = voltdiff/compResistance + curSourceValue; - } - double curSourceValue; - void doStep() { - if (sim.dcAnalysisFlag) - return; - sim.stampCurrentSource(nodes[0], nodes[1], curSourceValue); - } - void getInfo(String arr[]) { - arr[0] = "capacitor"; - getBasicInfo(arr); - arr[3] = "C = " + getUnitText(capacitance, "F"); - arr[4] = "P = " + getUnitText(getPower(), "W"); - //double v = getVoltageDiff(); - //arr[4] = "U = " + getUnitText(.5*capacitance*v*v, "J"); - } - @Override - String getScopeText(int v) { - return Locale.LS("capacitor") + ", " + getUnitText(capacitance, "F"); - } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Capacitance (F)", capacitance, 1e-6, 1e-3); - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Trapezoidal Approximation", isTrapezoidal()); - return ei; - } - if (n == 2) - return new EditInfo("Initial Voltage (on Reset)", initialVoltage); - // if you add more things here, check PolarCapacitorElm - return null; + flags |= FLAG_BACK_EULER; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - capacitance = (ei.value > 0) ? ei.value : 1e-12; - if (n == 1) { - if (ei.checkbox.getState()) - flags &= ~FLAG_BACK_EULER; - else - flags |= FLAG_BACK_EULER; - } - if (n == 2) - initialVoltage = ei.value; - } - int getShortcut() { return 'c'; } - public double getCapacitance() { return capacitance; } - public void setCapacitance(double c) { capacitance = c; } + if (n == 2) + initialVoltage = ei.value; + } + + int getShortcut() { + return 'c'; + } + + public double getCapacitance() { + return capacitance; + } + + public void setCapacitance(double c) { + capacitance = c; } +} diff --git a/src/com/lushprojects/circuitjs1/client/Checkbox.java b/src/com/lushprojects/circuitjs1/client/Checkbox.java index 2aeeaf99..1082ceac 100644 --- a/src/com/lushprojects/circuitjs1/client/Checkbox.java +++ b/src/com/lushprojects/circuitjs1/client/Checkbox.java @@ -23,21 +23,21 @@ import com.lushprojects.circuitjs1.client.util.Locale; class Checkbox extends CheckBox { - public Checkbox(String s){ - super(Locale.LS(s)); - } - - public Checkbox(String s, boolean b){ - super(Locale.LS(s)); - this.setValue(b); - } - - public boolean getState(){ - return this.getValue(); - } - - public void setState(boolean s){ - this.setValue(s); - } - + public Checkbox(String s) { + super(Locale.LS(s)); + } + + public Checkbox(String s, boolean b) { + super(Locale.LS(s)); + this.setValue(b); + } + + public boolean getState() { + return this.getValue(); + } + + public void setState(boolean s) { + this.setValue(s); + } + } \ No newline at end of file diff --git a/src/com/lushprojects/circuitjs1/client/CheckboxAlignedMenuItem.java b/src/com/lushprojects/circuitjs1/client/CheckboxAlignedMenuItem.java index a6677997..704fe622 100644 --- a/src/com/lushprojects/circuitjs1/client/CheckboxAlignedMenuItem.java +++ b/src/com/lushprojects/circuitjs1/client/CheckboxAlignedMenuItem.java @@ -24,9 +24,9 @@ import com.google.gwt.safehtml.shared.SafeHtmlUtils; public class CheckboxAlignedMenuItem extends MenuItem { - - public CheckboxAlignedMenuItem(String s, Command cmd) { - super(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+" "+s), cmd); - } + + public CheckboxAlignedMenuItem(String s, Command cmd) { + super(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml + " " + s), cmd); + } } diff --git a/src/com/lushprojects/circuitjs1/client/CheckboxMenuItem.java b/src/com/lushprojects/circuitjs1/client/CheckboxMenuItem.java index 5ac96d8b..970dd701 100644 --- a/src/com/lushprojects/circuitjs1/client/CheckboxMenuItem.java +++ b/src/com/lushprojects/circuitjs1/client/CheckboxMenuItem.java @@ -23,78 +23,85 @@ import com.google.gwt.user.client.Command; public class CheckboxMenuItem extends MenuItem implements Command { - private boolean on=false; - private String name=""; - private String shortcut=""; - private Command extcmd=null; - static String checkBoxHtml="
"; - - public String getName() { return name; } - public String getShortcut() { return shortcut; } - - public CheckboxMenuItem(String s){ - super(s, (Command)null); - super.setScheduledCommand(this); - name=s; - setState(false); - } - - public CheckboxMenuItem(String s, Command cmd){ - super(s, (Command)null); - super.setScheduledCommand(this); - extcmd=cmd; - name=s; - setState(false); - } - - public CheckboxMenuItem(String s, String c, Command cmd){ - this(s, cmd); - shortcut=c; - } - - public CheckboxMenuItem(String s, String c){ - this(s); - shortcut=c; - } - - public void setShortcut(String s) { - shortcut=s; - } - - public void execute() { - setState(!on); - if (extcmd!=null) { - extcmd.execute(); - CircuitElm.sim.repaint(); - } - } - - public void setTitle(String s) { - name = s; - } - - public void setState(boolean newstate) { - on = newstate; - String s; - if (on) - // super.setHTML("✔ "+name); - s = checkBoxHtml+"✔
"+name; - else -// super.setHTML("  "+name); - s = checkBoxHtml+" "+name; - if (shortcut!="") - if (shortcut.length()==1) { - s = s + "
"+shortcut+"
"; - } else { - // add some space so menu text doesn't overlap shortcut - s = s+ ""; - s = s + "
"+shortcut+"
"; - } - setHTML(s); - } - - public boolean getState(){ - return on; + private boolean on = false; + private String name = ""; + private String shortcut = ""; + private Command extcmd = null; + static String checkBoxHtml = "
"; + + public String getName() { + return name; + } + + public String getShortcut() { + return shortcut; + } + + public CheckboxMenuItem(String s) { + super(s, (Command) null); + super.setScheduledCommand(this); + name = s; + setState(false); + } + + public CheckboxMenuItem(String s, Command cmd) { + super(s, (Command) null); + super.setScheduledCommand(this); + extcmd = cmd; + name = s; + setState(false); + } + + public CheckboxMenuItem(String s, String c, Command cmd) { + this(s, cmd); + shortcut = c; + } + + public CheckboxMenuItem(String s, String c) { + this(s); + shortcut = c; + } + + public void setShortcut(String s) { + shortcut = s; + } + + public void execute() { + setState(!on); + if (extcmd != null) { + extcmd.execute(); + CircuitElm.sim.repaint(); } + } + + public void setTitle(String s) { + name = s; + } + + public void setState(boolean newstate) { + on = newstate; + String s; + if (on) + // super.setHTML("✔ "+name); + s = checkBoxHtml + "✔
" + name; + else + // super.setHTML("  "+name); + s = checkBoxHtml + " " + name; + if (shortcut != "") + if (shortcut.length() == 1) { + s = s + "
" + + shortcut + "
"; + } else { + // add some space so menu text doesn't overlap shortcut + s = s + ""; + s = s + "
" + shortcut + + "
"; + } + setHTML(s); + } + + public boolean getState() { + return on; + } } diff --git a/src/com/lushprojects/circuitjs1/client/ChipElm.java b/src/com/lushprojects/circuitjs1/client/ChipElm.java index 2d713daa..0c99c252 100644 --- a/src/com/lushprojects/circuitjs1/client/ChipElm.java +++ b/src/com/lushprojects/circuitjs1/client/ChipElm.java @@ -20,556 +20,615 @@ package com.lushprojects.circuitjs1.client; abstract class ChipElm extends CircuitElm { - int csize, cspc, cspc2; - int bits; - double highVoltage; - - static final int FLAG_SMALL = 1; - static final int FLAG_FLIP_X = 1<<10; - static final int FLAG_FLIP_Y = 1<<11; - static final int FLAG_FLIP_XY = 1<<12; - static final int FLAG_CUSTOM_VOLTAGE = 1<<13; - public ChipElm(int xx, int yy) { - super(xx, yy); - if (needsBits()) + int csize, cspc, cspc2; + int bits; + double highVoltage; + + static final int FLAG_SMALL = 1; + static final int FLAG_FLIP_X = 1 << 10; + static final int FLAG_FLIP_Y = 1 << 11; + static final int FLAG_FLIP_XY = 1 << 12; + static final int FLAG_CUSTOM_VOLTAGE = 1 << 13; + + public ChipElm(int xx, int yy) { + super(xx, yy); + if (needsBits()) + bits = defaultBitCount(); + highVoltage = 5; + noDiagonal = true; + setupPins(); + setSize(sim.smallGridCheckItem.getState() ? 1 : 2); + } + + public ChipElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + if (needsBits()) + if (st.hasMoreTokens()) + bits = Integer.valueOf(st.nextToken()).intValue(); + else bits = defaultBitCount(); - highVoltage = 5; - noDiagonal = true; - setupPins(); - setSize(sim.smallGridCheckItem.getState() ? 1 : 2); - } - public ChipElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - if (needsBits()) - if (st.hasMoreTokens()) - bits = new Integer(st.nextToken()).intValue(); - else - bits = defaultBitCount(); - highVoltage = (hasCustomVoltage()) ? Double.parseDouble(st.nextToken()) : 5; - noDiagonal = true; - setupPins(); - setSize((f & FLAG_SMALL) != 0 ? 1 : 2); - int i; - for (i = 0; i != getPostCount(); i++) { - if (pins == null) - volts[i] = new Double(st.nextToken()).doubleValue(); - else if (pins[i].state) { - volts[i] = new Double(st.nextToken()).doubleValue(); - pins[i].value = volts[i] > getThreshold(); - } + highVoltage = (hasCustomVoltage()) ? Double.parseDouble(st.nextToken()) : 5; + noDiagonal = true; + setupPins(); + setSize((f & FLAG_SMALL) != 0 ? 1 : 2); + int i; + for (i = 0; i != getPostCount(); i++) { + if (pins == null) + volts[i] = Double.valueOf(st.nextToken()).doubleValue(); + else if (pins[i].state) { + volts[i] = Double.valueOf(st.nextToken()).doubleValue(); + pins[i].value = volts[i] > getThreshold(); } } - boolean needsBits() { return false; } - boolean hasCustomVoltage() { return (flags & FLAG_CUSTOM_VOLTAGE) != 0; } - boolean isDigitalChip() { return true; } - double getThreshold() { return highVoltage/2; } - - int defaultBitCount() { return 4; } - void setSize(int s) { - csize = s; - cspc = 8*s; - cspc2 = cspc*2; - flags &= ~FLAG_SMALL; - flags |= (s == 1) ? FLAG_SMALL : 0; - } - abstract void setupPins(); - void draw(Graphics g) { - drawChip(g); - } - void drawChip(Graphics g) { - int i; - g.save(); - Font f = new Font("normal", 0, 10*csize); -// FontMetrics fm = g.getFontMetrics(); - boolean hasVertical = false; - // check if there are any vertical pins. if not, we can make the labels wider - for (i = 0; i != getPostCount(); i++) - if (pins[i].side == SIDE_N || pins[i].side == SIDE_S) { - hasVertical = true; - break; - } - for (i = 0; i != getPostCount(); i++) { - g.setFont(f); - Pin p = pins[i]; - setVoltageColor(g, volts[i]); - Point a = p.post; - Point b = p.stub; - drawThickLine(g, a, b); - p.curcount = updateDotCount(p.current, p.curcount); - drawDots(g, b, a, p.curcount); - if (p.bubble) { - g.setColor(sim.getBackgroundColor()); - drawThickCircle(g, p.bubbleX, p.bubbleY, 1); - g.setColor(lightGrayColor); - drawThickCircle(g, p.bubbleX, p.bubbleY, 3); - } - if (p.clockPointsX != null) - g.drawPolyline(p.clockPointsX, p.clockPointsY, 3); - g.setColor(p.selected ? selectColor : whiteColor); - int fsz = 10*csize; - double availSpace = cspc*2-8; - // allow a little more space if the chip is wide and there are no vertical pins - // (we could still do this if vertical pins are present but then we would have to do - // more work to avoid overlaps) - if (!hasVertical && sizeX > 2) - availSpace = cspc*2.5+cspc*(sizeX-3); - while (true) { - int sw=(int)g.context.measureText(p.text).getWidth(); - // scale font down if it's too big - if (sw > availSpace) { - fsz -= 1; - Font f2 = new Font("normal", 0, fsz); - g.setFont(f2); - continue; - } - int asc=(int)g.currentFontSize; - int tx; - // put text closer to edge if it's on left or right. - if (p.side == flippedXSide(SIDE_W)) - tx = p.textloc.x-(cspc-5); - else if (p.side == flippedXSide(SIDE_E)) - tx = p.textloc.x+(cspc-5)-sw; - else - tx = p.textloc.x-sw/2; - g.drawString(p.text, tx, p.textloc.y+asc/3); - if (p.lineOver) { - int ya = p.textloc.y-asc+asc/3; - g.drawLine(tx, ya, tx+sw, ya); - } - break; - } - } - - drawLabel(g, labelX, labelY); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - drawThickPolygon(g, rectPointsX, rectPointsY, 4); - drawPosts(g); - g.restore(); - } - int rectPointsX[], rectPointsY[]; - Pin pins[]; - int sizeX, sizeY, flippedSizeX, flippedSizeY; - boolean lastClock; - void drag(int xx, int yy) { - yy = sim.snapGrid(yy); - if (xx < x) { - xx = x; yy = y; - } else { - y = y2 = yy; - x2 = sim.snapGrid(xx); + } + + boolean needsBits() { + return false; + } + + boolean hasCustomVoltage() { + return (flags & FLAG_CUSTOM_VOLTAGE) != 0; + } + + boolean isDigitalChip() { + return true; + } + + double getThreshold() { + return highVoltage / 2; + } + + int defaultBitCount() { + return 4; + } + + void setSize(int s) { + csize = s; + cspc = 8 * s; + cspc2 = cspc * 2; + flags &= ~FLAG_SMALL; + flags |= (s == 1) ? FLAG_SMALL : 0; + } + + abstract void setupPins(); + + void draw(Graphics g) { + drawChip(g); + } + + void drawChip(Graphics g) { + int i; + g.save(); + Font f = new Font("normal", 0, 10 * csize); + // FontMetrics fm = g.getFontMetrics(); + boolean hasVertical = false; + // check if there are any vertical pins. if not, we can make the labels wider + for (i = 0; i != getPostCount(); i++) + if (pins[i].side == SIDE_N || pins[i].side == SIDE_S) { + hasVertical = true; + break; } - setPoints(); - } - - void drawLabel(Graphics g, int x, int y) {} - int labelX, labelY; - - void setPoints() { - if (x2-x > sizeX*cspc2 && this == sim.dragElm) - setSize(2); - int x0 = x+cspc2; int y0 = y; - int xr = x0-cspc; - int yr = y0-cspc; - flippedSizeX = sizeX; - flippedSizeY = sizeY; - if (isFlippedXY()) { - flippedSizeX = sizeY; - flippedSizeY = sizeX; + for (i = 0; i != getPostCount(); i++) { + g.setFont(f); + Pin p = pins[i]; + setVoltageColor(g, volts[i]); + Point a = p.post; + Point b = p.stub; + drawThickLine(g, a, b); + p.curcount = updateDotCount(p.current, p.curcount); + drawDots(g, b, a, p.curcount); + if (p.bubble) { + g.setColor(sim.getBackgroundColor()); + drawThickCircle(g, p.bubbleX, p.bubbleY, 1); + g.setColor(lightGrayColor); + drawThickCircle(g, p.bubbleX, p.bubbleY, 3); } - int xs = flippedSizeX*cspc2; - int ys = flippedSizeY*cspc2; - int i; - for (i = 0; i != getPostCount(); i++) { - Pin p = pins[i]; - p.side = p.side0; - if ((flags & FLAG_FLIP_XY) != 0) - p.side = sideFlipXY[p.side]; - switch (p.side) { - case SIDE_N: p.setPoint(x0, y0, 1, 0, 0, -1, 0, 0); break; - case SIDE_S: p.setPoint(x0, y0, 1, 0, 0, 1, 0, ys-cspc2);break; - case SIDE_W: p.setPoint(x0, y0, 0, 1, -1, 0, 0, 0); break; - case SIDE_E: p.setPoint(x0, y0, 0, 1, 1, 0, xs-cspc2, 0);break; + if (p.clockPointsX != null) + g.drawPolyline(p.clockPointsX, p.clockPointsY, 3); + g.setColor(p.selected ? selectColor : whiteColor); + int fsz = 10 * csize; + double availSpace = cspc * 2 - 8; + // allow a little more space if the chip is wide and there are no vertical pins + // (we could still do this if vertical pins are present but then we would have + // to do + // more work to avoid overlaps) + if (!hasVertical && sizeX > 2) + availSpace = cspc * 2.5 + cspc * (sizeX - 3); + while (true) { + int sw = (int) g.context.measureText(p.text).getWidth(); + // scale font down if it's too big + if (sw > availSpace) { + fsz -= 1; + Font f2 = new Font("normal", 0, fsz); + g.setFont(f2); + continue; + } + int asc = (int) g.currentFontSize; + int tx; + // put text closer to edge if it's on left or right. + if (p.side == flippedXSide(SIDE_W)) + tx = p.textloc.x - (cspc - 5); + else if (p.side == flippedXSide(SIDE_E)) + tx = p.textloc.x + (cspc - 5) - sw; + else + tx = p.textloc.x - sw / 2; + g.drawString(p.text, tx, p.textloc.y + asc / 3); + if (p.lineOver) { + int ya = p.textloc.y - asc + asc / 3; + g.drawLine(tx, ya, tx + sw, ya); } + break; } - rectPointsX = new int[] { xr, xr+xs, xr+xs, xr }; - rectPointsY = new int[] { yr, yr, yr+ys, yr+ys }; - setBbox(xr, yr, rectPointsX[2], rectPointsY[2]); - labelX = xr+xs/2; - labelY = yr+ys/2; } - - // see if we can move pin to position xp, yp, and return the new position - boolean getPinPos(int xp, int yp, int pin, int pos[]) { - int x0 = x+cspc2; int y0 = y; - int xr = x0-cspc; - int yr = y0-cspc; - double xd = (xp-xr)/(double)cspc2 - .5; - double yd = (yp-yr)/(double)cspc2 - .5; - if (xd < .25 && yd > 0 && yd < sizeY-1) { - pos[0] = (int) Math.max(Math.round(yd), 0); - pos[1] = SIDE_W; - } else if (xd > sizeX-.75) { - pos[0] = (int) Math.min(Math.round(yd), sizeY-1); - pos[1] = SIDE_E; - } else if (yd < .25) { - pos[0] = (int) Math.max(Math.round(xd), 0); - pos[1] = SIDE_N; - } else if (yd > sizeY-.75) { - pos[0] = (int) Math.min(Math.round(xd), sizeX-1); - pos[1] = SIDE_S; - } else - return false; - - if (pos[0] < 0) - return false; - if ((pos[1] == SIDE_N || pos[1] == SIDE_S) && pos[0] >= sizeX) - return false; - if ((pos[1] == SIDE_W || pos[1] == SIDE_E) && pos[0] >= sizeY) - return false; - return true; + + drawLabel(g, labelX, labelY); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickPolygon(g, rectPointsX, rectPointsY, 4); + drawPosts(g); + g.restore(); + } + + int rectPointsX[], rectPointsY[]; + Pin pins[]; + int sizeX, sizeY, flippedSizeX, flippedSizeY; + boolean lastClock; + + void drag(int xx, int yy) { + yy = sim.snapGrid(yy); + if (xx < x) { + xx = x; + yy = y; + } else { + y = y2 = yy; + x2 = sim.snapGrid(xx); } - - int getOverlappingPin(int p1, int p2, int pin) { - for (int i = 0; i != getPostCount(); i++) { - if (pin == i) - continue; - if (pins[i].overlaps(p1, p2)) - return i; + setPoints(); + } + + void drawLabel(Graphics g, int x, int y) { + } + + int labelX, labelY; + + void setPoints() { + if (x2 - x > sizeX * cspc2 && this == sim.dragElm) + setSize(2); + int x0 = x + cspc2; + int y0 = y; + int xr = x0 - cspc; + int yr = y0 - cspc; + flippedSizeX = sizeX; + flippedSizeY = sizeY; + if (isFlippedXY()) { + flippedSizeX = sizeY; + flippedSizeY = sizeX; + } + int xs = flippedSizeX * cspc2; + int ys = flippedSizeY * cspc2; + int i; + for (i = 0; i != getPostCount(); i++) { + Pin p = pins[i]; + p.side = p.side0; + if ((flags & FLAG_FLIP_XY) != 0) + p.side = sideFlipXY[p.side]; + switch (p.side) { + case SIDE_N: + p.setPoint(x0, y0, 1, 0, 0, -1, 0, 0); + break; + case SIDE_S: + p.setPoint(x0, y0, 1, 0, 0, 1, 0, ys - cspc2); + break; + case SIDE_W: + p.setPoint(x0, y0, 0, 1, -1, 0, 0, 0); + break; + case SIDE_E: + p.setPoint(x0, y0, 0, 1, 1, 0, xs - cspc2, 0); + break; } - return -1; } - - Point getPost(int n) { - return pins[n].post; + rectPointsX = new int[] { xr, xr + xs, xr + xs, xr }; + rectPointsY = new int[] { yr, yr, yr + ys, yr + ys }; + setBbox(xr, yr, rectPointsX[2], rectPointsY[2]); + labelX = xr + xs / 2; + labelY = yr + ys / 2; + } + + // see if we can move pin to position xp, yp, and return the new position + boolean getPinPos(int xp, int yp, int pin, int pos[]) { + int x0 = x + cspc2; + int y0 = y; + int xr = x0 - cspc; + int yr = y0 - cspc; + double xd = (xp - xr) / (double) cspc2 - .5; + double yd = (yp - yr) / (double) cspc2 - .5; + if (xd < .25 && yd > 0 && yd < sizeY - 1) { + pos[0] = (int) Math.max(Math.round(yd), 0); + pos[1] = SIDE_W; + } else if (xd > sizeX - .75) { + pos[0] = (int) Math.min(Math.round(yd), sizeY - 1); + pos[1] = SIDE_E; + } else if (yd < .25) { + pos[0] = (int) Math.max(Math.round(xd), 0); + pos[1] = SIDE_N; + } else if (yd > sizeY - .75) { + pos[0] = (int) Math.min(Math.round(xd), sizeX - 1); + pos[1] = SIDE_S; + } else + return false; + + if (pos[0] < 0) + return false; + if ((pos[1] == SIDE_N || pos[1] == SIDE_S) && pos[0] >= sizeX) + return false; + if ((pos[1] == SIDE_W || pos[1] == SIDE_E) && pos[0] >= sizeY) + return false; + return true; + } + + int getOverlappingPin(int p1, int p2, int pin) { + for (int i = 0; i != getPostCount(); i++) { + if (pin == i) + continue; + if (pins[i].overlaps(p1, p2)) + return i; } - abstract int getVoltageSourceCount(); // output count - void setVoltageSource(int j, int vs) { - int i; - for (i = 0; i != getPostCount(); i++) { - Pin p = pins[i]; - if (p.output && j-- == 0) { - p.voltSource = vs; - return; - } + return -1; + } + + Point getPost(int n) { + return pins[n].post; + } + + abstract int getVoltageSourceCount(); // output count + + void setVoltageSource(int j, int vs) { + int i; + for (i = 0; i != getPostCount(); i++) { + Pin p = pins[i]; + if (p.output && j-- == 0) { + p.voltSource = vs; + return; } - System.out.println("setVoltageSource failed for " + this); } - void stamp() { - int i; - int vsc = 0; - for (i = 0; i != getPostCount(); i++) { - Pin p = pins[i]; - if (p.output) { - sim.stampVoltageSource(0, nodes[i], p.voltSource); - vsc++; - } + System.out.println("setVoltageSource failed for " + this); + } + + void stamp() { + int i; + int vsc = 0; + for (i = 0; i != getPostCount(); i++) { + Pin p = pins[i]; + if (p.output) { + sim.stampVoltageSource(0, nodes[i], p.voltSource); + vsc++; } - if (vsc != getVoltageSourceCount()) - CirSim.console("voltage source count does not match number of outputs"); } - void execute() {} - void doStep() { - int i; - for (i = 0; i != getPostCount(); i++) { - Pin p = pins[i]; - if (!p.output) - p.value = volts[i] > getThreshold(); - } - execute(); - for (i = 0; i != getPostCount(); i++) { - Pin p = pins[i]; - if (p.output) - sim.updateVoltageSource(0, nodes[i], p.voltSource, - p.value ? highVoltage : 0); - } + if (vsc != getVoltageSourceCount()) + CirSim.console("voltage source count does not match number of outputs"); + } + + void execute() { + } + + void doStep() { + int i; + for (i = 0; i != getPostCount(); i++) { + Pin p = pins[i]; + if (!p.output) + p.value = volts[i] > getThreshold(); } - void reset() { - int i; - for (i = 0; i != getPostCount(); i++) { - pins[i].value = false; - pins[i].curcount = 0; - volts[i] = 0; - } - lastClock = false; + execute(); + for (i = 0; i != getPostCount(); i++) { + Pin p = pins[i]; + if (p.output) + sim.updateVoltageSource(0, nodes[i], p.voltSource, p.value ? highVoltage : 0); } - - String dump() { - if (highVoltage == 5) - flags &= ~FLAG_CUSTOM_VOLTAGE; + } + + void reset() { + int i; + for (i = 0; i != getPostCount(); i++) { + pins[i].value = false; + pins[i].curcount = 0; + volts[i] = 0; + } + lastClock = false; + } + + String dump() { + if (highVoltage == 5) + flags &= ~FLAG_CUSTOM_VOLTAGE; + else + flags |= FLAG_CUSTOM_VOLTAGE; + + String s = super.dump(); + if (needsBits()) + s += " " + bits; + if (hasCustomVoltage()) + s += " " + highVoltage; + int i; + for (i = 0; i != getPostCount(); i++) { + if (pins[i].state) + s += " " + volts[i]; + } + return s; + } + + void writeOutput(int n, boolean value) { + if (!pins[n].output) + CirSim.console("pin " + n + " is not an output!"); + pins[n].value = value; + } + + void getInfo(String arr[]) { + arr[0] = getChipName(); + int i, a = 1; + for (i = 0; i != getPostCount(); i++) { + Pin p = pins[i]; + if (arr[a] != null) + arr[a] += "; "; else - flags |= FLAG_CUSTOM_VOLTAGE; - - String s = super.dump(); - if (needsBits()) - s += " " + bits; - if (hasCustomVoltage()) - s += " " + highVoltage; - int i; - for (i = 0; i != getPostCount(); i++) { - if (pins[i].state) - s += " " + volts[i]; - } - return s; + arr[a] = ""; + String t = p.text; + if (p.lineOver) + t += '\''; + if (p.clock) + t = "Clk"; + arr[a] += t + " = " + getVoltageText(volts[i]); + if (i % 2 == 1) + a++; } - - void writeOutput(int n, boolean value) { - if (!pins[n].output) - CirSim.console("pin " + n + " is not an output!"); - pins[n].value = value; + } + + void setCurrent(int x, double c) { + int i; + for (i = 0; i != getPostCount(); i++) + if (pins[i].output && pins[i].voltSource == x) + pins[i].current = c; + } + + String getChipName() { + return "chip"; + } + + boolean getConnection(int n1, int n2) { + return false; + } + + boolean hasGroundConnection(int n1) { + return pins[n1].output; + } + + double getCurrentIntoNode(int n) { + return pins[n].current; + } + + boolean isFlippedXY() { + return (flags & FLAG_FLIP_XY) != 0; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip X", (flags & FLAG_FLIP_X) != 0); + return ei; } - - void getInfo(String arr[]) { - arr[0] = getChipName(); - int i, a = 1; - for (i = 0; i != getPostCount(); i++) { - Pin p = pins[i]; - if (arr[a] != null) - arr[a] += "; "; - else - arr[a] = ""; - String t = p.text; - if (p.lineOver) - t += '\''; - if (p.clock) - t = "Clk"; - arr[a] += t + " = " + getVoltageText(volts[i]); - if (i % 2 == 1) - a++; - } + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip Y", (flags & FLAG_FLIP_Y) != 0); + return ei; } - void setCurrent(int x, double c) { - int i; - for (i = 0; i != getPostCount(); i++) - if (pins[i].output && pins[i].voltSource == x) - pins[i].current = c; + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip X/Y", (flags & FLAG_FLIP_XY) != 0); + return ei; } - String getChipName() { return "chip"; } - boolean getConnection(int n1, int n2) { return false; } - boolean hasGroundConnection(int n1) { - return pins[n1].output; + if (!isDigitalChip()) + return getChipEditInfo(n - 3); + + if (n == 3) + return new EditInfo("High Logic Voltage", highVoltage); + + return getChipEditInfo(n - 4); + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) { + flags = ei.changeFlag(flags, FLAG_FLIP_X); + setPoints(); } - - double getCurrentIntoNode(int n) { - return pins[n].current; + if (n == 1) { + flags = ei.changeFlag(flags, FLAG_FLIP_Y); + setPoints(); } - - boolean isFlippedXY() { return (flags & FLAG_FLIP_XY) != 0; } - - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip X", (flags & FLAG_FLIP_X) != 0); - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip Y", (flags & FLAG_FLIP_Y) != 0); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip X/Y", (flags & FLAG_FLIP_XY) != 0); - return ei; - } - if (!isDigitalChip()) - return getChipEditInfo(n-3); - - if (n == 3) - return new EditInfo("High Logic Voltage", highVoltage); - - return getChipEditInfo(n-4); + if (n == 2) { + flags = ei.changeFlag(flags, FLAG_FLIP_XY); + setPoints(); } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) { - flags = ei.changeFlag(flags, FLAG_FLIP_X); - setPoints(); - } - if (n == 1) { - flags = ei.changeFlag(flags, FLAG_FLIP_Y); - setPoints(); - } - if (n == 2) { - flags = ei.changeFlag(flags, FLAG_FLIP_XY); - setPoints(); - } - if (!isDigitalChip()) { - if (n >= 3) - setChipEditValue(n-3, ei); - return; + if (!isDigitalChip()) { + if (n >= 3) + setChipEditValue(n - 3, ei); + return; + } + + if (n == 3) + highVoltage = ei.value; + + if (n >= 4) + setChipEditValue(n - 4, ei); + } + + public EditInfo getChipEditInfo(int n) { + return null; + } + + public void setChipEditValue(int n, EditInfo ei) { + } + + static String writeBits(boolean[] data) { + StringBuilder sb = new StringBuilder(); + int integer = 0; + int bitIndex = 0; + for (int i = 0; i < data.length; i++) { + if (bitIndex >= Integer.SIZE) { + // Flush completed integer + sb.append(' '); + sb.append(integer); + integer = 0; + bitIndex = 0; } - - if (n == 3) - highVoltage = ei.value; - - if (n >= 4) - setChipEditValue(n-4, ei); + if (data[i]) + integer |= 1 << bitIndex; + bitIndex++; } - - public EditInfo getChipEditInfo(int n) { return null; } - public void setChipEditValue(int n, EditInfo ei) { } - - static String writeBits(boolean[] data) { - StringBuilder sb = new StringBuilder(); - int integer = 0; - int bitIndex = 0; - for (int i = 0; i < data.length; i++) { - if (bitIndex >= Integer.SIZE) { - //Flush completed integer - sb.append(' '); - sb.append(integer); - integer = 0; - bitIndex = 0; - } - if (data[i]) - integer |= 1 << bitIndex; - bitIndex++; - } - if (bitIndex > 0) { - sb.append(' '); - sb.append(integer); - } - return sb.toString(); + if (bitIndex > 0) { + sb.append(' '); + sb.append(integer); } - static void readBits(StringTokenizer st, boolean[] output) { - int integer = 0; - int bitIndex = Integer.MAX_VALUE; - for (int i = 0; i < output.length; i++) { - if (bitIndex >= Integer.SIZE) - if (st.hasMoreTokens()) { - integer = Integer.parseInt(st.nextToken()); //Load next integer - bitIndex = 0; - } else - break; //Data is absent - - output[i] = (integer & (1 << bitIndex)) != 0; - bitIndex++; - } + return sb.toString(); + } + + static void readBits(StringTokenizer st, boolean[] output) { + int integer = 0; + int bitIndex = Integer.MAX_VALUE; + for (int i = 0; i < output.length; i++) { + if (bitIndex >= Integer.SIZE) + if (st.hasMoreTokens()) { + integer = Integer.parseInt(st.nextToken()); // Load next integer + bitIndex = 0; + } else + break; // Data is absent + + output[i] = (integer & (1 << bitIndex)) != 0; + bitIndex++; } + } - static final int SIDE_N = 0; - static final int SIDE_S = 1; - static final int SIDE_W = 2; - static final int SIDE_E = 3; - - static final int sideFlipXY[] = { SIDE_W, SIDE_E, SIDE_N, SIDE_S }; + static final int SIDE_N = 0; + static final int SIDE_S = 1; + static final int SIDE_W = 2; + static final int SIDE_E = 3; - int flippedXSide(int s) { - if ((flags & FLAG_FLIP_X) == 0) - return s; - if (s == SIDE_W) - return SIDE_E; - if (s == SIDE_E) - return SIDE_W; + static final int sideFlipXY[] = { SIDE_W, SIDE_E, SIDE_N, SIDE_S }; + + int flippedXSide(int s) { + if ((flags & FLAG_FLIP_X) == 0) return s; + if (s == SIDE_W) + return SIDE_E; + if (s == SIDE_E) + return SIDE_W; + return s; + } + + class Pin { + Pin(int p, int s, String t) { + pos = p; + side0 = side = s; + text = t; } - - class Pin { - Pin(int p, int s, String t) { - pos = p; side0 = side = s; text = t; - } - Point post, stub; - Point textloc; - int pos, side, side0, voltSource, bubbleX, bubbleY; - String text; - boolean lineOver, bubble, clock, output, value, state, selected; - double curcount, current; - int clockPointsX[], clockPointsY[]; - void setPoint(int px, int py, int dx, int dy, int dax, int day, int sx, int sy) { - if ((flags & FLAG_FLIP_X) != 0) { - dx = -dx; - dax = -dax; - px += cspc2*(flippedSizeX-1); - sx = -sx; - } - if ((flags & FLAG_FLIP_Y) != 0) { - dy = -dy; - day = -day; - py += cspc2*(flippedSizeY-1); - sy = -sy; - } - int xa = px+cspc2*dx*pos+sx; - int ya = py+cspc2*dy*pos+sy; - post = new Point(xa+dax*cspc2, ya+day*cspc2); - stub = new Point(xa+dax*cspc , ya+day*cspc ); - textloc = new Point(xa , ya ); - if (bubble) { - bubbleX = xa+dax*10*csize; - bubbleY = ya+day*10*csize; - } - if (clock) { - if (clockPointsX == null) { - clockPointsX = new int[3]; - clockPointsY = new int[3]; - } - clockPointsX[0] = xa+dax*cspc-dx*cspc/2; - clockPointsY[0] = ya+day*cspc-dy*cspc/2; - clockPointsX[1] = xa; - clockPointsY[1] = ya; - clockPointsX[2] = xa+dax*cspc+dx*cspc/2; - clockPointsY[2] = ya+day*cspc+dy*cspc/2; - if (text.length() > 0) { - // See for example http://127.0.0.1:8000/circuitjs.html?ctz=CQAgjCAMB0l3BWcMBMcUHYMGZIA4UA2ATmIxAUgpABZsKBTAWjDACgAncDQkPKlDSr8oySGzTkwPPlTAo8s2iADCAGQDSALgCSAOQBqWle0khBwgUJDYUy9dv1GVKCZHIXwNGubyKw3vaauobG2G5SMgE+0rxgxHY+DiHONJzcvCKxXj5y8OnZ0ebWRXlw6Z5FniJl4kA - clockPointsX[1] += dax*cspc/2; - clockPointsY[1] += day*cspc/2; - textloc.x -= dax*cspc/2; - textloc.y -= day*cspc/4; - } - } - else { - clockPointsX = null; - clockPointsY = null; - } - } - // convert position, side to a grid position (0=top left) so we can detect overlaps - int toGrid(int p, int s) { - if (s == SIDE_N) - return p; - if (s == SIDE_S) - return p+sizeX*(sizeY-1); - if (s == SIDE_W) - return p*sizeX; - if (s == SIDE_E) - return p*sizeX+sizeX-1; - return -1; + Point post, stub; + Point textloc; + int pos, side, side0, voltSource, bubbleX, bubbleY; + String text; + boolean lineOver, bubble, clock, output, value, state, selected; + double curcount, current; + int clockPointsX[], clockPointsY[]; + + void setPoint(int px, int py, int dx, int dy, int dax, int day, int sx, int sy) { + if ((flags & FLAG_FLIP_X) != 0) { + dx = -dx; + dax = -dax; + px += cspc2 * (flippedSizeX - 1); + sx = -sx; + } + if ((flags & FLAG_FLIP_Y) != 0) { + dy = -dy; + day = -day; + py += cspc2 * (flippedSizeY - 1); + sy = -sy; } - - boolean overlaps(int p, int s) { - int g = toGrid(p, s); - if (g == -1) - return true; - return toGrid(pos, side) == g; + int xa = px + cspc2 * dx * pos + sx; + int ya = py + cspc2 * dy * pos + sy; + post = new Point(xa + dax * cspc2, ya + day * cspc2); + stub = new Point(xa + dax * cspc, ya + day * cspc); + textloc = new Point(xa, ya); + if (bubble) { + bubbleX = xa + dax * 10 * csize; + bubbleY = ya + day * 10 * csize; } - - void fixName() { - if (text.startsWith("/")) { - text = text.substring(1); - lineOver = true; + if (clock) { + if (clockPointsX == null) { + clockPointsX = new int[3]; + clockPointsY = new int[3]; } - else if (text.startsWith("#")) { - text = text.substring(1); - bubble = true; + clockPointsX[0] = xa + dax * cspc - dx * cspc / 2; + clockPointsY[0] = ya + day * cspc - dy * cspc / 2; + clockPointsX[1] = xa; + clockPointsY[1] = ya; + clockPointsX[2] = xa + dax * cspc + dx * cspc / 2; + clockPointsY[2] = ya + day * cspc + dy * cspc / 2; + if (text.length() > 0) { + // See for example + // http://127.0.0.1:8000/circuitjs.html?ctz=CQAgjCAMB0l3BWcMBMcUHYMGZIA4UA2ATmIxAUgpABZsKBTAWjDACgAncDQkPKlDSr8oySGzTkwPPlTAo8s2iADCAGQDSALgCSAOQBqWle0khBwgUJDYUy9dv1GVKCZHIXwNGubyKw3vaauobG2G5SMgE+0rxgxHY+DiHONJzcvCKxXj5y8OnZ0ebWRXlw6Z5FniJl4kA + clockPointsX[1] += dax * cspc / 2; + clockPointsY[1] += day * cspc / 2; + textloc.x -= dax * cspc / 2; + textloc.y -= day * cspc / 4; } + } else { + clockPointsX = null; + clockPointsY = null; + } + } - String result = text.replaceAll("CLK:", ""); - if (result.length() != text.length()) { - clock = true; - text = result; - } - result = text.replaceAll("INV:", ""); - if (result.length() != text.length()) { - bubble = true; - text = result; - } + // convert position, side to a grid position (0=top left) so we can detect + // overlaps + int toGrid(int p, int s) { + if (s == SIDE_N) + return p; + if (s == SIDE_S) + return p + sizeX * (sizeY - 1); + if (s == SIDE_W) + return p * sizeX; + if (s == SIDE_E) + return p * sizeX + sizeX - 1; + return -1; + } - if (text.compareToIgnoreCase("clk") == 0) { - text = ""; - clock = true; - } + boolean overlaps(int p, int s) { + int g = toGrid(p, s); + if (g == -1) + return true; + return toGrid(pos, side) == g; + } + + void fixName() { + if (text.startsWith("/")) { + text = text.substring(1); + lineOver = true; + } else if (text.startsWith("#")) { + text = text.substring(1); + bubble = true; + } + + String result = text.replaceAll("CLK:", ""); + if (result.length() != text.length()) { + clock = true; + text = result; + } + result = text.replaceAll("INV:", ""); + if (result.length() != text.length()) { + bubble = true; + text = result; } - + if (text.compareToIgnoreCase("clk") == 0) { + text = ""; + clock = true; + } } - } + } +} diff --git a/src/com/lushprojects/circuitjs1/client/Choice.java b/src/com/lushprojects/circuitjs1/client/Choice.java index acbb1539..00351413 100644 --- a/src/com/lushprojects/circuitjs1/client/Choice.java +++ b/src/com/lushprojects/circuitjs1/client/Choice.java @@ -23,16 +23,16 @@ import com.lushprojects.circuitjs1.client.util.Locale; public class Choice extends ListBox { - - Choice() { - super(); - } - - public void add(String s){ - this.addItem(Locale.LS(s)); - } - - public void select(int i){ - this.setSelectedIndex(i); - } + + Choice() { + super(); + } + + public void add(String s) { + this.addItem(Locale.LS(s)); + } + + public void select(int i) { + this.setSelectedIndex(i); + } } diff --git a/src/com/lushprojects/circuitjs1/client/CirSim.java b/src/com/lushprojects/circuitjs1/client/CirSim.java index 7473db15..30f5b822 100644 --- a/src/com/lushprojects/circuitjs1/client/CirSim.java +++ b/src/com/lushprojects/circuitjs1/client/CirSim.java @@ -98,9 +98,8 @@ import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.user.client.DOM; -public class CirSim implements MouseDownHandler, MouseMoveHandler, MouseUpHandler, -ClickHandler, DoubleClickHandler, ContextMenuHandler, NativePreviewHandler, -MouseOutHandler, MouseWheelHandler { +public class CirSim implements MouseDownHandler, MouseMoveHandler, MouseUpHandler, ClickHandler, DoubleClickHandler, + ContextMenuHandler, NativePreviewHandler, MouseOutHandler, MouseWheelHandler { Random random; Button resetButton; @@ -108,7 +107,7 @@ public class CirSim implements MouseDownHandler, MouseMoveHandler, MouseUpHandle Button dumpMatrixButton; MenuItem aboutItem; MenuItem importFromLocalFileItem, importFromTextItem, exportAsUrlItem, exportAsLocalFileItem, exportAsTextItem, - printItem, recoverItem, saveFileItem; + printItem, recoverItem, saveFileItem; MenuItem importFromDropboxItem; MenuItem undoItem, redoItem, cutItem, copyItem, pasteItem, selectAllItem, optionsItem; MenuBar optionsMenuBar; @@ -278,17 +277,17 @@ public class CirSim implements MouseDownHandler, MouseMoveHandler, MouseUpHandle static final int POSTGRABSQ = 25; static final int MINPOSTGRABSIZE = 256; final Timer timer = new Timer() { - public void run() { - updateCircuit(); - } + public void run() { + updateCircuit(); + } }; final int FASTTIMER = 16; int getrand(int x) { - int q = random.nextInt(); - if (q < 0) - q = -q; - return q % x; + int q = random.nextInt(); + if (q < 0) + q = -q; + return q % x; } static native float devicePixelRatio() /*-{ @@ -296,56 +295,57 @@ static native float devicePixelRatio() /*-{ }-*/; void checkCanvasSize() { - if (cv.getCoordinateSpaceWidth() != (int) (canvasWidth * devicePixelRatio())) - setCanvasSize(); - } - - public void setCanvasSize(){ - int width, height; - width=(int)RootLayoutPanel.get().getOffsetWidth(); - height=(int)RootLayoutPanel.get().getOffsetHeight(); - height=height-MENUBARHEIGHT; - width=width-VERTICALPANELWIDTH; - width = Math.max(width, 0); // avoid exception when setting negative width - height = Math.max(height, 0); - if (cv != null) { - cv.setWidth(width + "PX"); - cv.setHeight(height + "PX"); - canvasWidth = width; - canvasHeight = height; - float scale = devicePixelRatio(); - cv.setCoordinateSpaceWidth((int)(width*scale)); - cv.setCoordinateSpaceHeight((int)(height*scale)); - } + if (cv.getCoordinateSpaceWidth() != (int) (canvasWidth * devicePixelRatio())) + setCanvasSize(); + } + + public void setCanvasSize() { + int width, height; + width = (int) RootLayoutPanel.get().getOffsetWidth(); + height = (int) RootLayoutPanel.get().getOffsetHeight(); + height = height - MENUBARHEIGHT; + width = width - VERTICALPANELWIDTH; + width = Math.max(width, 0); // avoid exception when setting negative width + height = Math.max(height, 0); + if (cv != null) { + cv.setWidth(width + "PX"); + cv.setHeight(height + "PX"); + canvasWidth = width; + canvasHeight = height; + float scale = devicePixelRatio(); + cv.setCoordinateSpaceWidth((int) (width * scale)); + cv.setCoordinateSpaceHeight((int) (height * scale)); + } - setCircuitArea(); + setCircuitArea(); // recenter circuit in case canvas was hidden at startup - if (transform[0] == 0) - centreCircuit(); + if (transform[0] == 0) + centreCircuit(); } - + void setCircuitArea() { - int height = canvasHeight; - int width = canvasWidth; - int h = (int) ((double)height * scopeHeightFraction); - /*if (h < 128 && winSize.height > 300) - h = 128;*/ - if (scopeCount == 0) - h = 0; - circuitArea = new Rectangle(0, 0, width, height-h); + int height = canvasHeight; + int width = canvasWidth; + int h = (int) ((double) height * scopeHeightFraction); + /* + * if (h < 128 && winSize.height > 300) h = 128; + */ + if (scopeCount == 0) + h = 0; + circuitArea = new Rectangle(0, 0, width, height - h); } - + native String decompress(String dump) /*-{ return $wnd.LZString.decompressFromEncodedURIComponent(dump); }-*/; -// Circuit applet; + // Circuit applet; CirSim() { -// super("Circuit Simulator v1.6d"); -// applet = a; -// useFrame = false; + // super("Circuit Simulator v1.6d"); + // applet = a; + // useFrame = false; theSim = this; } @@ -353,10 +353,9 @@ native String decompress(String dump) /*-{ String startLabel = null; String startCircuitText = null; String startCircuitLink = null; -// String baseURL = "http://www.falstad.com/circuit/"; - - public void init() { + // String baseURL = "http://www.falstad.com/circuit/"; + public void init() { boolean printable = false; boolean convention = true; @@ -382,29 +381,28 @@ public void init() { boolean euroGates = false; try { - //baseURL = applet.getDocumentBase().getFile(); + // baseURL = applet.getDocumentBase().getFile(); // look for circuit embedded in URL - // String doc = applet.getDocumentBase().toString(); - String cct=qp.getValue("cct"); - if (cct!=null) + // String doc = applet.getDocumentBase().toString(); + String cct = qp.getValue("cct"); + if (cct != null) startCircuitText = cct.replace("%24", "$"); if (startCircuitText == null) startCircuitText = getElectronStartCircuitText(); - String ctz=qp.getValue("ctz"); - if (ctz!= null) + String ctz = qp.getValue("ctz"); + if (ctz != null) startCircuitText = decompress(ctz); startCircuit = qp.getValue("startCircuit"); - startLabel = qp.getValue("startLabel"); + startLabel = qp.getValue("startLabel"); startCircuitLink = qp.getValue("startCircuitLink"); euroRes = qp.getBooleanValue("euroResistors", false); euroGates = qp.getBooleanValue("IECGates", getOptionFromStorage("euroGates", weAreInGermany())); - usRes = qp.getBooleanValue("usResistors", false); + usRes = qp.getBooleanValue("usResistors", false); running = qp.getBooleanValue("running", true); hideSidebar = qp.getBooleanValue("hideSidebar", false); hideMenu = qp.getBooleanValue("hideMenu", false); printable = qp.getBooleanValue("whiteBackground", getOptionFromStorage("whiteBackground", false)); - convention = qp.getBooleanValue("conventionalCurrent", - getOptionFromStorage("conventionalCurrent", true)); + convention = qp.getBooleanValue("conventionalCurrent", getOptionFromStorage("conventionalCurrent", true)); noEditing = !qp.getBooleanValue("editable", true); mouseWheelEdit = qp.getBooleanValue("mouseWheelEdit", getOptionFromStorage("mouseWheelEdit", true)); positiveColor = qp.getValue("positiveColor"); @@ -414,7 +412,8 @@ public void init() { currentColor = qp.getValue("currentColor"); mouseModeReq = qp.getValue("mouseMode"); hideInfoBox = qp.getBooleanValue("hideInfoBox", false); - } catch (Exception e) { } + } catch (Exception e) { + } boolean euroSetting = false; if (euroRes) @@ -437,15 +436,16 @@ else if (usRes) if (isElectron()) fileMenuBar.addItem(menuItemWithShortcut("window", "New Window...", Locale.LS(ctrlMetaKey + "N"), new MyCommand("file", "newwindow"))); - + fileMenuBar.addItem(iconMenuItem("doc-new", "New Blank Circuit", new MyCommand("file", "newblankcircuit"))); importFromLocalFileItem = menuItemWithShortcut("folder", "Open File...", Locale.LS(ctrlMetaKey + "O"), - new MyCommand("file","importfromlocalfile")); + new MyCommand("file", "importfromlocalfile")); importFromLocalFileItem.setEnabled(LoadFile.isSupported()); fileMenuBar.addItem(importFromLocalFileItem); - importFromTextItem = iconMenuItem("doc-text", "Import From Text...", new MyCommand("file","importfromtext")); + importFromTextItem = iconMenuItem("doc-text", "Import From Text...", new MyCommand("file", "importfromtext")); fileMenuBar.addItem(importFromTextItem); - importFromDropboxItem = iconMenuItem("dropbox", "Import From Dropbox...", new MyCommand("file", "importfromdropbox")); + importFromDropboxItem = iconMenuItem("dropbox", "Import From Dropbox...", + new MyCommand("file", "importfromdropbox")); fileMenuBar.addItem(importFromDropboxItem); if (isElectron()) { saveFileItem = fileMenuBar.addItem(menuItemWithShortcut("floppy", "Save", Locale.LS(ctrlMetaKey + "S"), @@ -453,32 +453,34 @@ else if (usRes) fileMenuBar.addItem(iconMenuItem("floppy", "Save As...", new MyCommand("file", "saveas"))); } else { exportAsLocalFileItem = menuItemWithShortcut("floppy", "Save As...", Locale.LS(ctrlMetaKey + "S"), - new MyCommand("file","exportaslocalfile")); + new MyCommand("file", "exportaslocalfile")); exportAsLocalFileItem.setEnabled(ExportAsLocalFileDialog.downloadIsSupported()); fileMenuBar.addItem(exportAsLocalFileItem); } - exportAsUrlItem = iconMenuItem("export", "Export As Link...", new MyCommand("file","exportasurl")); + exportAsUrlItem = iconMenuItem("export", "Export As Link...", new MyCommand("file", "exportasurl")); fileMenuBar.addItem(exportAsUrlItem); - exportAsTextItem = iconMenuItem("export", "Export As Text...", new MyCommand("file","exportastext")); + exportAsTextItem = iconMenuItem("export", "Export As Text...", new MyCommand("file", "exportastext")); fileMenuBar.addItem(exportAsTextItem); - fileMenuBar.addItem(iconMenuItem("export", "Export As Image...", new MyCommand("file","exportasimage"))); - fileMenuBar.addItem(iconMenuItem("export", "Export As SVG...", new MyCommand("file","exportassvg"))); - fileMenuBar.addItem(iconMenuItem("microchip", "Create Subcircuit...", new MyCommand("file","createsubcircuit"))); + fileMenuBar.addItem(iconMenuItem("export", "Export As Image...", new MyCommand("file", "exportasimage"))); + fileMenuBar.addItem(iconMenuItem("export", "Export As SVG...", new MyCommand("file", "exportassvg"))); + fileMenuBar + .addItem(iconMenuItem("microchip", "Create Subcircuit...", new MyCommand("file", "createsubcircuit"))); fileMenuBar.addItem(iconMenuItem("magic", "Find DC Operating Point", new MyCommand("file", "dcanalysis"))); - recoverItem = iconMenuItem("back-in-time", "Recover Auto-Save", new MyCommand("file","recover")); + recoverItem = iconMenuItem("back-in-time", "Recover Auto-Save", new MyCommand("file", "recover")); recoverItem.setEnabled(recovery != null); fileMenuBar.addItem(recoverItem); - printItem = menuItemWithShortcut("print", "Print...", Locale.LS(ctrlMetaKey + "P"), new MyCommand("file","print")); + printItem = menuItemWithShortcut("print", "Print...", Locale.LS(ctrlMetaKey + "P"), + new MyCommand("file", "print")); fileMenuBar.addItem(printItem); fileMenuBar.addSeparator(); fileMenuBar.addItem(iconMenuItem("resize-full-alt", "Toggle Full Screen", new MyCommand("view", "fullscreen"))); fileMenuBar.addSeparator(); - aboutItem = iconMenuItem("info-circled", "About...", (Command)null); + aboutItem = iconMenuItem("info-circled", "About...", (Command) null); fileMenuBar.addItem(aboutItem); - aboutItem.setScheduledCommand(new MyCommand("file","about")); + aboutItem.setScheduledCommand(new MyCommand("file", "about")); - int width=(int)RootLayoutPanel.get().getOffsetWidth(); - VERTICALPANELWIDTH = width/5; + int width = (int) RootLayoutPanel.get().getOffsetWidth(); + VERTICALPANELWIDTH = width / 5; if (VERTICALPANELWIDTH > 166) VERTICALPANELWIDTH = 166; if (VERTICALPANELWIDTH < 128) @@ -486,31 +488,39 @@ else if (usRes) menuBar = new MenuBar(); menuBar.addItem(Locale.LS("File"), fileMenuBar); - verticalPanel=new VerticalPanel(); + verticalPanel = new VerticalPanel(); // make buttons side by side if there's room - buttonPanel=(VERTICALPANELWIDTH == 166) ? new HorizontalPanel() : new VerticalPanel(); + buttonPanel = (VERTICALPANELWIDTH == 166) ? new HorizontalPanel() : new VerticalPanel(); m = new MenuBar(true); - m.addItem(undoItem = menuItemWithShortcut("ccw", "Undo", Locale.LS(ctrlMetaKey + "Z"), new MyCommand("edit","undo"))); - m.addItem(redoItem = menuItemWithShortcut("cw", "Redo", Locale.LS(ctrlMetaKey + "Y"), new MyCommand("edit","redo"))); + m.addItem(undoItem = menuItemWithShortcut("ccw", "Undo", Locale.LS(ctrlMetaKey + "Z"), + new MyCommand("edit", "undo"))); + m.addItem(redoItem = menuItemWithShortcut("cw", "Redo", Locale.LS(ctrlMetaKey + "Y"), + new MyCommand("edit", "redo"))); m.addSeparator(); - m.addItem(cutItem = menuItemWithShortcut("scissors", "Cut", Locale.LS(ctrlMetaKey + "X"), new MyCommand("edit","cut"))); - m.addItem(copyItem = menuItemWithShortcut("copy", "Copy", Locale.LS(ctrlMetaKey + "C"), new MyCommand("edit","copy"))); - m.addItem(pasteItem = menuItemWithShortcut("paste", "Paste", Locale.LS(ctrlMetaKey + "V"), new MyCommand("edit","paste"))); + m.addItem(cutItem = menuItemWithShortcut("scissors", "Cut", Locale.LS(ctrlMetaKey + "X"), + new MyCommand("edit", "cut"))); + m.addItem(copyItem = menuItemWithShortcut("copy", "Copy", Locale.LS(ctrlMetaKey + "C"), + new MyCommand("edit", "copy"))); + m.addItem(pasteItem = menuItemWithShortcut("paste", "Paste", Locale.LS(ctrlMetaKey + "V"), + new MyCommand("edit", "paste"))); pasteItem.setEnabled(false); - m.addItem(menuItemWithShortcut("clone", "Duplicate", Locale.LS(ctrlMetaKey + "D"), new MyCommand("edit","duplicate"))); + m.addItem(menuItemWithShortcut("clone", "Duplicate", Locale.LS(ctrlMetaKey + "D"), + new MyCommand("edit", "duplicate"))); m.addSeparator(); - m.addItem(selectAllItem = menuItemWithShortcut("select-all", "Select All", Locale.LS(ctrlMetaKey + "A"), new MyCommand("edit","selectAll"))); + m.addItem(selectAllItem = menuItemWithShortcut("select-all", "Select All", Locale.LS(ctrlMetaKey + "A"), + new MyCommand("edit", "selectAll"))); m.addSeparator(); m.addItem(menuItemWithShortcut("search", "Find Component...", "/", new MyCommand("edit", "search"))); - m.addItem(iconMenuItem("target", weAreInUS(false) ? "Center Circuit" : "Centre Circuit", new MyCommand("edit", "centrecircuit"))); + m.addItem(iconMenuItem("target", weAreInUS(false) ? "Center Circuit" : "Centre Circuit", + new MyCommand("edit", "centrecircuit"))); m.addItem(menuItemWithShortcut("zoom-11", "Zoom 100%", "0", new MyCommand("zoom", "zoom100"))); m.addItem(menuItemWithShortcut("zoom-in", "Zoom In", "+", new MyCommand("zoom", "zoomin"))); m.addItem(menuItemWithShortcut("zoom-out", "Zoom Out", "-", new MyCommand("zoom", "zoomout"))); - menuBar.addItem(Locale.LS("Edit"),m); + menuBar.addItem(Locale.LS("Edit"), m); MenuBar drawMenuBar = new MenuBar(true); drawMenuBar.setAutoOpen(true); @@ -521,91 +531,94 @@ else if (usRes) m.addItem(stackAllItem = iconMenuItem("lines", "Stack All", new MyCommand("scopes", "stackAll"))); m.addItem(unstackAllItem = iconMenuItem("columns", "Unstack All", new MyCommand("scopes", "unstackAll"))); m.addItem(combineAllItem = iconMenuItem("object-group", "Combine All", new MyCommand("scopes", "combineAll"))); - m.addItem(separateAllItem = iconMenuItem("object-ungroup", "Separate All", new MyCommand("scopes", "separateAll"))); + m.addItem(separateAllItem = iconMenuItem("object-ungroup", "Separate All", + new MyCommand("scopes", "separateAll"))); menuBar.addItem(Locale.LS("Scopes"), m); - optionsMenuBar = m = new MenuBar(true ); + optionsMenuBar = m = new MenuBar(true); menuBar.addItem(Locale.LS("Options"), optionsMenuBar); m.addItem(dotsCheckItem = new CheckboxMenuItem(Locale.LS("Show Current"))); dotsCheckItem.setState(true); - m.addItem(voltsCheckItem = new CheckboxMenuItem(Locale.LS("Show Voltage"), - new Command() { public void execute(){ - if (voltsCheckItem.getState()) - powerCheckItem.setState(false); - setPowerBarEnable(); - } + m.addItem(voltsCheckItem = new CheckboxMenuItem(Locale.LS("Show Voltage"), new Command() { + public void execute() { + if (voltsCheckItem.getState()) + powerCheckItem.setState(false); + setPowerBarEnable(); + } })); voltsCheckItem.setState(true); - m.addItem(powerCheckItem = new CheckboxMenuItem(Locale.LS("Show Power"), - new Command() { public void execute(){ - if (powerCheckItem.getState()) - voltsCheckItem.setState(false); - setPowerBarEnable(); - } + m.addItem(powerCheckItem = new CheckboxMenuItem(Locale.LS("Show Power"), new Command() { + public void execute() { + if (powerCheckItem.getState()) + voltsCheckItem.setState(false); + setPowerBarEnable(); + } })); m.addItem(showValuesCheckItem = new CheckboxMenuItem(Locale.LS("Show Values"))); showValuesCheckItem.setState(true); - //m.add(conductanceCheckItem = getCheckItem(LS("Show Conductance"))); - m.addItem(smallGridCheckItem = new CheckboxMenuItem(Locale.LS("Small Grid"), - new Command() { public void execute(){ - setGrid(); - } + // m.add(conductanceCheckItem = getCheckItem(LS("Show Conductance"))); + m.addItem(smallGridCheckItem = new CheckboxMenuItem(Locale.LS("Small Grid"), new Command() { + public void execute() { + setGrid(); + } })); - m.addItem(crossHairCheckItem = new CheckboxMenuItem(Locale.LS("Show Cursor Cross Hairs"), - new Command() { public void execute(){ - setOptionInStorage("crossHair", crossHairCheckItem.getState()); - } + m.addItem(crossHairCheckItem = new CheckboxMenuItem(Locale.LS("Show Cursor Cross Hairs"), new Command() { + public void execute() { + setOptionInStorage("crossHair", crossHairCheckItem.getState()); + } })); crossHairCheckItem.setState(getOptionFromStorage("crossHair", false)); - m.addItem(euroResistorCheckItem = new CheckboxMenuItem(Locale.LS("European Resistors"), - new Command() { public void execute(){ - setOptionInStorage("euroResistors", euroResistorCheckItem.getState()); - } + m.addItem(euroResistorCheckItem = new CheckboxMenuItem(Locale.LS("European Resistors"), new Command() { + public void execute() { + setOptionInStorage("euroResistors", euroResistorCheckItem.getState()); + } })); euroResistorCheckItem.setState(euroSetting); - m.addItem(euroGatesCheckItem = new CheckboxMenuItem(Locale.LS("IEC Gates"), - new Command() { public void execute(){ - setOptionInStorage("euroGates", euroGatesCheckItem.getState()); - int i; - for (i = 0; i != elmList.size(); i++) - getElm(i).setPoints(); - } + m.addItem(euroGatesCheckItem = new CheckboxMenuItem(Locale.LS("IEC Gates"), new Command() { + public void execute() { + setOptionInStorage("euroGates", euroGatesCheckItem.getState()); + int i; + for (i = 0; i != elmList.size(); i++) + getElm(i).setPoints(); + } })); euroGatesCheckItem.setState(euroGates); - m.addItem(printableCheckItem = new CheckboxMenuItem(Locale.LS("White Background"), - new Command() { public void execute(){ - int i; - for (i=0;i(); adjustables = new Vector(); - // setupList = new Vector(); + // setupList = new Vector(); undoStack = new Vector(); redoStack = new Vector(); - scopes = new Scope[20]; scopeColCount = new int[20]; scopeCount = 0; random = new Random(); - // cv.setBackground(Color.black); - // cv.setForeground(Color.lightGray); + // cv.setBackground(Color.black); + // cv.setForeground(Color.lightGray); elmMenuBar = new MenuBar(true); elmMenuBar.setAutoOpen(true); selectScopeMenuBar = new MenuBar(true) { @Override - + // when mousing over scope menu item, select associated scope public void onBrowserEvent(Event event) { int currentItem = -1; @@ -722,33 +733,37 @@ public void onBrowserEvent(Event event) { for (i = 0; i != selectScopeMenuItems.size(); i++) { MenuItem item = selectScopeMenuItems.get(i); if (DOM.isOrHasChild(item.getElement(), DOM.eventGetTarget(event))) { - //MenuItem found here + // MenuItem found here currentItem = i; } } switch (DOM.eventGetType(event)) { case Event.ONMOUSEOVER: - scopeMenuSelected = currentItem; - break; + scopeMenuSelected = currentItem; + break; case Event.ONMOUSEOUT: scopeMenuSelected = -1; - break; + break; } super.onBrowserEvent(event); } }; - - elmMenuBar.addItem(elmEditMenuItem = new MenuItem(Locale.LS("Edit..."),new MyCommand("elm","edit"))); - elmMenuBar.addItem(elmScopeMenuItem = new MenuItem(Locale.LS("View in New Scope"), new MyCommand("elm","viewInScope"))); - elmMenuBar.addItem(elmFloatScopeMenuItem = new MenuItem(Locale.LS("View in New Undocked Scope"), new MyCommand("elm","viewInFloatScope"))); - elmMenuBar.addItem(elmAddScopeMenuItem = new MenuItem(Locale.LS("Add to Existing Scope"), new MyCommand("elm", "addToScope0"))); - elmMenuBar.addItem(elmCutMenuItem = new MenuItem(Locale.LS("Cut"),new MyCommand("elm","cut"))); - elmMenuBar.addItem(elmCopyMenuItem = new MenuItem(Locale.LS("Copy"),new MyCommand("elm","copy"))); - elmMenuBar.addItem(elmDeleteMenuItem = new MenuItem(Locale.LS("Delete"),new MyCommand("elm","delete"))); - elmMenuBar.addItem( new MenuItem(Locale.LS("Duplicate"),new MyCommand("elm","duplicate"))); - elmMenuBar.addItem(elmFlipMenuItem = new MenuItem(Locale.LS("Swap Terminals"),new MyCommand("elm","flip"))); - elmMenuBar.addItem(elmSplitMenuItem = menuItemWithShortcut("", "Split Wire", Locale.LS(ctrlMetaKey + "click"), new MyCommand("elm","split"))); - elmMenuBar.addItem(elmSliderMenuItem = new MenuItem(Locale.LS("Sliders..."),new MyCommand("elm","sliders"))); + + elmMenuBar.addItem(elmEditMenuItem = new MenuItem(Locale.LS("Edit..."), new MyCommand("elm", "edit"))); + elmMenuBar.addItem( + elmScopeMenuItem = new MenuItem(Locale.LS("View in New Scope"), new MyCommand("elm", "viewInScope"))); + elmMenuBar.addItem(elmFloatScopeMenuItem = new MenuItem(Locale.LS("View in New Undocked Scope"), + new MyCommand("elm", "viewInFloatScope"))); + elmMenuBar.addItem(elmAddScopeMenuItem = new MenuItem(Locale.LS("Add to Existing Scope"), + new MyCommand("elm", "addToScope0"))); + elmMenuBar.addItem(elmCutMenuItem = new MenuItem(Locale.LS("Cut"), new MyCommand("elm", "cut"))); + elmMenuBar.addItem(elmCopyMenuItem = new MenuItem(Locale.LS("Copy"), new MyCommand("elm", "copy"))); + elmMenuBar.addItem(elmDeleteMenuItem = new MenuItem(Locale.LS("Delete"), new MyCommand("elm", "delete"))); + elmMenuBar.addItem(new MenuItem(Locale.LS("Duplicate"), new MyCommand("elm", "duplicate"))); + elmMenuBar.addItem(elmFlipMenuItem = new MenuItem(Locale.LS("Swap Terminals"), new MyCommand("elm", "flip"))); + elmMenuBar.addItem(elmSplitMenuItem = menuItemWithShortcut("", "Split Wire", Locale.LS(ctrlMetaKey + "click"), + new MyCommand("elm", "split"))); + elmMenuBar.addItem(elmSliderMenuItem = new MenuItem(Locale.LS("Sliders..."), new MyCommand("elm", "sliders"))); scopePopupMenu = new ScopePopupMenu(); @@ -759,7 +774,7 @@ public void onBrowserEvent(Event event) { readCircuit(startCircuitText); unsavedChanges = false; } else { - if (stopMessage == null && startCircuitLink!=null) { + if (stopMessage == null && startCircuitLink != null) { readCircuit(""); getSetupList(false); ImportFromDropboxDialog.setSim(this); @@ -769,8 +784,7 @@ public void onBrowserEvent(Event event) { if (stopMessage == null && startCircuit != null) { getSetupList(false); readSetupFile(startCircuit, startLabel); - } - else + } else getSetupList(true); } } @@ -788,47 +802,49 @@ public void onBrowserEvent(Event event) { cv.addClickHandler(this); cv.addDoubleClickHandler(this); doTouchHandlers(this, cv.getCanvasElement()); - cv.addDomHandler(this, ContextMenuEvent.getType()); + cv.addDomHandler(this, ContextMenuEvent.getType()); menuBar.addDomHandler(new ClickHandler() { public void onClick(ClickEvent event) { doMainMenuChecks(); } - }, ClickEvent.getType()); + }, ClickEvent.getType()); Event.addNativePreviewHandler(this); cv.addMouseWheelHandler(this); Window.addWindowClosingHandler(new Window.ClosingHandler() { public void onWindowClosing(ClosingEvent event) { - // there is a bug in electron that makes it impossible to close the app if this warning is given + // there is a bug in electron that makes it impossible to close the app if this + // warning is given if (unsavedChanges && !isElectron()) event.setMessage(Locale.LS("Are you sure? There are unsaved changes.")); } }); setupJSInterface(); - + setSimRunning(running); } - void setColors(String positiveColor, String negativeColor, String neutralColor, String selectColor, String currentColor) { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor != null) { - if (positiveColor == null) - positiveColor = stor.getItem("positiveColor"); - if (negativeColor == null) - negativeColor = stor.getItem("negativeColor"); - if (neutralColor == null) - neutralColor = stor.getItem("neutralColor"); - if (selectColor == null) - selectColor = stor.getItem("selectColor"); - if (currentColor == null) - currentColor = stor.getItem("currentColor"); - } - + void setColors(String positiveColor, String negativeColor, String neutralColor, String selectColor, + String currentColor) { + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor != null) { + if (positiveColor == null) + positiveColor = stor.getItem("positiveColor"); + if (negativeColor == null) + negativeColor = stor.getItem("negativeColor"); + if (neutralColor == null) + neutralColor = stor.getItem("neutralColor"); + if (selectColor == null) + selectColor = stor.getItem("selectColor"); + if (currentColor == null) + currentColor = stor.getItem("currentColor"); + } + if (positiveColor != null) CircuitElm.positiveColor = new Color(URL.decodeQueryString(positiveColor)); else if (getOptionFromStorage("alternativeColor", false)) CircuitElm.positiveColor = Color.blue; - + if (negativeColor != null) CircuitElm.negativeColor = new Color(URL.decodeQueryString(negativeColor)); if (neutralColor != null) @@ -838,109 +854,112 @@ else if (getOptionFromStorage("alternativeColor", false)) CircuitElm.selectColor = new Color(URL.decodeQueryString(selectColor)); else CircuitElm.selectColor = Color.cyan; - + if (currentColor != null) CircuitElm.currentColor = new Color(URL.decodeQueryString(currentColor)); else CircuitElm.currentColor = conventionCheckItem.getState() ? Color.yellow : Color.cyan; - + CircuitElm.setColorScale(); } - + MenuItem menuItemWithShortcut(String icon, String text, String shortcut, MyCommand cmd) { - final String edithtml="
" + nbsp + Locale.LS(text) + "
" + shortcut + "
"; + if (icon == "") + nbsp = ""; + String sn = edithtml + icon + "\">" + nbsp + Locale.LS(text) + "
" + shortcut + ""; return new MenuItem(SafeHtmlUtils.fromTrustedString(sn), cmd); } - + MenuItem iconMenuItem(String icon, String text, Command cmd) { - String icoStr = " " + Locale.LS(text); //  - return new MenuItem(SafeHtmlUtils.fromTrustedString(icoStr), cmd); + String icoStr = " " + Locale.LS(text); //   + return new MenuItem(SafeHtmlUtils.fromTrustedString(icoStr), cmd); } - + boolean getOptionFromStorage(String key, boolean val) { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return val; - String s = stor.getItem(key); - if (s == null) - return val; - return s == "true"; + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return val; + String s = stor.getItem(key); + if (s == null) + return val; + return s == "true"; } void setOptionInStorage(String key, boolean val) { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - stor.setItem(key, val ? "true" : "false"); + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + stor.setItem(key, val ? "true" : "false"); } - + // save shortcuts to local storage void saveShortcuts() { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - String str = "1"; - int i; - // format: version;code1=ClassName;code2=ClassName;etc - for (i = 0; i != shortcuts.length; i++) { - String sh = shortcuts[i]; - if (sh == null) - continue; - str += ";" + i + "=" + sh; - } - stor.setItem("shortcuts", str); + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + String str = "1"; + int i; + // format: version;code1=ClassName;code2=ClassName;etc + for (i = 0; i != shortcuts.length; i++) { + String sh = shortcuts[i]; + if (sh == null) + continue; + str += ";" + i + "=" + sh; + } + stor.setItem("shortcuts", str); } - + // load shortcuts from local storage void loadShortcuts() { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - String str = stor.getItem("shortcuts"); - if (str == null) - return; - String keys[] = str.split(";"); - - // clear existing shortcuts - int i; - for (i = 0; i != shortcuts.length; i++) - shortcuts[i] = null; - - // clear shortcuts from menu - for (i = 0; i != mainMenuItems.size(); i++) { - CheckboxMenuItem item = mainMenuItems.get(i); - // stop when we get to drag menu items - if (item.getShortcut().length() > 1) - break; - item.setShortcut(""); - } - - // go through keys (skipping version at start) - for (i = 1; i < keys.length; i++) { - String arr[] = keys[i].split("="); - if (arr.length != 2) - continue; - int c = Integer.parseInt(arr[0]); - String className = arr[1]; - shortcuts[c] = className; - - // find menu item and fix it - int j; - for (j = 0; j != mainMenuItems.size(); j++) { - if (mainMenuItemNames.get(j) == className) { - CheckboxMenuItem item = mainMenuItems.get(j); - item.setShortcut(Character.toString((char)c)); - break; - } - } - } + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + String str = stor.getItem("shortcuts"); + if (str == null) + return; + String keys[] = str.split(";"); + + // clear existing shortcuts + int i; + for (i = 0; i != shortcuts.length; i++) + shortcuts[i] = null; + + // clear shortcuts from menu + for (i = 0; i != mainMenuItems.size(); i++) { + CheckboxMenuItem item = mainMenuItems.get(i); + // stop when we get to drag menu items + if (item.getShortcut().length() > 1) + break; + item.setShortcut(""); + } + + // go through keys (skipping version at start) + for (i = 1; i < keys.length; i++) { + String arr[] = keys[i].split("="); + if (arr.length != 2) + continue; + int c = Integer.parseInt(arr[0]); + String className = arr[1]; + shortcuts[c] = className; + + // find menu item and fix it + int j; + for (j = 0; j != mainMenuItems.size(); j++) { + if (mainMenuItemNames.get(j) == className) { + CheckboxMenuItem item = mainMenuItems.get(j); + item.setShortcut(Character.toString((char) c)); + break; + } + } + } } - + // install touch handlers - // don't feel like rewriting this in java. Anyway, java doesn't let us create mouse + // don't feel like rewriting this in java. Anyway, java doesn't let us create + // mouse // events and dispatch them. native static void doTouchHandlers(CirSim sim, CanvasElement cv) /*-{ // Set up touch events for mobile, etc @@ -1007,193 +1026,222 @@ function getTouchPos(canvasDom, touchEvent) { } }-*/; - + boolean shown = false; - - // this is called twice, once for the Draw menu, once for the right mouse popup menu + + // this is called twice, once for the Draw menu, once for the right mouse popup + // menu public void composeMainMenu(MenuBar mainMenuBar, int num) { - mainMenuBar.addItem(getClassCheckItem(Locale.LS("Add Wire"), "WireElm")); - mainMenuBar.addItem(getClassCheckItem(Locale.LS("Add Resistor"), "ResistorElm")); - - MenuBar passMenuBar = new MenuBar(true); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Capacitor"), "CapacitorElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Capacitor (polarized)"), "PolarCapacitorElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Inductor"), "InductorElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Switch"), "SwitchElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Push Switch"), "PushSwitchElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add SPDT Switch"), "Switch2Elm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Make-Before-Break Switch"), "MBBSwitchElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Potentiometer"), "PotElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transformer"), "TransformerElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Tapped Transformer"), "TappedTransformerElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transmission Line"), "TransLineElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Relay"), "RelayElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Memristor"), "MemristorElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Spark Gap"), "SparkGapElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Fuse"), "FuseElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Custom Transformer"), "CustomTransformerElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Crystal"), "CrystalElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Photoresistor"), "LDRElm")); - passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Thermistor"), "ThermistorNTCElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Passive Components")), passMenuBar); - - MenuBar inputMenuBar = new MenuBar(true); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ground"), "GroundElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltage Source (2-terminal)"), "DCVoltageElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add A/C Voltage Source (2-terminal)"), "ACVoltageElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltage Source (1-terminal)"), "RailElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add A/C Voltage Source (1-terminal)"), "ACRailElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Square Wave Source (1-terminal)"), "SquareRailElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Clock"), "ClockElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add A/C Sweep"), "SweepElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Variable Voltage"), "VarRailElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Antenna"), "AntennaElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add AM Source"), "AMElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add FM Source"), "FMElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Current Source"), "CurrentElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Noise Generator"), "NoiseElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Audio Input"), "AudioInputElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Data Input"), "DataInputElm")); - inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add External Voltage (JavaScript)"), "ExtVoltageElm")); - - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Inputs and Sources")), inputMenuBar); - - MenuBar outputMenuBar = new MenuBar(true); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Analog Output"), "OutputElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add LED"), "LEDElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Lamp"), "LampElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Text"), "TextElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Box"), "BoxElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Line"), "LineElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltmeter/Scope Probe"), "ProbeElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ohmmeter"), "OhmMeterElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Labeled Node"), "LabeledNodeElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Test Point"), "TestPointElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ammeter"), "AmmeterElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Decimal Display"), "DecimalDisplayElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Data Export"), "DataRecorderElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Audio Output"), "AudioOutputElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add LED Array"), "LEDArrayElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Stop Trigger"), "StopTriggerElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add DC Motor"), "DCMotorElm")); - outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Wattmeter"), "WattmeterElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Outputs and Labels")), outputMenuBar); - - MenuBar activeMenuBar = new MenuBar(true); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Diode"), "DiodeElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Zener Diode"), "ZenerElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transistor (bipolar, NPN)"), "NTransistorElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transistor (bipolar, PNP)"), "PTransistorElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add MOSFET (N-Channel)"), "NMosfetElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add MOSFET (P-Channel)"), "PMosfetElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add JFET (N-Channel)"), "NJfetElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add JFET (P-Channel)"), "PJfetElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add SCR"), "SCRElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add DIAC"), "DiacElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add TRIAC"), "TriacElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Darlington Pair (NPN)"), "NDarlingtonElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Darlington Pair (PNP)"), "PDarlingtonElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Varactor/Varicap"), "VaractorElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Tunnel Diode"), "TunnelDiodeElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Triode"), "TriodeElm")); - activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Unijunction Transistor"), "UnijunctionElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Active Components")), activeMenuBar); - - MenuBar activeBlocMenuBar = new MenuBar(true); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Op Amp (ideal, - on top)"), "OpAmpElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Op Amp (ideal, + on top)"), "OpAmpSwapElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Op Amp (real)"), "OpAmpRealElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Analog Switch (SPST)"), "AnalogSwitchElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Analog Switch (SPDT)"), "AnalogSwitch2Elm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Tristate Buffer"), "TriStateElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Schmitt Trigger"), "SchmittElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Schmitt Trigger (Inverting)"), "InvertingSchmittElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Delay Buffer"), "DelayBufferElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add CCII+"), "CC2Elm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add CCII-"), "CC2NegElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Comparator (Hi-Z/GND output)"), "ComparatorElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add OTA (LM13700 style)"), "OTAElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltage-Controlled Voltage Source (VCVS)"), "VCVSElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltage-Controlled Current Source (VCCS)"), "VCCSElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Current-Controlled Voltage Source (CCVS)"), "CCVSElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Current-Controlled Current Source (CCCS)"), "CCCSElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Optocoupler"), "OptocouplerElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Time Delay Relay"), "TimeDelayRelayElm")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add LM317"), "CustomCompositeElm:~LM317-v2")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add TL431"), "CustomCompositeElm:~TL431")); - activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Subcircuit Instance"), "CustomCompositeElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Active Building Blocks")), activeBlocMenuBar); - - MenuBar gateMenuBar = new MenuBar(true); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add Logic Input"), "LogicInputElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add Logic Output"), "LogicOutputElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add Inverter"), "InverterElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add NAND Gate"), "NandGateElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add NOR Gate"), "NorGateElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add AND Gate"), "AndGateElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add OR Gate"), "OrGateElm")); - gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add XOR Gate"), "XorGateElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Logic Gates, Input and Output")), gateMenuBar); - - MenuBar chipMenuBar = new MenuBar(true); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add D Flip-Flop"), "DFlipFlopElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add JK Flip-Flop"), "JKFlipFlopElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add T Flip-Flop"), "TFlipFlopElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add 7 Segment LED"), "SevenSegElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add 7 Segment Decoder"), "SevenSegDecoderElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Multiplexer"), "MultiplexerElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Demultiplexer"), "DeMultiplexerElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add SIPO shift register"), "SipoShiftElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add PISO shift register"), "PisoShiftElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Counter"), "CounterElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Counter w/ Load"), "Counter2Elm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ring Counter"), "DecadeElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Latch"), "LatchElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Sequence generator"), "SeqGenElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Adder"), "FullAdderElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Half Adder"), "HalfAdderElm")); - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Custom Logic"), "UserDefinedLogicElm")); // don't change this, it will break people's saved shortcuts - chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Static RAM"), "SRAMElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Digital Chips")), chipMenuBar); - - MenuBar achipMenuBar = new MenuBar(true); - achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add 555 Timer"), "TimerElm")); - achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Phase Comparator"), "PhaseCompElm")); - achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add DAC"), "DACElm")); - achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add ADC"), "ADCElm")); - achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add VCO"), "VCOElm")); - achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Monostable"), "MonostableElm")); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Analog and Hybrid Chips")), achipMenuBar); - - if (subcircuitMenuBar == null) - subcircuitMenuBar = new MenuBar[2]; - subcircuitMenuBar[num] = new MenuBar(true); - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Subcircuits")), subcircuitMenuBar[num]); - - MenuBar otherMenuBar = new MenuBar(true); - CheckboxMenuItem mi; - otherMenuBar.addItem(mi=getClassCheckItem(Locale.LS("Drag All"), "DragAll")); - mi.setShortcut(Locale.LS("(Alt-drag)")); - otherMenuBar.addItem(mi=getClassCheckItem(Locale.LS("Drag Row"), "DragRow")); - mi.setShortcut(Locale.LS("(A-S-drag)")); - otherMenuBar.addItem(mi=getClassCheckItem(Locale.LS("Drag Column"), "DragColumn")); - mi.setShortcut(isMac ? Locale.LS("(A-Cmd-drag)") : Locale.LS("(A-M-drag)")); - otherMenuBar.addItem(getClassCheckItem(Locale.LS("Drag Selected"), "DragSelected")); - otherMenuBar.addItem(mi=getClassCheckItem(Locale.LS("Drag Post"), "DragPost")); - mi.setShortcut("(" + ctrlMetaKey + "drag)"); - - mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml+Locale.LS(" Drag")), otherMenuBar); - - mainMenuBar.addItem(mi=getClassCheckItem(Locale.LS("Select/Drag Sel"), "Select")); - mi.setShortcut(Locale.LS("(space or Shift-drag)")); + mainMenuBar.addItem(getClassCheckItem(Locale.LS("Add Wire"), "WireElm")); + mainMenuBar.addItem(getClassCheckItem(Locale.LS("Add Resistor"), "ResistorElm")); + + MenuBar passMenuBar = new MenuBar(true); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Capacitor"), "CapacitorElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Capacitor (polarized)"), "PolarCapacitorElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Inductor"), "InductorElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Switch"), "SwitchElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Push Switch"), "PushSwitchElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add SPDT Switch"), "Switch2Elm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Make-Before-Break Switch"), "MBBSwitchElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Potentiometer"), "PotElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transformer"), "TransformerElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Tapped Transformer"), "TappedTransformerElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transmission Line"), "TransLineElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Relay"), "RelayElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Memristor"), "MemristorElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Spark Gap"), "SparkGapElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Fuse"), "FuseElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Custom Transformer"), "CustomTransformerElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Crystal"), "CrystalElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Photoresistor"), "LDRElm")); + passMenuBar.addItem(getClassCheckItem(Locale.LS("Add Thermistor"), "ThermistorNTCElm")); + mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Passive Components")), passMenuBar); + + MenuBar inputMenuBar = new MenuBar(true); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ground"), "GroundElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltage Source (2-terminal)"), "DCVoltageElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add A/C Voltage Source (2-terminal)"), "ACVoltageElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltage Source (1-terminal)"), "RailElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add A/C Voltage Source (1-terminal)"), "ACRailElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Square Wave Source (1-terminal)"), "SquareRailElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Clock"), "ClockElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add A/C Sweep"), "SweepElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Variable Voltage"), "VarRailElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Antenna"), "AntennaElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add AM Source"), "AMElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add FM Source"), "FMElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Current Source"), "CurrentElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Noise Generator"), "NoiseElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Audio Input"), "AudioInputElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Data Input"), "DataInputElm")); + inputMenuBar.addItem(getClassCheckItem(Locale.LS("Add External Voltage (JavaScript)"), "ExtVoltageElm")); + + mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Inputs and Sources")), inputMenuBar); + + MenuBar outputMenuBar = new MenuBar(true); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Analog Output"), "OutputElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add LED"), "LEDElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Lamp"), "LampElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Text"), "TextElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Box"), "BoxElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Line"), "LineElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Voltmeter/Scope Probe"), "ProbeElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ohmmeter"), "OhmMeterElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Labeled Node"), "LabeledNodeElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Test Point"), "TestPointElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ammeter"), "AmmeterElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Decimal Display"), "DecimalDisplayElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Data Export"), "DataRecorderElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Audio Output"), "AudioOutputElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add LED Array"), "LEDArrayElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Stop Trigger"), "StopTriggerElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add DC Motor"), "DCMotorElm")); + outputMenuBar.addItem(getClassCheckItem(Locale.LS("Add Wattmeter"), "WattmeterElm")); + mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Outputs and Labels")), outputMenuBar); + + MenuBar activeMenuBar = new MenuBar(true); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Diode"), "DiodeElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Zener Diode"), "ZenerElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transistor (bipolar, NPN)"), "NTransistorElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Transistor (bipolar, PNP)"), "PTransistorElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add MOSFET (N-Channel)"), "NMosfetElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add MOSFET (P-Channel)"), "PMosfetElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add JFET (N-Channel)"), "NJfetElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add JFET (P-Channel)"), "PJfetElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add SCR"), "SCRElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add DIAC"), "DiacElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add TRIAC"), "TriacElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Darlington Pair (NPN)"), "NDarlingtonElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Darlington Pair (PNP)"), "PDarlingtonElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Varactor/Varicap"), "VaractorElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Tunnel Diode"), "TunnelDiodeElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Triode"), "TriodeElm")); + activeMenuBar.addItem(getClassCheckItem(Locale.LS("Add Unijunction Transistor"), "UnijunctionElm")); + mainMenuBar.addItem(SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Active Components")), activeMenuBar); + + MenuBar activeBlocMenuBar = new MenuBar(true); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Op Amp (ideal, - on top)"), "OpAmpElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Op Amp (ideal, + on top)"), "OpAmpSwapElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Op Amp (real)"), "OpAmpRealElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Analog Switch (SPST)"), "AnalogSwitchElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Analog Switch (SPDT)"), "AnalogSwitch2Elm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Tristate Buffer"), "TriStateElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Schmitt Trigger"), "SchmittElm")); + activeBlocMenuBar + .addItem(getClassCheckItem(Locale.LS("Add Schmitt Trigger (Inverting)"), "InvertingSchmittElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Delay Buffer"), "DelayBufferElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add CCII+"), "CC2Elm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add CCII-"), "CC2NegElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Comparator (Hi-Z/GND output)"), "ComparatorElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add OTA (LM13700 style)"), "OTAElm")); + activeBlocMenuBar + .addItem(getClassCheckItem(Locale.LS("Add Voltage-Controlled Voltage Source (VCVS)"), "VCVSElm")); + activeBlocMenuBar + .addItem(getClassCheckItem(Locale.LS("Add Voltage-Controlled Current Source (VCCS)"), "VCCSElm")); + activeBlocMenuBar + .addItem(getClassCheckItem(Locale.LS("Add Current-Controlled Voltage Source (CCVS)"), "CCVSElm")); + activeBlocMenuBar + .addItem(getClassCheckItem(Locale.LS("Add Current-Controlled Current Source (CCCS)"), "CCCSElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Optocoupler"), "OptocouplerElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Time Delay Relay"), "TimeDelayRelayElm")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add LM317"), "CustomCompositeElm:~LM317-v2")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add TL431"), "CustomCompositeElm:~TL431")); + activeBlocMenuBar.addItem(getClassCheckItem(Locale.LS("Add Subcircuit Instance"), "CustomCompositeElm")); + mainMenuBar.addItem( + SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Active Building Blocks")), + activeBlocMenuBar); + + MenuBar gateMenuBar = new MenuBar(true); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add Logic Input"), "LogicInputElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add Logic Output"), "LogicOutputElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add Inverter"), "InverterElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add NAND Gate"), "NandGateElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add NOR Gate"), "NorGateElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add AND Gate"), "AndGateElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add OR Gate"), "OrGateElm")); + gateMenuBar.addItem(getClassCheckItem(Locale.LS("Add XOR Gate"), "XorGateElm")); + mainMenuBar.addItem( + SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Logic Gates, Input and Output")), + gateMenuBar); + + MenuBar chipMenuBar = new MenuBar(true); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add D Flip-Flop"), "DFlipFlopElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add JK Flip-Flop"), "JKFlipFlopElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add T Flip-Flop"), "TFlipFlopElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add 7 Segment LED"), "SevenSegElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add 7 Segment Decoder"), "SevenSegDecoderElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Multiplexer"), "MultiplexerElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Demultiplexer"), "DeMultiplexerElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add SIPO shift register"), "SipoShiftElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add PISO shift register"), "PisoShiftElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Counter"), "CounterElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Counter w/ Load"), "Counter2Elm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Ring Counter"), "DecadeElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Latch"), "LatchElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Sequence generator"), "SeqGenElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Adder"), "FullAdderElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Half Adder"), "HalfAdderElm")); + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Custom Logic"), "UserDefinedLogicElm")); // don't change + // this, it will + // break people's + // saved shortcuts + chipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Static RAM"), "SRAMElm")); + mainMenuBar.addItem( + SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml + Locale.LS(" Digital Chips")), + chipMenuBar); + + MenuBar achipMenuBar = new MenuBar(true); + achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add 555 Timer"), "TimerElm")); + achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Phase Comparator"), "PhaseCompElm")); + achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add DAC"), "DACElm")); + achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add ADC"), "ADCElm")); + achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add VCO"), "VCOElm")); + achipMenuBar.addItem(getClassCheckItem(Locale.LS("Add Monostable"), "MonostableElm")); + mainMenuBar.addItem( + SafeHtmlUtils.fromTrustedString( + CheckboxMenuItem.checkBoxHtml + Locale.LS(" Analog and Hybrid Chips")), + achipMenuBar); + + if (subcircuitMenuBar == null) + subcircuitMenuBar = new MenuBar[2]; + subcircuitMenuBar[num] = new MenuBar(true); + mainMenuBar.addItem( + SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml + Locale.LS(" Subcircuits")), + subcircuitMenuBar[num]); + + MenuBar otherMenuBar = new MenuBar(true); + CheckboxMenuItem mi; + otherMenuBar.addItem(mi = getClassCheckItem(Locale.LS("Drag All"), "DragAll")); + mi.setShortcut(Locale.LS("(Alt-drag)")); + otherMenuBar.addItem(mi = getClassCheckItem(Locale.LS("Drag Row"), "DragRow")); + mi.setShortcut(Locale.LS("(A-S-drag)")); + otherMenuBar.addItem(mi = getClassCheckItem(Locale.LS("Drag Column"), "DragColumn")); + mi.setShortcut(isMac ? Locale.LS("(A-Cmd-drag)") : Locale.LS("(A-M-drag)")); + otherMenuBar.addItem(getClassCheckItem(Locale.LS("Drag Selected"), "DragSelected")); + otherMenuBar.addItem(mi = getClassCheckItem(Locale.LS("Drag Post"), "DragPost")); + mi.setShortcut("(" + ctrlMetaKey + "drag)"); + + mainMenuBar.addItem( + SafeHtmlUtils.fromTrustedString(CheckboxMenuItem.checkBoxHtml + Locale.LS(" Drag")), + otherMenuBar); + + mainMenuBar.addItem(mi = getClassCheckItem(Locale.LS("Select/Drag Sel"), "Select")); + mi.setShortcut(Locale.LS("(space or Shift-drag)")); } - + void composeSubcircuitMenu() { if (subcircuitMenuBar == null) return; int mi; - - // there are two menus to update: the one in the Draw menu, and the one in the right mouse menu + + // there are two menus to update: the one in the Draw menu, and the one in the + // right mouse menu for (mi = 0; mi != 2; mi++) { MenuBar menu = subcircuitMenuBar[mi]; menu.clearItems(); @@ -1206,143 +1254,141 @@ void composeSubcircuitMenu() { } lastSubcircuitMenuUpdate = CustomCompositeModel.sequenceNumber; } - + public void composeSelectScopeMenu(MenuBar sb) { sb.clearItems(); selectScopeMenuItems = new Vector(); - for( int i = 0; i < scopeCount; i++) { + for (int i = 0; i < scopeCount; i++) { String s, l; - s = Locale.LS("Scope")+" "+ Integer.toString(i+1); - l=scopes[i].getScopeLabelOrText(); - if (l!="") - s+=" ("+SafeHtmlUtils.htmlEscape(l)+")"; - selectScopeMenuItems.add(new MenuItem(s ,new MyCommand("elm", "addToScope"+Integer.toString(i)))); + s = Locale.LS("Scope") + " " + Integer.toString(i + 1); + l = scopes[i].getScopeLabelOrText(); + if (l != "") + s += " (" + SafeHtmlUtils.htmlEscape(l) + ")"; + selectScopeMenuItems.add(new MenuItem(s, new MyCommand("elm", "addToScope" + Integer.toString(i)))); } int c = countScopeElms(); for (int j = 0; j < c; j++) { - String s,l; - s = Locale.LS("Undocked Scope")+" "+ Integer.toString(j+1); + String s, l; + s = Locale.LS("Undocked Scope") + " " + Integer.toString(j + 1); l = getNthScopeElm(j).elmScope.getScopeLabelOrText(); - if (l!="") - s += " ("+SafeHtmlUtils.htmlEscape(l)+")"; - selectScopeMenuItems.add(new MenuItem(s, new MyCommand("elm", "addToScope"+Integer.toString(scopeCount+j)))); + if (l != "") + s += " (" + SafeHtmlUtils.htmlEscape(l) + ")"; + selectScopeMenuItems + .add(new MenuItem(s, new MyCommand("elm", "addToScope" + Integer.toString(scopeCount + j)))); } for (MenuItem mi : selectScopeMenuItems) sb.addItem(mi); } - + public void setiFrameHeight() { - if (iFrame==null) - return; - int i; - int cumheight=0; - for (i=0; i < verticalPanel.getWidgetIndex(iFrame); i++) { - if (verticalPanel.getWidget(i) !=loadFileInput) { - cumheight=cumheight+verticalPanel.getWidget(i).getOffsetHeight(); - if (verticalPanel.getWidget(i).getStyleName().contains("topSpace")) - cumheight+=12; - } - } - int ih=RootLayoutPanel.get().getOffsetHeight()-MENUBARHEIGHT-cumheight; - if (ih<0) - ih=0; - iFrame.setHeight(ih+"px"); + if (iFrame == null) + return; + int i; + int cumheight = 0; + for (i = 0; i < verticalPanel.getWidgetIndex(iFrame); i++) { + if (verticalPanel.getWidget(i) != loadFileInput) { + cumheight = cumheight + verticalPanel.getWidget(i).getOffsetHeight(); + if (verticalPanel.getWidget(i).getStyleName().contains("topSpace")) + cumheight += 12; + } + } + int ih = RootLayoutPanel.get().getOffsetHeight() - MENUBARHEIGHT - cumheight; + if (ih < 0) + ih = 0; + iFrame.setHeight(ih + "px"); } - - - - - CheckboxMenuItem getClassCheckItem(String s, String t) { - // try { - // Class c = Class.forName(t); - String shortcut=""; - CircuitElm elm = null; - try { - elm = constructElement(t, 0, 0); - } catch (Exception e) {} - CheckboxMenuItem mi; - // register(c, elm); - if ( elm!=null ) { - if (elm.needsShortcut() ) { - shortcut += (char)elm.getShortcut(); - if (shortcuts[elm.getShortcut()] != null && !shortcuts[elm.getShortcut()].equals(t)) - console("already have shortcut for " + (char)elm.getShortcut() + " " + elm); - shortcuts[elm.getShortcut()]=t; - } - elm.delete(); - } -// else -// GWT.log("Coudn't create class: "+t); - // } catch (Exception ee) { - // ee.printStackTrace(); - // } - if (shortcut=="") - mi= new CheckboxMenuItem(s); - else - mi = new CheckboxMenuItem(s, shortcut); - mi.setScheduledCommand(new MyCommand("main", t) ); - mainMenuItems.add(mi); - mainMenuItemNames.add(t); - return mi; + // try { + // Class c = Class.forName(t); + String shortcut = ""; + CircuitElm elm = null; + try { + elm = constructElement(t, 0, 0); + } catch (Exception e) { + } + CheckboxMenuItem mi; + // register(c, elm); + if (elm != null) { + if (elm.needsShortcut()) { + shortcut += (char) elm.getShortcut(); + if (shortcuts[elm.getShortcut()] != null && !shortcuts[elm.getShortcut()].equals(t)) + console("already have shortcut for " + (char) elm.getShortcut() + " " + elm); + shortcuts[elm.getShortcut()] = t; + } + elm.delete(); + } + // else + // GWT.log("Coudn't create class: "+t); + // } catch (Exception ee) { + // ee.printStackTrace(); + // } + if (shortcut == "") + mi = new CheckboxMenuItem(s); + else + mi = new CheckboxMenuItem(s, shortcut); + mi.setScheduledCommand(new MyCommand("main", t)); + mainMenuItems.add(mi); + mainMenuItemNames.add(t); + return mi; } - - - void centreCircuit() { - if (elmList == null) // avoid exception if called during initialization + if (elmList == null) // avoid exception if called during initialization return; - + Rectangle bounds = getCircuitBounds(); - setCircuitArea(); - - double scale = 1; - int cheight = circuitArea.height; - - // if there's no scope, and the window isn't very wide, then don't use all of the circuit area when - // centering, because the info in the corner might not get in the way. We still want circuitArea to be the full - // height though, to allow the user to put stuff there manually. - if (scopeCount == 0 && circuitArea.width < 800) { - int h = (int) ((double)cheight * scopeHeightFraction); - cheight -= h; - } - - if (bounds != null) - // add some space on edges because bounds calculation is not perfect - scale = Math.min(circuitArea.width /(double)(bounds.width+140), - cheight/(double)(bounds.height+100)); - scale = Math.min(scale, 1.5); // Limit scale so we don't create enormous circuits in big windows - - // calculate transform so circuit fills most of screen - transform[0] = transform[3] = scale; - transform[1] = transform[2] = transform[4] = transform[5] = 0; - if (bounds != null) { - transform[4] = (circuitArea.width -bounds.width *scale)/2 - bounds.x*scale; - transform[5] = (cheight-bounds.height*scale)/2 - bounds.y*scale; - } + setCircuitArea(); + + double scale = 1; + int cheight = circuitArea.height; + + // if there's no scope, and the window isn't very wide, then don't use all of + // the circuit area when + // centering, because the info in the corner might not get in the way. We still + // want circuitArea to be the full + // height though, to allow the user to put stuff there manually. + if (scopeCount == 0 && circuitArea.width < 800) { + int h = (int) ((double) cheight * scopeHeightFraction); + cheight -= h; + } + + if (bounds != null) + // add some space on edges because bounds calculation is not perfect + scale = Math.min(circuitArea.width / (double) (bounds.width + 140), + cheight / (double) (bounds.height + 100)); + scale = Math.min(scale, 1.5); // Limit scale so we don't create enormous circuits in big windows + + // calculate transform so circuit fills most of screen + transform[0] = transform[3] = scale; + transform[1] = transform[2] = transform[4] = transform[5] = 0; + if (bounds != null) { + transform[4] = (circuitArea.width - bounds.width * scale) / 2 - bounds.x * scale; + transform[5] = (cheight - bounds.height * scale) / 2 - bounds.y * scale; + } } - // get circuit bounds. remember this doesn't use setBbox(). That is calculated when we draw - // the circuit, but this needs to be ready before we first draw it, so we use this crude method + // get circuit bounds. remember this doesn't use setBbox(). That is calculated + // when we draw + // the circuit, but this needs to be ready before we first draw it, so we use + // this crude method Rectangle getCircuitBounds() { - int i; - int minx = 30000, maxx = -30000, miny = 30000, maxy = -30000; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - // centered text causes problems when trying to center the circuit, - // so we special-case it here - if (!ce.isCenteredText()) { - minx = min(ce.x, min(ce.x2, minx)); - maxx = max(ce.x, max(ce.x2, maxx)); - } - miny = min(ce.y, min(ce.y2, miny)); - maxy = max(ce.y, max(ce.y2, maxy)); - } - if (minx > maxx) - return null; - return new Rectangle(minx, miny, maxx-minx, maxy-miny); + int i; + int minx = 30000, maxx = -30000, miny = 30000, maxy = -30000; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + // centered text causes problems when trying to center the circuit, + // so we special-case it here + if (!ce.isCenteredText()) { + minx = min(ce.x, min(ce.x2, minx)); + maxx = max(ce.x, max(ce.x2, maxx)); + } + miny = min(ce.y, min(ce.y2, miny)); + maxy = max(ce.y, max(ce.y2, maxy)); + } + if (minx > maxx) + return null; + return new Rectangle(minx, miny, maxx - minx, maxy - miny); } long lastTime = 0, lastFrameTime, lastIterTime, secTime = 0; @@ -1351,286 +1397,285 @@ Rectangle getCircuitBounds() { int framerate = 0, steprate = 0; static CirSim theSim; - public void setSimRunning(boolean s) { - if (s) { - if (stopMessage != null) - return; - simRunning = true; - runStopButton.setHTML(Locale.LSHTML("RUN / Stop")); - runStopButton.setStylePrimaryName("topButton"); - timer.scheduleRepeating(FASTTIMER); - } else { - simRunning = false; - runStopButton.setHTML(Locale.LSHTML("Run / STOP")); - runStopButton.setStylePrimaryName("topButton-red"); - timer.cancel(); - repaint(); - } + if (s) { + if (stopMessage != null) + return; + simRunning = true; + runStopButton.setHTML(Locale.LSHTML("RUN / Stop")); + runStopButton.setStylePrimaryName("topButton"); + timer.scheduleRepeating(FASTTIMER); + } else { + simRunning = false; + runStopButton.setHTML(Locale.LSHTML("Run / STOP")); + runStopButton.setStylePrimaryName("topButton-red"); + timer.cancel(); + repaint(); + } } - + public boolean simIsRunning() { - return simRunning; + return simRunning; } - + boolean needsRepaint; - + void repaint() { if (!needsRepaint) { needsRepaint = true; Scheduler.get().scheduleFixedDelay(new Scheduler.RepeatingCommand() { public boolean execute() { - updateCircuit(); - needsRepaint = false; - return false; - } + updateCircuit(); + needsRepaint = false; + return false; + } }, FASTTIMER); } } - + // ***************************************************************** - // UPDATE CIRCUIT - + // UPDATE CIRCUIT + public void updateCircuit() { - PerfMonitor perfmon = new PerfMonitor(); - perfmon.startContext("updateCircuit()"); - - checkCanvasSize(); - - // Analyze circuit - boolean didAnalyze = analyzeFlag; - if (analyzeFlag || dcAnalysisFlag) { - perfmon.startContext("analyzeCircuit()"); - analyzeCircuit(); - analyzeFlag = false; - perfmon.stopContext(); - } - - // Stamp circuit - if (needsStamp && simRunning) { - perfmon.startContext("stampCircuit()"); - try { - stampCircuit(); - } catch (Exception e) { - stop("Exception in stampCircuit()", null); - } - perfmon.stopContext(); - } - - if (stopElm != null && stopElm != mouseElm) - stopElm.setMouseElm(true); - - setupScopes(); - - Graphics g = new Graphics(cvcontext); - - if (printableCheckItem.getState()) { - CircuitElm.whiteColor = Color.black; - CircuitElm.lightGrayColor = Color.black; - g.setColor(Color.white); - cv.getElement().getStyle().setBackgroundColor("#fff"); - } else { - CircuitElm.whiteColor = Color.white; - CircuitElm.lightGrayColor = Color.lightGray; - g.setColor(Color.black); - cv.getElement().getStyle().setBackgroundColor("#000"); - } - - // Clear the frame - g.fillRect(0, 0, canvasWidth, canvasHeight); - - // Run circuit - if (simRunning) { - if (needsStamp) - console("needsStamp while simRunning?"); - - perfmon.startContext("runCircuit()"); - try { - runCircuit(didAnalyze); - } catch (Exception e) { - debugger(); - console("exception in runCircuit " + e); - e.printStackTrace(); - } - perfmon.stopContext(); - } - - long sysTime = System.currentTimeMillis(); - if (simRunning) { - if (lastTime != 0) { - int inc = (int) (sysTime - lastTime); - double c = currentBar.getValue(); - c = java.lang.Math.exp(c / 3.5 - 14.2); - CircuitElm.currentMult = 1.7 * inc * c; - if (!conventionCheckItem.getState()) - CircuitElm.currentMult = -CircuitElm.currentMult; - } - lastTime = sysTime; - } else { - lastTime = 0; - } - - if (sysTime - secTime >= 1000) { - framerate = frames; - steprate = steps; - frames = 0; - steps = 0; - secTime = sysTime; - } - - CircuitElm.powerMult = Math.exp(powerBar.getValue() / 4.762 - 7); - - perfmon.startContext("graphics"); - - g.setFont(CircuitElm.unitsFont); - - g.context.setLineCap(LineCap.ROUND); - - if (noEditCheckItem.getState()) - g.drawLock(20, 30); - - g.setColor(Color.white); - - // Set the graphics transform to deal with zoom and offset - double scale = devicePixelRatio(); - cvcontext.setTransform(transform[0] * scale, 0, 0, transform[3] * scale, transform[4] * scale, transform[5] * scale); - - // Draw each element - perfmon.startContext("elm.draw()"); - for (int i = 0; i != elmList.size(); i++) { - if (powerCheckItem.getState()) - g.setColor(Color.gray); - - getElm(i).draw(g); - } - perfmon.stopContext(); - - // Draw posts normally - if (mouseMode != CirSim.MODE_DRAG_ROW && mouseMode != CirSim.MODE_DRAG_COLUMN) { - for (int i = 0; i != postDrawList.size(); i++) - CircuitElm.drawPost(g, postDrawList.get(i)); - } - - // for some mouse modes, what matters is not the posts but the endpoints (which - // are only the same for 2-terminal elements). We draw those now if needed - if (tempMouseMode == MODE_DRAG_ROW || - tempMouseMode == MODE_DRAG_COLUMN || - tempMouseMode == MODE_DRAG_POST || - tempMouseMode == MODE_DRAG_SELECTED) { - for (int i = 0; i != elmList.size(); i++) { - - CircuitElm ce = getElm(i); - // ce.drawPost(g, ce.x , ce.y ); - // ce.drawPost(g, ce.x2, ce.y2); - if (ce != mouseElm || tempMouseMode != MODE_DRAG_POST) { - g.setColor(Color.gray); - g.fillOval(ce.x - 3, ce.y - 3, 7, 7); - g.fillOval(ce.x2 - 3, ce.y2 - 3, 7, 7); - } else { - ce.drawHandles(g, CircuitElm.selectColor); - } - } - } - - // draw handles for elm we're creating - if (tempMouseMode == MODE_SELECT && mouseElm != null) { - mouseElm.drawHandles(g, CircuitElm.selectColor); - } - - // draw handles for elm we're dragging - if (dragElm != null && (dragElm.x != dragElm.x2 || dragElm.y != dragElm.y2)) { - dragElm.draw(g); - dragElm.drawHandles(g, CircuitElm.selectColor); - } - - // draw bad connections. do this last so they will not be overdrawn. - for (int i = 0; i != badConnectionList.size(); i++) { - Point cn = badConnectionList.get(i); - g.setColor(Color.red); - g.fillOval(cn.x - 3, cn.y - 3, 7, 7); - } - - // draw the selection rect - if (selectedArea != null) { - g.setColor(CircuitElm.selectColor); - g.drawRect(selectedArea.x, selectedArea.y, selectedArea.width, selectedArea.height); - } - - // draw the crosshair cursor - if (crossHairCheckItem.getState() && mouseCursorX >= 0 - && mouseCursorX <= circuitArea.width && mouseCursorY <= circuitArea.height) { - g.setColor(Color.gray); - int x = snapGrid(inverseTransformX(mouseCursorX)); - int y = snapGrid(inverseTransformY(mouseCursorY)); - g.drawLine(x, inverseTransformY(0), x, inverseTransformY(circuitArea.height)); - g.drawLine(inverseTransformX(0), y, inverseTransformX(circuitArea.width), y); - } - - // reset the graphics scale and translation - cvcontext.setTransform(scale, 0, 0, scale, 0, 0); - - // draw the bottom area i.e. the scope and info section - perfmon.startContext("drawBottomArea()"); - drawBottomArea(g); - perfmon.stopContext(); - - g.setColor(Color.white); - - perfmon.stopContext(); // graphics - - if (stopElm != null && stopElm != mouseElm) - stopElm.setMouseElm(false); - - frames++; - - // if we did DC analysis, we need to re-analyze the circuit with that flag - // cleared. - if (dcAnalysisFlag) { - dcAnalysisFlag = false; - analyzeFlag = true; - } - - lastFrameTime = lastTime; - - perfmon.stopContext(); // updateCircuit - - if (developerMode) { - int height = 15; - int increment = 15; - g.drawString("Framerate: " + CircuitElm.showFormat.format(framerate), 10, height); - g.drawString("Steprate: " + CircuitElm.showFormat.format(steprate), 10, height += increment); - g.drawString("Steprate/iter: " + CircuitElm.showFormat.format(steprate / getIterCount()), 10, height += increment); - g.drawString("iterc: " + CircuitElm.showFormat.format(getIterCount()), 10, height += increment); - g.drawString("Frames: " + frames, 10, height += increment); - - height += (increment * 2); - - String perfmonResult = PerfMonitor.buildString(perfmon).toString(); - String[] splits = perfmonResult.split("\n"); - for (int x = 0; x < splits.length; x++) { - g.drawString(splits[x], 10, height + (increment * x)); - } - } - - // This should always be the last - // thing called by updateCircuit(); - callUpdateHook(); + PerfMonitor perfmon = new PerfMonitor(); + perfmon.startContext("updateCircuit()"); + + checkCanvasSize(); + + // Analyze circuit + boolean didAnalyze = analyzeFlag; + if (analyzeFlag || dcAnalysisFlag) { + perfmon.startContext("analyzeCircuit()"); + analyzeCircuit(); + analyzeFlag = false; + perfmon.stopContext(); + } + + // Stamp circuit + if (needsStamp && simRunning) { + perfmon.startContext("stampCircuit()"); + try { + stampCircuit(); + } catch (Exception e) { + stop("Exception in stampCircuit()", null); + } + perfmon.stopContext(); + } + + if (stopElm != null && stopElm != mouseElm) + stopElm.setMouseElm(true); + + setupScopes(); + + Graphics g = new Graphics(cvcontext); + + if (printableCheckItem.getState()) { + CircuitElm.whiteColor = Color.black; + CircuitElm.lightGrayColor = Color.black; + g.setColor(Color.white); + cv.getElement().getStyle().setBackgroundColor("#fff"); + } else { + CircuitElm.whiteColor = Color.white; + CircuitElm.lightGrayColor = Color.lightGray; + g.setColor(Color.black); + cv.getElement().getStyle().setBackgroundColor("#000"); + } + + // Clear the frame + g.fillRect(0, 0, canvasWidth, canvasHeight); + + // Run circuit + if (simRunning) { + if (needsStamp) + console("needsStamp while simRunning?"); + + perfmon.startContext("runCircuit()"); + try { + runCircuit(didAnalyze); + } catch (Exception e) { + debugger(); + console("exception in runCircuit " + e); + e.printStackTrace(); + } + perfmon.stopContext(); + } + + long sysTime = System.currentTimeMillis(); + if (simRunning) { + if (lastTime != 0) { + int inc = (int) (sysTime - lastTime); + double c = currentBar.getValue(); + c = java.lang.Math.exp(c / 3.5 - 14.2); + CircuitElm.currentMult = 1.7 * inc * c; + if (!conventionCheckItem.getState()) + CircuitElm.currentMult = -CircuitElm.currentMult; + } + lastTime = sysTime; + } else { + lastTime = 0; + } + + if (sysTime - secTime >= 1000) { + framerate = frames; + steprate = steps; + frames = 0; + steps = 0; + secTime = sysTime; + } + + CircuitElm.powerMult = Math.exp(powerBar.getValue() / 4.762 - 7); + + perfmon.startContext("graphics"); + + g.setFont(CircuitElm.unitsFont); + + g.context.setLineCap(LineCap.ROUND); + + if (noEditCheckItem.getState()) + g.drawLock(20, 30); + + g.setColor(Color.white); + + // Set the graphics transform to deal with zoom and offset + double scale = devicePixelRatio(); + cvcontext.setTransform(transform[0] * scale, 0, 0, transform[3] * scale, transform[4] * scale, + transform[5] * scale); + + // Draw each element + perfmon.startContext("elm.draw()"); + for (int i = 0; i != elmList.size(); i++) { + if (powerCheckItem.getState()) + g.setColor(Color.gray); + + getElm(i).draw(g); + } + perfmon.stopContext(); + + // Draw posts normally + if (mouseMode != CirSim.MODE_DRAG_ROW && mouseMode != CirSim.MODE_DRAG_COLUMN) { + for (int i = 0; i != postDrawList.size(); i++) + CircuitElm.drawPost(g, postDrawList.get(i)); + } + + // for some mouse modes, what matters is not the posts but the endpoints (which + // are only the same for 2-terminal elements). We draw those now if needed + if (tempMouseMode == MODE_DRAG_ROW || tempMouseMode == MODE_DRAG_COLUMN || tempMouseMode == MODE_DRAG_POST + || tempMouseMode == MODE_DRAG_SELECTED) { + for (int i = 0; i != elmList.size(); i++) { + + CircuitElm ce = getElm(i); + // ce.drawPost(g, ce.x , ce.y ); + // ce.drawPost(g, ce.x2, ce.y2); + if (ce != mouseElm || tempMouseMode != MODE_DRAG_POST) { + g.setColor(Color.gray); + g.fillOval(ce.x - 3, ce.y - 3, 7, 7); + g.fillOval(ce.x2 - 3, ce.y2 - 3, 7, 7); + } else { + ce.drawHandles(g, CircuitElm.selectColor); + } + } + } + + // draw handles for elm we're creating + if (tempMouseMode == MODE_SELECT && mouseElm != null) { + mouseElm.drawHandles(g, CircuitElm.selectColor); + } + + // draw handles for elm we're dragging + if (dragElm != null && (dragElm.x != dragElm.x2 || dragElm.y != dragElm.y2)) { + dragElm.draw(g); + dragElm.drawHandles(g, CircuitElm.selectColor); + } + + // draw bad connections. do this last so they will not be overdrawn. + for (int i = 0; i != badConnectionList.size(); i++) { + Point cn = badConnectionList.get(i); + g.setColor(Color.red); + g.fillOval(cn.x - 3, cn.y - 3, 7, 7); + } + + // draw the selection rect + if (selectedArea != null) { + g.setColor(CircuitElm.selectColor); + g.drawRect(selectedArea.x, selectedArea.y, selectedArea.width, selectedArea.height); + } + + // draw the crosshair cursor + if (crossHairCheckItem.getState() && mouseCursorX >= 0 && mouseCursorX <= circuitArea.width + && mouseCursorY <= circuitArea.height) { + g.setColor(Color.gray); + int x = snapGrid(inverseTransformX(mouseCursorX)); + int y = snapGrid(inverseTransformY(mouseCursorY)); + g.drawLine(x, inverseTransformY(0), x, inverseTransformY(circuitArea.height)); + g.drawLine(inverseTransformX(0), y, inverseTransformX(circuitArea.width), y); + } + + // reset the graphics scale and translation + cvcontext.setTransform(scale, 0, 0, scale, 0, 0); + + // draw the bottom area i.e. the scope and info section + perfmon.startContext("drawBottomArea()"); + drawBottomArea(g); + perfmon.stopContext(); + + g.setColor(Color.white); + + perfmon.stopContext(); // graphics + + if (stopElm != null && stopElm != mouseElm) + stopElm.setMouseElm(false); + + frames++; + + // if we did DC analysis, we need to re-analyze the circuit with that flag + // cleared. + if (dcAnalysisFlag) { + dcAnalysisFlag = false; + analyzeFlag = true; + } + + lastFrameTime = lastTime; + + perfmon.stopContext(); // updateCircuit + + if (developerMode) { + int height = 15; + int increment = 15; + g.drawString("Framerate: " + CircuitElm.showFormat.format(framerate), 10, height); + g.drawString("Steprate: " + CircuitElm.showFormat.format(steprate), 10, height += increment); + g.drawString("Steprate/iter: " + CircuitElm.showFormat.format(steprate / getIterCount()), 10, + height += increment); + g.drawString("iterc: " + CircuitElm.showFormat.format(getIterCount()), 10, height += increment); + g.drawString("Frames: " + frames, 10, height += increment); + + height += (increment * 2); + + String perfmonResult = PerfMonitor.buildString(perfmon).toString(); + String[] splits = perfmonResult.split("\n"); + for (int x = 0; x < splits.length; x++) { + g.drawString(splits[x], 10, height + (increment * x)); + } + } + + // This should always be the last + // thing called by updateCircuit(); + callUpdateHook(); } void drawBottomArea(Graphics g) { int leftX = 0; int h = 0; if (stopMessage == null && scopeCount == 0) { - leftX = max(canvasWidth-infoWidth, 0); + leftX = max(canvasWidth - infoWidth, 0); int h0 = (int) (canvasHeight * scopeHeightFraction); h = (mouseElm == null) ? 70 : h0; if (hideInfoBox) h = 0; } - if (stopMessage != null && circuitArea.height > canvasHeight-30) + if (stopMessage != null && circuitArea.height > canvasHeight - 30) h = 30; g.setColor(printableCheckItem.getState() ? "#eee" : "#111"); - g.fillRect(leftX, circuitArea.height-h, circuitArea.width, canvasHeight-circuitArea.height+h); + g.fillRect(leftX, circuitArea.height - h, circuitArea.width, canvasHeight - circuitArea.height + h); g.setFont(CircuitElm.unitsFont); int ct = scopeCount; if (stopMessage != null) @@ -1640,20 +1685,20 @@ void drawBottomArea(Graphics g) { for (i = 0; i != ct; i++) scopes[i].selectScope(mouseCursorX, mouseCursorY); if (scopeElmArr != null) - for (i=0; i != scopeElmArr.length; i++) + for (i = 0; i != scopeElmArr.length; i++) scopeElmArr[i].selectScope(mouseCursorX, mouseCursorY); for (i = 0; i != ct; i++) scopes[i].draw(g); if (mouseWasOverSplitter) { - g.setColor(CircuitElm.selectColor); - g.setLineWidth(4.0); - g.drawLine(0, circuitArea.height-2, circuitArea.width, circuitArea.height-2); - g.setLineWidth(1.0); + g.setColor(CircuitElm.selectColor); + g.setLineWidth(4.0); + g.drawLine(0, circuitArea.height - 2, circuitArea.width, circuitArea.height - 2); + g.setLineWidth(1.0); } g.setColor(CircuitElm.whiteColor); if (stopMessage != null) { - g.drawString(stopMessage, 10, canvasHeight-10); + g.drawString(stopMessage, 10, canvasHeight - 10); } else if (!hideInfoBox) { // in JS it doesn't matter how big this is, there's no out-of-bounds exception String info[] = new String[10]; @@ -1664,21 +1709,20 @@ void drawBottomArea(Graphics g) { if (info[1] != null) info[1] = Locale.LS(info[1]); } else - info[0] = "V = " + - CircuitElm.getUnitText(mouseElm.getPostVoltage(mousePost), "V"); -// /* //shownodes -// for (i = 0; i != mouseElm.getPostCount(); i++) -// info[0] += " " + mouseElm.nodes[i]; -// if (mouseElm.getVoltageSourceCount() > 0) -// info[0] += ";" + (mouseElm.getVoltageSource()+nodeList.size()); -// */ - + info[0] = "V = " + CircuitElm.getUnitText(mouseElm.getPostVoltage(mousePost), "V"); + // /* //shownodes + // for (i = 0; i != mouseElm.getPostCount(); i++) + // info[0] += " " + mouseElm.nodes[i]; + // if (mouseElm.getVoltageSourceCount() > 0) + // info[0] += ";" + (mouseElm.getVoltageSource()+nodeList.size()); + // */ + } else { - info[0] = "t = " + CircuitElm.getTimeText(t); - double timerate = 160*getIterCount()*timeStep; - if (timerate >= .1) - info[0] += " (" + CircuitElm.showFormat.format(timerate) + "x)"; - info[1] = Locale.LS("time step = ") + CircuitElm.getTimeText(timeStep); + info[0] = "t = " + CircuitElm.getTimeText(t); + double timerate = 160 * getIterCount() * timeStep; + if (timerate >= .1) + info[0] += " (" + CircuitElm.showFormat.format(timerate) + "x)"; + info[1] = Locale.LS("time step = ") + CircuitElm.getTimeText(timeStep); } if (hintType != -1) { for (i = 0; info[i] != null; i++) @@ -1691,110 +1735,109 @@ void drawBottomArea(Graphics g) { } int x = leftX + 5; if (ct != 0) - x = scopes[ct-1].rightEdge() + 20; -// x = max(x, canvasWidth*2/3); - // x=cv.getCoordinateSpaceWidth()*2/3; - + x = scopes[ct - 1].rightEdge() + 20; + // x = max(x, canvasWidth*2/3); + // x=cv.getCoordinateSpaceWidth()*2/3; + // count lines of data for (i = 0; info[i] != null; i++) ; int badnodes = badConnectionList.size(); if (badnodes > 0) - info[i++] = badnodes + ((badnodes == 1) ? - Locale.LS(" bad connection") : Locale.LS(" bad connections")); + info[i++] = badnodes + ((badnodes == 1) ? Locale.LS(" bad connection") : Locale.LS(" bad connections")); if (savedFlag) info[i++] = "(saved)"; - int ybase = circuitArea.height-h; + int ybase = circuitArea.height - h; for (i = 0; info[i] != null; i++) - g.drawString(info[i], x, ybase+15*(i+1)); + g.drawString(info[i], x, ybase + 15 * (i + 1)); } } - + Color getBackgroundColor() { if (printableCheckItem.getState()) return Color.white; return Color.black; } - + int oldScopeCount = -1; - + boolean scopeMenuIsSelected(Scope s) { if (scopeMenuSelected < 0) return false; if (scopeMenuSelected < scopeCount) return scopes[scopeMenuSelected] == s; - return getNthScopeElm(scopeMenuSelected-scopeCount).elmScope == s; + return getNthScopeElm(scopeMenuSelected - scopeCount).elmScope == s; } - + void setupScopes() { - int i; - - // check scopes to make sure the elements still exist, and remove - // unused scopes/columns - int pos = -1; - for (i = 0; i < scopeCount; i++) { - if (scopes[i].needToRemove()) { - int j; - for (j = i; j != scopeCount; j++) - scopes[j] = scopes[j+1]; - scopeCount--; - i--; - continue; - } - if (scopes[i].position > pos+1) - scopes[i].position = pos+1; - pos = scopes[i].position; - } - while (scopeCount > 0 && scopes[scopeCount-1].getElm() == null) - scopeCount--; - int h = canvasHeight - circuitArea.height; - pos = 0; - for (i = 0; i != scopeCount; i++) - scopeColCount[i] = 0; - for (i = 0; i != scopeCount; i++) { - pos = max(scopes[i].position, pos); - scopeColCount[scopes[i].position]++; - } - int colct = pos+1; - int iw = infoWidth; - if (colct <= 2) - iw = iw*3/2; - int w = (canvasWidth-iw) / colct; - int marg = 10; - if (w < marg*2) - w = marg*2; - pos = -1; - int colh = 0; - int row = 0; - int speed = 0; - for (i = 0; i != scopeCount; i++) { - Scope s = scopes[i]; - if (s.position > pos) { - pos = s.position; - colh = h / scopeColCount[pos]; - row = 0; - speed = s.speed; - } - s.stackCount = scopeColCount[pos]; - if (s.speed != speed) { - s.speed = speed; - s.resetGraph(); - } - Rectangle r = new Rectangle(pos*w, canvasHeight-h+colh*row, w-marg, colh); - row++; - if (!r.equals(s.rect)) - s.setRect(r); - } - if (oldScopeCount != scopeCount) { - setCircuitArea(); - oldScopeCount = scopeCount; - } - } - - String getHint() { - CircuitElm c1 = getElm(hintItem1); - CircuitElm c2 = getElm(hintItem2); + int i; + + // check scopes to make sure the elements still exist, and remove + // unused scopes/columns + int pos = -1; + for (i = 0; i < scopeCount; i++) { + if (scopes[i].needToRemove()) { + int j; + for (j = i; j != scopeCount; j++) + scopes[j] = scopes[j + 1]; + scopeCount--; + i--; + continue; + } + if (scopes[i].position > pos + 1) + scopes[i].position = pos + 1; + pos = scopes[i].position; + } + while (scopeCount > 0 && scopes[scopeCount - 1].getElm() == null) + scopeCount--; + int h = canvasHeight - circuitArea.height; + pos = 0; + for (i = 0; i != scopeCount; i++) + scopeColCount[i] = 0; + for (i = 0; i != scopeCount; i++) { + pos = max(scopes[i].position, pos); + scopeColCount[scopes[i].position]++; + } + int colct = pos + 1; + int iw = infoWidth; + if (colct <= 2) + iw = iw * 3 / 2; + int w = (canvasWidth - iw) / colct; + int marg = 10; + if (w < marg * 2) + w = marg * 2; + pos = -1; + int colh = 0; + int row = 0; + int speed = 0; + for (i = 0; i != scopeCount; i++) { + Scope s = scopes[i]; + if (s.position > pos) { + pos = s.position; + colh = h / scopeColCount[pos]; + row = 0; + speed = s.speed; + } + s.stackCount = scopeColCount[pos]; + if (s.speed != speed) { + s.speed = speed; + s.resetGraph(); + } + Rectangle r = new Rectangle(pos * w, canvasHeight - h + colh * row, w - marg, colh); + row++; + if (!r.equals(s.rect)) + s.setRect(r); + } + if (oldScopeCount != scopeCount) { + setCircuitArea(); + oldScopeCount = scopeCount; + } + } + + String getHint() { + CircuitElm c1 = getElm(hintItem1); + CircuitElm c2 = getElm(hintItem2); if (c1 == null || c2 == null) return null; if (hintType == HINT_LC) { @@ -1804,8 +1847,8 @@ String getHint() { return null; InductorElm ie = (InductorElm) c1; CapacitorElm ce = (CapacitorElm) c2; - return Locale.LS("res.f = ") + CircuitElm.getUnitText(1/(2*pi*Math.sqrt(ie.inductance* - ce.capacitance)), "Hz"); + return Locale.LS("res.f = ") + + CircuitElm.getUnitText(1 / (2 * pi * Math.sqrt(ie.inductance * ce.capacitance)), "Hz"); } if (hintType == HINT_RC) { if (!(c1 instanceof ResistorElm)) @@ -1814,8 +1857,7 @@ String getHint() { return null; ResistorElm re = (ResistorElm) c1; CapacitorElm ce = (CapacitorElm) c2; - return "RC = " + CircuitElm.getUnitText(re.resistance*ce.capacitance, - "s"); + return "RC = " + CircuitElm.getUnitText(re.resistance * ce.capacitance, "s"); } if (hintType == HINT_3DB_C) { if (!(c1 instanceof ResistorElm)) @@ -1824,8 +1866,7 @@ String getHint() { return null; ResistorElm re = (ResistorElm) c1; CapacitorElm ce = (CapacitorElm) c2; - return Locale.LS("f.3db = ") + - CircuitElm.getUnitText(1/(2*pi*re.resistance*ce.capacitance), "Hz"); + return Locale.LS("f.3db = ") + CircuitElm.getUnitText(1 / (2 * pi * re.resistance * ce.capacitance), "Hz"); } if (hintType == HINT_3DB_L) { if (!(c1 instanceof ResistorElm)) @@ -1834,8 +1875,7 @@ String getHint() { return null; ResistorElm re = (ResistorElm) c1; InductorElm ie = (InductorElm) c2; - return Locale.LS("f.3db = ") + - CircuitElm.getUnitText(re.resistance/(2*pi*ie.inductance), "Hz"); + return Locale.LS("f.3db = ") + CircuitElm.getUnitText(re.resistance / (2 * pi * ie.inductance), "Hz"); } if (hintType == HINT_TWINT) { if (!(c1 instanceof ResistorElm)) @@ -1844,33 +1884,32 @@ String getHint() { return null; ResistorElm re = (ResistorElm) c1; CapacitorElm ce = (CapacitorElm) c2; - return Locale.LS("fc = ") + - CircuitElm.getUnitText(1/(2*pi*re.resistance*ce.capacitance), "Hz"); + return Locale.LS("fc = ") + CircuitElm.getUnitText(1 / (2 * pi * re.resistance * ce.capacitance), "Hz"); } return null; } -// public void toggleSwitch(int n) { -// int i; -// for (i = 0; i != elmList.size(); i++) { -// CircuitElm ce = getElm(i); -// if (ce instanceof SwitchElm) { -// n--; -// if (n == 0) { -// ((SwitchElm) ce).toggle(); -// analyzeFlag = true; -// cv.repaint(); -// return; -// } -// } -// } -// } - + // public void toggleSwitch(int n) { + // int i; + // for (i = 0; i != elmList.size(); i++) { + // CircuitElm ce = getElm(i); + // if (ce instanceof SwitchElm) { + // n--; + // if (n == 0) { + // ((SwitchElm) ce).toggle(); + // analyzeFlag = true; + // cv.repaint(); + // return; + // } + // } + // } + // } + void needAnalyze() { analyzeFlag = true; - repaint(); + repaint(); } - + Vector nodeList; Vector postDrawList = new Vector(); Vector badConnectionList = new Vector(); @@ -1887,7 +1926,7 @@ public CircuitElm getElm(int n) { return null; return elmList.elementAt(n); } - + public Adjustable findAdjustable(CircuitElm elm, int item) { int i; for (i = 0; i != adjustables.size(); i++) { @@ -1897,44 +1936,55 @@ public Adjustable findAdjustable(CircuitElm elm, int item) { } return null; } - + public static native void console(String text) /*-{ - console.log(text); - }-*/; + console.log(text); + }-*/; public static native void debugger() /*-{ debugger; }-*/; - + class NodeMapEntry { int node; - NodeMapEntry() { node = -1; } - NodeMapEntry(int n) { node = n; } + + NodeMapEntry() { + node = -1; + } + + NodeMapEntry(int n) { + node = n; + } } + // map points to node numbers - HashMap nodeMap; - HashMap postCountMap; - + HashMap nodeMap; + HashMap postCountMap; + class WireInfo { CircuitElm wire; Vector neighbors; int post; + WireInfo(CircuitElm w) { wire = w; } } - + // info about each wire and its neighbors, used to calculate wire currents Vector wireInfoList; - - // find groups of nodes connected by wire equivalents and map them to the same node. this speeds things - // up considerably by reducing the size of the matrix. We do this for wires, labeled nodes, and ground. - // The actual node we map to is not assigned yet. Instead we map to the same NodeMapEntry. + + // find groups of nodes connected by wire equivalents and map them to the same + // node. this speeds things + // up considerably by reducing the size of the matrix. We do this for wires, + // labeled nodes, and ground. + // The actual node we map to is not assigned yet. Instead we map to the same + // NodeMapEntry. void calculateWireClosure() { int i; LabeledNodeElm.resetNodeList(); GroundElm.resetNodeList(); - nodeMap = new HashMap(); -// int mergeCount = 0; + nodeMap = new HashMap(); + // int mergeCount = 0; wireInfoList = new Vector(); for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); @@ -1943,12 +1993,13 @@ void calculateWireClosure() { ce.hasWireInfo = false; wireInfoList.add(new WireInfo(ce)); Point p0 = ce.getPost(0); - NodeMapEntry cn = nodeMap.get(p0); - + NodeMapEntry cn = nodeMap.get(p0); + // what post are we connected to Point p1 = ce.getConnectedPost(); if (p1 == null) { - // no connected post (true for labeled node the first time it's encountered, or ground) + // no connected post (true for labeled node the first time it's encountered, or + // ground) if (cn == null) { cn = new NodeMapEntry(); nodeMap.put(p0, cn); @@ -1957,12 +2008,13 @@ void calculateWireClosure() { } NodeMapEntry cn2 = nodeMap.get(p1); if (cn != null && cn2 != null) { - // merge nodes; go through map and change all keys pointing to cn2 to point to cn + // merge nodes; go through map and change all keys pointing to cn2 to point to + // cn for (Map.Entry entry : nodeMap.entrySet()) { if (entry.getValue() == cn2) entry.setValue(cn); } -// mergeCount++; + // mergeCount++; continue; } if (cn != null) { @@ -1978,37 +2030,47 @@ void calculateWireClosure() { nodeMap.put(p0, cn); nodeMap.put(p1, cn); } - -// console("got " + (groupCount-mergeCount) + " groups with " + nodeMap.size() + " nodes " + mergeCount); - } - - // generate info we need to calculate wire currents. Most other elements calculate currents using - // the voltage on their terminal nodes. But wires have the same voltage at both ends, so we need - // to use the neighbors' currents instead. We used to treat wires as zero voltage sources to make - // this easier, but this is very inefficient, since it makes the matrix 2 rows bigger for each wire. - // We create a list of WireInfo objects instead to help us calculate the wire currents instead, - // so we make the matrix less complex, and we only calculate the wire currents when we need them - // (once per frame, not once per subiteration). We need the WireInfos arranged in the correct order, - // each one containing a list of neighbors and which end to use (since one end may be ready before + + // console("got " + (groupCount-mergeCount) + " groups with " + nodeMap.size() + + // " nodes " + mergeCount); + } + + // generate info we need to calculate wire currents. Most other elements + // calculate currents using + // the voltage on their terminal nodes. But wires have the same voltage at both + // ends, so we need + // to use the neighbors' currents instead. We used to treat wires as zero + // voltage sources to make + // this easier, but this is very inefficient, since it makes the matrix 2 rows + // bigger for each wire. + // We create a list of WireInfo objects instead to help us calculate the wire + // currents instead, + // so we make the matrix less complex, and we only calculate the wire currents + // when we need them + // (once per frame, not once per subiteration). We need the WireInfos arranged + // in the correct order, + // each one containing a list of neighbors and which end to use (since one end + // may be ready before // the other) boolean calcWireInfo() { int i; int moved = 0; - + for (i = 0; i != wireInfoList.size(); i++) { WireInfo wi = wireInfoList.get(i); CircuitElm wire = wi.wire; - CircuitNode cn1 = nodeList.get(wire.getNode(0)); // both ends of wire have same node # + CircuitNode cn1 = nodeList.get(wire.getNode(0)); // both ends of wire have same node # int j; Vector neighbors0 = new Vector(); Vector neighbors1 = new Vector(); - + // assume each end is ready (except ground nodes which have one end) // labeled nodes are treated as having 2 terminals, see below boolean isReady0 = true, isReady1 = !(wire instanceof GroundElm); - // go through elements sharing a node with this wire (may be connected indirectly + // go through elements sharing a node with this wire (may be connected + // indirectly // by other wires, but at least it's faster than going through all elements) for (j = 0; j != cn1.links.size(); j++) { CircuitNodeLink cnl = cn1.links.get(j); @@ -2016,26 +2078,30 @@ boolean calcWireInfo() { if (ce == wire) continue; Point pt = ce.getPost(cnl.num); - - // is this a wire that doesn't have wire info yet? If so we can't use it yet. - // That would create a circular dependency. So that side isn't ready. + + // is this a wire that doesn't have wire info yet? If so we can't use it yet. + // That would create a circular dependency. So that side isn't ready. boolean notReady = (ce.isRemovableWire() && !ce.hasWireInfo); - + // which post does this element connect to, if any? if (pt.x == wire.x && pt.y == wire.y) { neighbors0.add(ce); - if (notReady) isReady0 = false; + if (notReady) + isReady0 = false; } else if (wire.getPostCount() > 1) { Point p2 = wire.getConnectedPost(); - if (pt.x == p2.x && pt.y == p2.y) { + if (pt.x == p2.x && pt.y == p2.y) { neighbors1.add(ce); - if (notReady) isReady1 = false; + if (notReady) + isReady1 = false; } - } else if (ce instanceof LabeledNodeElm && wire instanceof LabeledNodeElm && - ((LabeledNodeElm) ce).text == ((LabeledNodeElm) wire).text) { - // ce and wire are both labeled nodes with matching labels. treat them as neighbors + } else if (ce instanceof LabeledNodeElm && wire instanceof LabeledNodeElm + && ((LabeledNodeElm) ce).text == ((LabeledNodeElm) wire).text) { + // ce and wire are both labeled nodes with matching labels. treat them as + // neighbors neighbors1.add(ce); - if (notReady) isReady1 = false; + if (notReady) + isReady1 = false; } } @@ -2060,7 +2126,7 @@ boolean calcWireInfo() { } } } - + return true; } @@ -2070,23 +2136,23 @@ void setGroundNode() { boolean gotGround = false; boolean gotRail = false; CircuitElm volt = null; - - //System.out.println("ac1"); + + // System.out.println("ac1"); // look for voltage or ground element for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); if (ce instanceof GroundElm) { gotGround = true; - + // set ground node to 0 NodeMapEntry nme = nodeMap.get(ce.getPost(0)); nme.node = 0; break; } if (ce instanceof RailElm) - gotRail = true; + gotRail = true; if (volt == null && ce instanceof VoltageElm) - volt = ce; + volt = ce; } // if no ground, and no rails, then the voltage elm's first terminal @@ -2118,18 +2184,19 @@ void makeNodeList() { int inodes = ce.getInternalNodeCount(); int ivs = ce.getVoltageSourceCount(); int posts = ce.getPostCount(); - + // allocate a node for each post and match posts to nodes for (j = 0; j != posts; j++) { Point pt = ce.getPost(j); Integer g = postCountMap.get(pt); - postCountMap.put(pt, g == null ? 1 : g+1); + postCountMap.put(pt, g == null ? 1 : g + 1); NodeMapEntry cln = nodeMap.get(pt); - - // is this node not in map yet? or is the node number unallocated? + + // is this node not in map yet? or is the node number unallocated? // (we don't allocate nodes before this because changing the allocation order // of nodes changes circuit behavior and breaks backward compatibility; - // the code below to connect unconnected nodes may connect a different node to ground) + // the code below to connect unconnected nodes may connect a different node to + // ground) if (cln == null || cln.node == -1) { CircuitNode cn = new CircuitNode(); CircuitNodeLink cnl = new CircuitNodeLink(); @@ -2159,27 +2226,27 @@ void makeNodeList() { CircuitNode cn = new CircuitNode(); cn.internal = true; CircuitNodeLink cnl = new CircuitNodeLink(); - cnl.num = j+posts; + cnl.num = j + posts; cnl.elm = ce; cn.links.addElement(cnl); ce.setNode(cnl.num, nodeList.size()); nodeList.addElement(cn); } - + // also count voltage sources so we can allocate array vscount += ivs; } - - voltageSources = new CircuitElm[vscount]; + + voltageSources = new CircuitElm[vscount]; } - + Vector unconnectedNodes; Vector nodesWithGroundConnection; int nodesWithGroundConnectionCount; - + void findUnconnectedNodes() { int i, j; - + // determine nodes that are not connected indirectly to ground. // all nodes must be connected to ground somehow, or else we // will get a matrix error. @@ -2223,21 +2290,24 @@ void findUnconnectedNodes() { if (changed) continue; - // connect one of the unconnected nodes to ground with a big resistor, then try again + // connect one of the unconnected nodes to ground with a big resistor, then try + // again for (i = 0; i != nodeList.size(); i++) if (!closure[i] && !getCircuitNode(i).internal) { unconnectedNodes.add(i); console("node " + i + " unconnected"); -// stampResistor(0, i, 1e8); // do this later in connectUnconnectedNodes() + // stampResistor(0, i, 1e8); // do this later in connectUnconnectedNodes() closure[i] = true; changed = true; break; } } } - - // take list of unconnected nodes, which we identified earlier, and connect them to ground - // with a big resistor. otherwise we will get matrix errors. The resistor has to be big, + + // take list of unconnected nodes, which we identified earlier, and connect them + // to ground + // with a big resistor. otherwise we will get matrix errors. The resistor has to + // be big, // otherwise circuits like 555 Square Wave will break void connectUnconnectedNodes() { int i; @@ -2246,43 +2316,39 @@ void connectUnconnectedNodes() { stampResistor(0, n, 1e8); } } - + boolean validateCircuit() { int i, j; - + for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); // look for inductors with no current path if (ce instanceof InductorElm) { - FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, - ce.getNode(1)); + FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, ce.getNode(1)); if (!fpi.findPath(ce.getNode(0))) { -// console(ce + " no path"); + // console(ce + " no path"); ce.reset(); } } // look for current sources with no current path if (ce instanceof CurrentElm) { CurrentElm cur = (CurrentElm) ce; - FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, - ce.getNode(1)); + FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, ce.getNode(1)); cur.setBroken(!fpi.findPath(ce.getNode(0))); } if (ce instanceof VCCSElm) { VCCSElm cur = (VCCSElm) ce; - FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, - cur.getOutputNode(0)); + FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, cur.getOutputNode(0)); if (cur.hasCurrentOutput() && !fpi.findPath(cur.getOutputNode(1))) { cur.broken = true; } else cur.broken = false; } - - // look for voltage source or wire loops. we do this for voltage sources + + // look for voltage source or wire loops. we do this for voltage sources if (ce.getPostCount() == 2) { if (ce instanceof VoltageElm) { - FindPathInfo fpi = new FindPathInfo(FindPathInfo.VOLTAGE, ce, - ce.getNode(1)); + FindPathInfo fpi = new FindPathInfo(FindPathInfo.VOLTAGE, ce, ce.getNode(1)); if (fpi.findPath(ce.getNode(0))) { stop("Voltage source/wire loop with no resistance!", ce); return false; @@ -2298,19 +2364,22 @@ boolean validateCircuit() { return false; } } - + // look for shorted caps, or caps w/ voltage but no R if (ce instanceof CapacitorElm) { - FindPathInfo fpi = new FindPathInfo(FindPathInfo.SHORT, ce, - ce.getNode(1)); + FindPathInfo fpi = new FindPathInfo(FindPathInfo.SHORT, ce, ce.getNode(1)); if (fpi.findPath(ce.getNode(0))) { console(ce + " shorted"); ((CapacitorElm) ce).shorted(); } else { - // a capacitor loop used to cause a matrix error. but we changed the capacitor model - // so it works fine now. The only issue is if a capacitor is added in parallel with - // another capacitor with a nonzero voltage; in that case we will get oscillation unless - // we reset both capacitors to have the same voltage. Rather than check for that, we just + // a capacitor loop used to cause a matrix error. but we changed the capacitor + // model + // so it works fine now. The only issue is if a capacitor is added in parallel + // with + // another capacitor with a nonzero voltage; in that case we will get + // oscillation unless + // we reset both capacitors to have the same voltage. Rather than check for + // that, we just // give an error. fpi = new FindPathInfo(FindPathInfo.CAP_V, ce, ce.getNode(1)); if (fpi.findPath(ce.getNode(0))) { @@ -2322,7 +2391,7 @@ boolean validateCircuit() { } return true; } - + // analyze the circuit when something changes, so it can be simulated void analyzeCircuit() { stopMessage = null; @@ -2334,23 +2403,23 @@ void analyzeCircuit() { } int i, j; nodeList = new Vector(); - postCountMap = new HashMap(); + postCountMap = new HashMap(); calculateWireClosure(); setGroundNode(); // allocate nodes and voltage sources makeNodeList(); - + makePostDrawList(); if (!calcWireInfo()) return; nodeMap = null; // done with this - + int vscount = 0; circuitNonLinear = false; - // determine if circuit is nonlinear. also set voltage sources + // determine if circuit is nonlinear. also set voltage sources for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); if (ce.nonLinear()) @@ -2364,7 +2433,8 @@ void analyzeCircuit() { voltageSourceCount = vscount; // show resistance in voltage sources if there's only one. - // can't use voltageSourceCount here since that counts internal voltage sources, like the one in GroundElm + // can't use voltageSourceCount here since that counts internal voltage sources, + // like the one in GroundElm boolean gotVoltageSource = false; showResistanceInVoltageSources = true; for (i = 0; i != elmList.size(); i++) { @@ -2380,26 +2450,27 @@ void analyzeCircuit() { findUnconnectedNodes(); if (!validateCircuit()) return; - + nodesWithGroundConnectionCount = nodesWithGroundConnection.size(); // only need this for validation nodesWithGroundConnection = null; - + timeStep = maxTimeStep; needsStamp = true; - + callAnalyzeHook(); } - // stamp the matrix, meaning populate the matrix as required to simulate the circuit (for all linear elements, at least) + // stamp the matrix, meaning populate the matrix as required to simulate the + // circuit (for all linear elements, at least) void stampCircuit() { int i; - int matrixSize = nodeList.size()-1 + voltageSourceCount; + int matrixSize = nodeList.size() - 1 + voltageSourceCount; circuitMatrix = new double[matrixSize][matrixSize]; circuitRightSide = new double[matrixSize]; - nodeVoltages = new double[nodeList.size()-1]; + nodeVoltages = new double[nodeList.size() - 1]; if (lastNodeVoltages == null || lastNodeVoltages.length != nodeVoltages.length) - lastNodeVoltages = new double[nodeList.size()-1]; + lastNodeVoltages = new double[nodeList.size() - 1]; origMatrix = new double[matrixSize][matrixSize]; origRightSide = new double[matrixSize]; circuitMatrixSize = circuitMatrixFullSize = matrixSize; @@ -2408,7 +2479,7 @@ void stampCircuit() { for (i = 0; i != matrixSize; i++) circuitRowInfo[i] = new RowInfo(); circuitNeedsMap = false; - + connectUnconnectedNodes(); // stamp linear circuit elements @@ -2420,11 +2491,11 @@ void stampCircuit() { if (!simplifyMatrix(matrixSize)) return; - + // check if we called stop() if (circuitMatrix == null) return; - + // if a matrix is linear, we can do the lu_factor here instead of // needing to do it every frame if (!circuitNonLinear) { @@ -2433,8 +2504,9 @@ void stampCircuit() { return; } } - - // copy elmList to an array to avoid a bunch of calls to canCast() when doing simulation + + // copy elmList to an array to avoid a bunch of calls to canCast() when doing + // simulation elmArr = new CircuitElm[elmList.size()]; int scopeElmCount = 0; for (i = 0; i != elmList.size(); i++) { @@ -2442,19 +2514,21 @@ void stampCircuit() { if (elmArr[i] instanceof ScopeElm) scopeElmCount++; } - - // copy ScopeElms to an array to avoid a second pass over entire list of elms during simulation + + // copy ScopeElms to an array to avoid a second pass over entire list of elms + // during simulation scopeElmArr = new ScopeElm[scopeElmCount]; int j = 0; for (i = 0; i != elmList.size(); i++) { if (elmArr[i] instanceof ScopeElm) scopeElmArr[j++] = (ScopeElm) elmArr[i]; - } + } needsStamp = false; } - // simplify the matrix; this speeds things up quite a bit, especially for digital circuits. + // simplify the matrix; this speeds things up quite a bit, especially for + // digital circuits. // or at least it did before we added wire removal boolean simplifyMatrix(int matrixSize) { int i, j; @@ -2462,11 +2536,14 @@ boolean simplifyMatrix(int matrixSize) { int qp = -1; double qv = 0; RowInfo re = circuitRowInfo[i]; - /*System.out.println("row " + i + " " + re.lsChanges + " " + re.rsChanges + " " + - re.dropRow);*/ - -// if (qp != -100) continue; // uncomment this line to disable matrix simplification for debugging purposes - + /* + * System.out.println("row " + i + " " + re.lsChanges + " " + re.rsChanges + " " + * + re.dropRow); + */ + + // if (qp != -100) continue; // uncomment this line to disable matrix + // simplification for debugging purposes + if (re.lsChanges || re.dropRow || re.rsChanges) continue; double rsadd = 0; @@ -2477,7 +2554,7 @@ boolean simplifyMatrix(int matrixSize) { if (circuitRowInfo[j].type == RowInfo.ROW_CONST) { // keep a running total of const values that have been // removed already - rsadd -= circuitRowInfo[j].value*q; + rsadd -= circuitRowInfo[j].value * q; continue; } // ignore zeroes @@ -2489,12 +2566,13 @@ boolean simplifyMatrix(int matrixSize) { qv = q; continue; } - // more than one nonzero element? give up + // more than one nonzero element? give up break; } if (j == matrixSize) { if (qp == -1) { - // probably a singular matrix, try disabling matrix simplification above to check this + // probably a singular matrix, try disabling matrix simplification above to + // check this stop("Matrix error", null); return false; } @@ -2506,18 +2584,18 @@ boolean simplifyMatrix(int matrixSize) { continue; } elt.type = RowInfo.ROW_CONST; -// console("ROW_CONST " + i + " " + rsadd); - elt.value = (circuitRightSide[i]+rsadd)/qv; + // console("ROW_CONST " + i + " " + rsadd); + elt.value = (circuitRightSide[i] + rsadd) / qv; circuitRowInfo[i].dropRow = true; // find first row that referenced the element we just deleted for (j = 0; j != i; j++) if (circuitMatrix[j][qp] != 0) break; // start over just before that - i = j-1; + i = j - 1; } } - //System.out.println("ac7"); + // System.out.println("ac7"); // find size of new matrix int nn = 0; @@ -2525,7 +2603,7 @@ boolean simplifyMatrix(int matrixSize) { RowInfo elt = circuitRowInfo[i]; if (elt.type == RowInfo.ROW_NORMAL) { elt.mapCol = nn++; - //System.out.println("col " + i + " maps to " + elt.mapCol); + // System.out.println("col " + i + " maps to " + elt.mapCol); continue; } if (elt.type == RowInfo.ROW_CONST) @@ -2535,7 +2613,7 @@ boolean simplifyMatrix(int matrixSize) { // make the new, simplified matrix int newsize = nn; double newmatx[][] = new double[newsize][newsize]; - double newrs [] = new double[newsize]; + double newrs[] = new double[newsize]; int ii = 0; for (i = 0; i != matrixSize; i++) { RowInfo rri = circuitRowInfo[i]; @@ -2545,19 +2623,19 @@ boolean simplifyMatrix(int matrixSize) { } newrs[ii] = circuitRightSide[i]; rri.mapRow = ii; - //System.out.println("Row " + i + " maps to " + ii); + // System.out.println("Row " + i + " maps to " + ii); for (j = 0; j != matrixSize; j++) { RowInfo ri = circuitRowInfo[j]; if (ri.type == RowInfo.ROW_CONST) - newrs[ii] -= ri.value*circuitMatrix[i][j]; + newrs[ii] -= ri.value * circuitMatrix[i][j]; else newmatx[ii][ri.mapCol] += circuitMatrix[i][j]; } ii++; } -// console("old size = " + matrixSize + " new size = " + newsize); - + // console("old size = " + matrixSize + " new size = " + newsize); + circuitMatrix = newmatx; circuitRightSide = newrs; matrixSize = circuitMatrixSize = newsize; @@ -2569,9 +2647,11 @@ boolean simplifyMatrix(int matrixSize) { circuitNeedsMap = true; return true; } - - // make list of posts we need to draw. posts shared by 2 elements should be hidden, all - // others should be drawn. We can't use the node list for this purpose anymore because wires + + // make list of posts we need to draw. posts shared by 2 elements should be + // hidden, all + // others should be drawn. We can't use the node list for this purpose anymore + // because wires // have the same node number at both ends. void makePostDrawList() { postDrawList = new Vector(); @@ -2579,8 +2659,9 @@ void makePostDrawList() { for (Map.Entry entry : postCountMap.entrySet()) { if (entry.getValue() != 2) postDrawList.add(entry.getKey()); - - // look for bad connections, posts not connected to other elements which intersect + + // look for bad connections, posts not connected to other elements which + // intersect // other elements' bounding boxes if (entry.getValue() == 1) { int j; @@ -2588,7 +2669,7 @@ void makePostDrawList() { Point cn = entry.getKey(); for (j = 0; j != elmList.size() && !bad; j++) { CircuitElm ce = getElm(j); - if ( ce instanceof GraphicElm ) + if (ce instanceof GraphicElm) continue; // does this post intersect elm's bounding box? if (!ce.boundingBox.contains(cn.x, cn.y)) @@ -2610,25 +2691,27 @@ void makePostDrawList() { } class FindPathInfo { - static final int INDUCT = 1; + static final int INDUCT = 1; static final int VOLTAGE = 2; - static final int SHORT = 3; - static final int CAP_V = 4; + static final int SHORT = 3; + static final int CAP_V = 4; boolean visited[]; int dest; CircuitElm firstElm; int type; - // State object to help find loops in circuit subject to various conditions (depending on type_) - // elm_ = source and destination element. dest_ = destination node. + // State object to help find loops in circuit subject to various conditions + // (depending on type_) + // elm_ = source and destination element. dest_ = destination node. FindPathInfo(int type_, CircuitElm elm_, int dest_) { dest = dest_; type = type_; firstElm = elm_; - visited = new boolean[nodeList.size()]; + visited = new boolean[nodeList.size()]; } - // look through circuit for loop starting at node n1 of firstElm, for a path back to + // look through circuit for loop starting at node n1 of firstElm, for a path + // back to // dest node of firstElm boolean findPath(int n1) { if (n1 == dest) @@ -2656,84 +2739,85 @@ boolean findPath(int n1) { } return false; } - + boolean checkElm(int n1, CircuitElm ce) { - if (ce == firstElm) + if (ce == firstElm) + return false; + if (type == INDUCT) { + // inductors need a path free of current sources + if (ce instanceof CurrentElm) return false; - if (type == INDUCT) { - // inductors need a path free of current sources - if (ce instanceof CurrentElm) - return false; - } - if (type == VOLTAGE) { - // when checking for voltage loops, we only care about voltage sources/wires/ground - if (!(ce.isWireEquivalent() || ce instanceof VoltageElm || ce instanceof GroundElm)) - return false; - } - // when checking for shorts, just check wires - if (type == SHORT && !ce.isWireEquivalent()) + } + if (type == VOLTAGE) { + // when checking for voltage loops, we only care about voltage + // sources/wires/ground + if (!(ce.isWireEquivalent() || ce instanceof VoltageElm || ce instanceof GroundElm)) return false; - if (type == CAP_V) { - // checking for capacitor/voltage source loops - if (!(ce.isWireEquivalent() || ce instanceof CapacitorElm || ce instanceof VoltageElm)) - return false; - } - if (n1 == 0) { - // look for posts which have a ground connection; - // our path can go through ground - int j; - for (j = 0; j != ce.getConnectionNodeCount(); j++) - if (ce.hasGroundConnection(j) && findPath(ce.getConnectionNode(j))) - return true; - } + } + // when checking for shorts, just check wires + if (type == SHORT && !ce.isWireEquivalent()) + return false; + if (type == CAP_V) { + // checking for capacitor/voltage source loops + if (!(ce.isWireEquivalent() || ce instanceof CapacitorElm || ce instanceof VoltageElm)) + return false; + } + if (n1 == 0) { + // look for posts which have a ground connection; + // our path can go through ground int j; - for (j = 0; j != ce.getConnectionNodeCount(); j++) { - if (ce.getConnectionNode(j) == n1) { - if (ce.hasGroundConnection(j) && findPath(0)) + for (j = 0; j != ce.getConnectionNodeCount(); j++) + if (ce.hasGroundConnection(j) && findPath(ce.getConnectionNode(j))) + return true; + } + int j; + for (j = 0; j != ce.getConnectionNodeCount(); j++) { + if (ce.getConnectionNode(j) == n1) { + if (ce.hasGroundConnection(j) && findPath(0)) + return true; + if (type == INDUCT && ce instanceof InductorElm) { + // inductors can use paths with other inductors of matching current + double c = ce.getCurrent(); + if (j == 0) + c = -c; + if (Math.abs(c - firstElm.getCurrent()) > 1e-10) + continue; + } + int k; + for (k = 0; k != ce.getConnectionNodeCount(); k++) { + if (j == k) + continue; + if (ce.getConnection(j, k) && findPath(ce.getConnectionNode(k))) { + // System.out.println("got findpath " + n1); return true; - if (type == INDUCT && ce instanceof InductorElm) { - // inductors can use paths with other inductors of matching current - double c = ce.getCurrent(); - if (j == 0) - c = -c; - if (Math.abs(c-firstElm.getCurrent()) > 1e-10) - continue; - } - int k; - for (k = 0; k != ce.getConnectionNodeCount(); k++) { - if (j == k) - continue; - if (ce.getConnection(j, k) && findPath(ce.getConnectionNode(k))) { - //System.out.println("got findpath " + n1); - return true; - } } } } + } return false; } } void stop(String s, CircuitElm ce) { stopMessage = Locale.LS(s); - circuitMatrix = null; // causes an exception + circuitMatrix = null; // causes an exception stopElm = ce; setSimRunning(false); analyzeFlag = false; -// cv.repaint(); + // cv.repaint(); } - + // control voltage source vs with voltage from n1 to n2 (must // also call stampVoltageSource()) void stampVCVS(int n1, int n2, double coef, int vs) { - int vn = nodeList.size()+vs; + int vn = nodeList.size() + vs; stampMatrix(vn, n1, coef); stampMatrix(vn, n2, -coef); } - + // stamp independent voltage source #vs, from n1 to n2, amount v void stampVoltageSource(int n1, int n2, int vs, double v) { - int vn = nodeList.size()+vs; + int vn = nodeList.size() + vs; stampMatrix(vn, n1, -1); stampMatrix(vn, n2, 1); stampRightSide(vn, v); @@ -2741,24 +2825,25 @@ void stampVoltageSource(int n1, int n2, int vs, double v) { stampMatrix(n2, vn, -1); } - // use this if the amount of voltage is going to be updated in doStep(), by updateVoltageSource() + // use this if the amount of voltage is going to be updated in doStep(), by + // updateVoltageSource() void stampVoltageSource(int n1, int n2, int vs) { - int vn = nodeList.size()+vs; + int vn = nodeList.size() + vs; stampMatrix(vn, n1, -1); stampMatrix(vn, n2, 1); stampRightSide(vn); stampMatrix(n1, vn, 1); stampMatrix(n2, vn, -1); } - + // update voltage source in doStep() void updateVoltageSource(int n1, int n2, int vs, double v) { - int vn = nodeList.size()+vs; + int vn = nodeList.size() + vs; stampRightSide(vn, v); } - + void stampResistor(int n1, int n2, double r) { - double r0 = 1/r; + double r0 = 1 / r; if (Double.isNaN(r0) || Double.isInfinite(r0)) { System.out.print("bad resistance " + r + " " + r0 + "\n"); int a = 0; @@ -2777,7 +2862,8 @@ void stampConductance(int n1, int n2, double r0) { stampMatrix(n2, n1, -r0); } - // specify that current from cn1 to cn2 is equal to voltage from vn1 to 2, divided by g + // specify that current from cn1 to cn2 is equal to voltage from vn1 to 2, + // divided by g void stampVCCurrentSource(int cn1, int cn2, int vn1, int vn2, double g) { stampMatrix(cn1, vn1, g); stampMatrix(cn2, vn2, g); @@ -2792,7 +2878,7 @@ void stampCurrentSource(int n1, int n2, double i) { // stamp a current source from n1 to n2 depending on current through vs void stampCCCS(int n1, int n2, int vs, double gain) { - int vn = nodeList.size()+vs; + int vn = nodeList.size() + vs; stampMatrix(n1, vn, gain); stampMatrix(n2, vn, -gain); } @@ -2805,15 +2891,15 @@ void stampMatrix(int i, int j, double x) { debugger(); if (i > 0 && j > 0) { if (circuitNeedsMap) { - i = circuitRowInfo[i-1].mapRow; - RowInfo ri = circuitRowInfo[j-1]; + i = circuitRowInfo[i - 1].mapRow; + RowInfo ri = circuitRowInfo[j - 1]; if (ri.type == RowInfo.ROW_CONST) { - //System.out.println("Stamping constant " + i + " " + j + " " + x); - circuitRightSide[i] -= x*ri.value; + // System.out.println("Stamping constant " + i + " " + j + " " + x); + circuitRightSide[i] -= x * ri.value; return; } j = ri.mapCol; - //System.out.println("stamping " + i + " " + j + " " + x); + // System.out.println("stamping " + i + " " + j + " " + x); } else { i--; j--; @@ -2827,8 +2913,8 @@ void stampMatrix(int i, int j, double x) { void stampRightSide(int i, double x) { if (i > 0) { if (circuitNeedsMap) { - i = circuitRowInfo[i-1].mapRow; - //System.out.println("stamping " + i + " " + x); + i = circuitRowInfo[i - 1].mapRow; + // System.out.println("stamping " + i + " " + x); } else i--; circuitRightSide[i] += x; @@ -2837,90 +2923,92 @@ void stampRightSide(int i, double x) { // indicate that the value on the right side of row i changes in doStep() void stampRightSide(int i) { - //System.out.println("rschanges true " + (i-1)); + // System.out.println("rschanges true " + (i-1)); if (i > 0) - circuitRowInfo[i-1].rsChanges = true; + circuitRowInfo[i - 1].rsChanges = true; } - + // indicate that the values on the left side of row i change in doStep() void stampNonLinear(int i) { if (i > 0) - circuitRowInfo[i-1].lsChanges = true; + circuitRowInfo[i - 1].lsChanges = true; } double getIterCount() { - // IES - remove interaction + // IES - remove interaction if (speedBar.getValue() == 0) - return 0; + return 0; - return .1*Math.exp((speedBar.getValue()-61)/24.); + return .1 * Math.exp((speedBar.getValue() - 61) / 24.); } - // we need to calculate wire currents for every iteration if someone is viewing a wire in the - // scope. Otherwise we can do it only once per frame. + // we need to calculate wire currents for every iteration if someone is viewing + // a wire in the + // scope. Otherwise we can do it only once per frame. boolean canDelayWireProcessing() { int i; for (i = 0; i != scopeCount; i++) if (scopes[i].viewingWire()) return false; - for (i=0; i != elmList.size(); i++) - if (getElm(i) instanceof ScopeElm && ((ScopeElm)getElm(i)).elmScope.viewingWire()) + for (i = 0; i != elmList.size(); i++) + if (getElm(i) instanceof ScopeElm && ((ScopeElm) getElm(i)).elmScope.viewingWire()) return false; return true; } - + boolean converged; int subIterations; - + void runCircuit(boolean didAnalyze) { if (circuitMatrix == null || elmList.size() == 0) { circuitMatrix = null; return; } int iter; - //int maxIter = getIterCount(); + // int maxIter = getIterCount(); boolean debugprint = dumpMatrix; dumpMatrix = false; - long steprate = (long) (160*getIterCount()); + long steprate = (long) (160 * getIterCount()); long tm = System.currentTimeMillis(); long lit = lastIterTime; if (lit == 0) { lastIterTime = tm; return; } - + // Check if we don't need to run simulation (for very slow simulation speeds). - // If the circuit changed, do at least one iteration to make sure everything is consistent. - if (1000 >= steprate*(tm-lastIterTime) && !didAnalyze) + // If the circuit changed, do at least one iteration to make sure everything is + // consistent. + if (1000 >= steprate * (tm - lastIterTime) && !didAnalyze) return; - + boolean delayWireProcessing = canDelayWireProcessing(); - + int timeStepCountAtFrameStart = timeStepCount; - + // keep track of iterations completed without convergence issues int goodIterations = 100; - - for (iter = 1; ; iter++) { + + for (iter = 1;; iter++) { if (goodIterations >= 3 && timeStep < maxTimeStep) { // things are going well, double the time step - timeStep = Math.min(timeStep*2, maxTimeStep); + timeStep = Math.min(timeStep * 2, maxTimeStep); console("timestep up = " + timeStep + " at " + t); stampCircuit(); goodIterations = 0; } - + int i, j, subiter; for (i = 0; i != elmArr.length; i++) elmArr[i].startIteration(); steps++; - int subiterCount = (adjustTimeStep && timeStep/2 > minTimeStep) ? 100 : 5000; + int subiterCount = (adjustTimeStep && timeStep / 2 > minTimeStep) ? 100 : 5000; for (subiter = 0; subiter != subiterCount; subiter++) { converged = true; subIterations = subiter; -// if (t % .030 < .002 && timeStep > 1e-6) // force nonconvergence for debugging -// converged = false; + // if (t % .030 < .002 && timeStep > 1e-6) // force nonconvergence for debugging + // converged = false; for (i = 0; i != circuitMatrixSize; i++) circuitRightSide[i] = origRightSide[i]; if (circuitNonLinear) { @@ -2935,7 +3023,7 @@ void runCircuit(boolean didAnalyze) { boolean printit = debugprint; debugprint = false; if (circuitMatrixSize < 8) { - // we only need this for debugging purposes, so skip it for large matrices + // we only need this for debugging purposes, so skip it for large matrices for (j = 0; j != circuitMatrixSize; j++) { for (i = 0; i != circuitMatrixSize; i++) { double x = circuitMatrix[i][j]; @@ -2961,14 +3049,12 @@ void runCircuit(boolean didAnalyze) { // stop if converged (elements check for convergence in doStep()) if (converged && subiter > 0) break; - if (!lu_factor(circuitMatrix, circuitMatrixSize, - circuitPermute)) { + if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute)) { stop("Singular matrix!", null); return; } } - lu_solve(circuitMatrix, circuitMatrixSize, circuitPermute, - circuitRightSide); + lu_solve(circuitMatrix, circuitMatrixSize, circuitPermute, circuitRightSide); applySolvedRightSide(circuitRightSide); if (!circuitNonLinear) break; @@ -2985,7 +3071,8 @@ void runCircuit(boolean didAnalyze) { stop("Convergence failed!", null); break; } - // we reduced the timestep. reset circuit state to the way it was at start of iteration + // we reduced the timestep. reset circuit state to the way it was at start of + // iteration setNodeVoltages(lastNodeVoltages); stampCircuit(); continue; @@ -3007,20 +3094,23 @@ void runCircuit(boolean didAnalyze) { if (!delayWireProcessing) calcWireCurrents(); for (i = 0; i != scopeCount; i++) - scopes[i].timeStep(); - for (i=0; i != scopeElmArr.length; i++) + scopes[i].timeStep(); + for (i = 0; i != scopeElmArr.length; i++) scopeElmArr[i].stepScope(); callTimeStepHook(); // save last node voltages so we can restart the next iteration if necessary for (i = 0; i != lastNodeVoltages.length; i++) lastNodeVoltages[i] = nodeVoltages[i]; -// console("set lastrightside at " + t + " " + lastNodeVoltages); - + // console("set lastrightside at " + t + " " + lastNodeVoltages); + tm = System.currentTimeMillis(); lit = tm; - // Check whether enough time has elapsed to perform an *additional* iteration after - // those we have already completed. But limit total computation time to 50ms (20fps) - if ((timeStepCount-timeStepCountAtFrameStart)*1000 >= steprate*(tm-lastIterTime) || (tm-lastFrameTime > 50)) + // Check whether enough time has elapsed to perform an *additional* iteration + // after + // those we have already completed. But limit total computation time to 50ms + // (20fps) + if ((timeStepCount - timeStepCountAtFrameStart) * 1000 >= steprate * (tm - lastIterTime) + || (tm - lastFrameTime > 50)) break; if (!simRunning) break; @@ -3028,12 +3118,12 @@ void runCircuit(boolean didAnalyze) { lastIterTime = lit; if (delayWireProcessing) calcWireCurrents(); -// System.out.println((System.currentTimeMillis()-lastFrameTime)/(double) iter); + // System.out.println((System.currentTimeMillis()-lastFrameTime)/(double) iter); } // set node voltages given right side found by solving matrix void applySolvedRightSide(double rs[]) { -// console("setvoltages " + rs); + // console("setvoltages " + rs); int j; for (j = 0; j != circuitMatrixFullSize; j++) { RowInfo ri = circuitRowInfo[j]; @@ -3046,39 +3136,40 @@ void applySolvedRightSide(double rs[]) { converged = false; break; } - if (j < nodeList.size()-1) { + if (j < nodeList.size() - 1) { nodeVoltages[j] = res; } else { - int ji = j-(nodeList.size()-1); + int ji = j - (nodeList.size() - 1); voltageSources[ji].setCurrent(ji, res); } } - + setNodeVoltages(nodeVoltages); } - + // set node voltages in each element given an array of node voltages void setNodeVoltages(double nv[]) { int j, k; for (j = 0; j != nv.length; j++) { double res = nv[j]; - CircuitNode cn = getCircuitNode(j+1); + CircuitNode cn = getCircuitNode(j + 1); for (k = 0; k != cn.links.size(); k++) { CircuitNodeLink cnl = cn.links.elementAt(k); cnl.elm.setNodeVoltage(cnl.num, res); } } } - - // we removed wires from the matrix to speed things up. in order to display wire currents, + + // we removed wires from the matrix to speed things up. in order to display wire + // currents, // we need to calculate them now. void calcWireCurrents() { int i; - + // for debugging - //for (i = 0; i != wireInfoList.size(); i++) - // wireInfoList.get(i).wire.setCurrent(-1, 1.23); - + // for (i = 0; i != wireInfoList.size(); i++) + // wireInfoList.get(i).wire.setCurrent(-1, 1.23); + for (i = 0; i != wireInfoList.size(); i++) { WireInfo wi = wireInfoList.get(i); double cur = 0; @@ -3097,27 +3188,32 @@ void calcWireCurrents() { wi.wire.setCurrent(-1, -cur); } } - - int min(int a, int b) { return (a < b) ? a : b; } - int max(int a, int b) { return (a > b) ? a : b; } - - public void resetAction(){ - int i; - analyzeFlag = true; - if (t == 0) - setSimRunning(true); - t = timeStepAccum = 0; - timeStepCount = 0; - for (i = 0; i != elmList.size(); i++) - getElm(i).reset(); + + int min(int a, int b) { + return (a < b) ? a : b; + } + + int max(int a, int b) { + return (a > b) ? a : b; + } + + public void resetAction() { + int i; + analyzeFlag = true; + if (t == 0) + setSimRunning(true); + t = timeStepAccum = 0; + timeStepCount = 0; + for (i = 0; i != elmList.size(); i++) + getElm(i).reset(); for (i = 0; i != scopeCount; i++) - scopes[i].resetGraph(true); - repaint(); + scopes[i].resetGraph(true); + repaint(); } - + static void electronSaveAsCallback(String s) { - s = s.substring(s.lastIndexOf('/')+1); - s = s.substring(s.lastIndexOf('\\')+1); + s = s.substring(s.lastIndexOf('/') + 1); + s = s.substring(s.lastIndexOf('\\') + 1); theSim.setCircuitTitle(s); theSim.allowSave(true); theSim.savedFlag = true; @@ -3128,7 +3224,7 @@ static void electronSaveCallback() { theSim.savedFlag = true; theSim.repaint(); } - + static native void electronSaveAs(String dump) /*-{ $wnd.showSaveDialog().then(function (file) { if (file.canceled) @@ -3142,453 +3238,454 @@ static native void electronSave(String dump) /*-{ $wnd.saveFile(null, dump); @com.lushprojects.circuitjs1.client.CirSim::electronSaveCallback()(); }-*/; - + static void electronOpenFileCallback(String text, String name) { LoadFile.doLoadCallback(text, name); theSim.allowSave(true); } - + static native void electronOpenFile() /*-{ $wnd.openFile(function (text, name) { @com.lushprojects.circuitjs1.client.CirSim::electronOpenFileCallback(Ljava/lang/String;Ljava/lang/String;)(text, name); }); }-*/; - + static native void toggleDevTools() /*-{ $wnd.toggleDevTools(); }-*/; - + static native boolean isElectron() /*-{ return ($wnd.openFile != undefined); - }-*/; + }-*/; static native String getElectronStartCircuitText() /*-{ return $wnd.startCircuitText; - }-*/; - + }-*/; + void allowSave(boolean b) { if (saveFileItem != null) saveFileItem.setEnabled(b); } - + public void menuPerformed(String menu, String item) { - if ((menu=="edit" || menu=="main" || menu=="scopes") && noEditCheckItem.getState()) { + if ((menu == "edit" || menu == "main" || menu == "scopes") && noEditCheckItem.getState()) { Window.alert(Locale.LS("Editing disabled. Re-enable from the Options menu.")); return; } - if (item=="about") - aboutBox = new AboutBox(circuitjs1.versionString); - if (item=="importfromlocalfile") { - pushUndo(); - if (isElectron()) - electronOpenFile(); - else - loadFileInput.click(); - } - if (item=="newwindow") { - Window.open(Document.get().getURL(), "_blank", ""); - } - if (item=="save") - electronSave(dumpCircuit()); - if (item=="saveas") - electronSaveAs(dumpCircuit()); - if (item=="importfromtext") { - dialogShowing = new ImportFromTextDialog(this); - } - if (item=="importfromdropbox") { - dialogShowing = new ImportFromDropboxDialog(this); - } - if (item=="exportasurl") { - doExportAsUrl(); - unsavedChanges = false; - } - if (item=="exportaslocalfile") { - doExportAsLocalFile(); - unsavedChanges = false; - } - if (item=="exportastext") { - doExportAsText(); - unsavedChanges = false; - } - if (item=="exportasimage") - doExportAsImage(); - if (item=="exportassvg") - doExportAsSVG(); - if (item=="createsubcircuit") - doCreateSubcircuit(); - if (item=="dcanalysis") - doDCAnalysis(); - if (item=="print") - doPrint(); - if (item=="recover") - doRecover(); - - if ((menu=="elm" || menu=="scopepop") && contextPanel!=null) - contextPanel.hide(); - if (menu=="options" && item=="shortcuts") { - dialogShowing = new ShortcutsDialog(this); - dialogShowing.show(); - } - if (item=="search") { - dialogShowing = new SearchDialog(this); - dialogShowing.show(); - } - if (menu=="options" && item=="other") - doEdit(new EditOptions(this)); - if (item=="devtools") - toggleDevTools(); - if (item=="undo") - doUndo(); - if (item=="redo") - doRedo(); - - // if the mouse is hovering over an element, and a shortcut key is pressed, operate on that element (treat it like a context menu item selection) - if (menu == "key" && mouseElm != null) { - menuElm = mouseElm; - menu = "elm"; - } - - if (item == "cut") { - if (menu!="elm") - menuElm = null; - doCut(); - } - if (item == "copy") { - if (menu!="elm") - menuElm = null; - doCopy(); - } - if (item=="paste") - doPaste(null); - if (item=="duplicate") { - if (menu!="elm") - menuElm = null; - doDuplicate(); - } - if (item=="flip") - doFlip(); - if (item=="split") - doSplit(menuElm); - if (item=="selectAll") - doSelectAll(); - // if (e.getSource() == exitItem) { - // destroyFrame(); - // return; - // } - - if (item=="centrecircuit") { - pushUndo(); - centreCircuit(); - } - if (item=="stackAll") - stackAll(); - if (item=="unstackAll") - unstackAll(); - if (item=="combineAll") - combineAll(); - if (item=="separateAll") - separateAll(); - if (item=="zoomin") - zoomCircuit(20, true); - if (item=="zoomout") - zoomCircuit(-20, true); - if (item=="zoom100") - setCircuitScale(1, true); - if (menu=="elm" && item=="edit") - doEdit(menuElm); - if (item=="delete") { - if (menu!="elm") - menuElm = null; - pushUndo(); - doDelete(true); - } - if (item=="sliders") - doSliders(menuElm); - - if (item=="viewInScope" && menuElm != null) { - int i; - for (i = 0; i != scopeCount; i++) - if (scopes[i].getElm() == null) - break; - if (i == scopeCount) { - if (scopeCount == scopes.length) - return; - scopeCount++; - scopes[i] = new Scope(this); - scopes[i].position = i; - //handleResize(); - } - scopes[i].setElm(menuElm); - if (i > 0) - scopes[i].speed = scopes[i-1].speed; - } - - if (item=="viewInFloatScope" && menuElm != null) { - ScopeElm newScope = new ScopeElm(snapGrid(menuElm.x+50), snapGrid(menuElm.y+50)); - elmList.addElement(newScope); - newScope.setScopeElm(menuElm); - - // need to rebuild scopeElmArr - needAnalyze(); - } - - if (item.startsWith("addToScope") && menuElm != null) { - int n; - n = Integer.parseInt(item.substring(10)); - if (n < scopeCount + countScopeElms()) { - if (n < scopeCount ) - scopes[n].addElm(menuElm); - else - getNthScopeElm(n-scopeCount).elmScope.addElm(menuElm); - } - scopeMenuSelected = -1; - } - - if (menu=="scopepop") { - pushUndo(); - Scope s; - if (menuScope != -1 ) - s= scopes[menuScope]; - else - s= ((ScopeElm)mouseElm).elmScope; - - if (item=="dock") { - if (scopeCount == scopes.length) - return; - scopes[scopeCount] = ((ScopeElm)mouseElm).elmScope; - ((ScopeElm)mouseElm).clearElmScope(); - scopes[scopeCount].position = scopeCount; - scopeCount++; - doDelete(false); - } - if (item=="undock") { - ScopeElm newScope = new ScopeElm(snapGrid(menuElm.x+50), snapGrid(menuElm.y+50)); - elmList.addElement(newScope); - newScope.setElmScope(scopes[menuScope]); - - int i; - // remove scope from list. setupScopes() will fix the positions - for (i = menuScope; i < scopeCount; i++) - scopes[i] = scopes[i+1]; - scopeCount--; - - needAnalyze(); // need to rebuild scopeElmArr - } - if (item=="remove") - s.setElm(null); // setupScopes() will clean this up - if (item=="removeplot") - s.removePlot(menuPlot); - if (item=="speed2") - s.speedUp(); - if (item=="speed1/2") - s.slowDown(); -// if (item=="scale") -// scopes[menuScope].adjustScale(.5); - if (item=="maxscale") - s.maxScale(); - if (item=="stack") - stackScope(menuScope); - if (item=="unstack") - unstackScope(menuScope); - if (item=="combine") - combineScope(menuScope); - if (item=="selecty") - s.selectY(); - if (item=="reset") - s.resetGraph(true); - if (item=="properties") - s.properties(); - deleteUnusedScopeElms(); - } - if (menu=="circuits" && item.indexOf("setup ") ==0) { - pushUndo(); - int sp = item.indexOf(' ', 6); - readSetupFile(item.substring(6, sp), item.substring(sp+1)); - } - if (item=="newblankcircuit") { - pushUndo(); - readSetupFile("blank.txt", "Blank Circuit"); - } - - // if (ac.indexOf("setup ") == 0) { - // pushUndo(); - // readSetupFile(ac.substring(6), - // ((MenuItem) e.getSource()).getLabel()); - // } - - // IES: Moved from itemStateChanged() - if (menu=="main") { - if (contextPanel!=null) - contextPanel.hide(); - // MenuItem mmi = (MenuItem) mi; - // int prevMouseMode = mouseMode; - setMouseMode(MODE_ADD_ELM); - String s = item; - if (s.length() > 0) - mouseModeStr = s; - if (s.compareTo("DragAll") == 0) - setMouseMode(MODE_DRAG_ALL); - else if (s.compareTo("DragRow") == 0) - setMouseMode(MODE_DRAG_ROW); - else if (s.compareTo("DragColumn") == 0) - setMouseMode(MODE_DRAG_COLUMN); - else if (s.compareTo("DragSelected") == 0) - setMouseMode(MODE_DRAG_SELECTED); - else if (s.compareTo("DragPost") == 0) - setMouseMode(MODE_DRAG_POST); - else if (s.compareTo("Select") == 0) - setMouseMode(MODE_SELECT); - // else if (s.length() > 0) { - // try { - // addingClass = Class.forName(s); - // } catch (Exception ee) { - // ee.printStackTrace(); - // } - // } - // else - // setMouseMode(prevMouseMode); - tempMouseMode = mouseMode; - } - if (item=="fullscreen") { - if (! Graphics.isFullScreen) - Graphics.viewFullScreen(); - else - Graphics.exitFullScreen(); - centreCircuit(); - } - - repaint(); - } - - int countScopeElms() { - int c = 0; - for (int i = 0; i != elmList.size(); i++) { - if ( elmList.get(i) instanceof ScopeElm) - c++; + if (item == "about") + aboutBox = new AboutBox(circuitjs1.versionString); + if (item == "importfromlocalfile") { + pushUndo(); + if (isElectron()) + electronOpenFile(); + else + loadFileInput.click(); } - return c; - } - - ScopeElm getNthScopeElm(int n) { - for (int i = 0; i != elmList.size(); i++) { - if ( elmList.get(i) instanceof ScopeElm) { - n--; - if (n<0) - return (ScopeElm) elmList.get(i); - } + if (item == "newwindow") { + Window.open(Document.get().getURL(), "_blank", ""); } - return (ScopeElm) null; - } - - - boolean canStackScope(int s) { - if (scopeCount < 2) - return false; - if (s==0) - s=1; - if (scopes[s].position == scopes[s-1].position) - return false; - return true; - } - - boolean canCombineScope(int s) { - return scopeCount >=2; - } - - boolean canUnstackScope(int s) { - if (scopeCount < 2) + if (item == "save") + electronSave(dumpCircuit()); + if (item == "saveas") + electronSaveAs(dumpCircuit()); + if (item == "importfromtext") { + dialogShowing = new ImportFromTextDialog(this); + } + if (item == "importfromdropbox") { + dialogShowing = new ImportFromDropboxDialog(this); + } + if (item == "exportasurl") { + doExportAsUrl(); + unsavedChanges = false; + } + if (item == "exportaslocalfile") { + doExportAsLocalFile(); + unsavedChanges = false; + } + if (item == "exportastext") { + doExportAsText(); + unsavedChanges = false; + } + if (item == "exportasimage") + doExportAsImage(); + if (item == "exportassvg") + doExportAsSVG(); + if (item == "createsubcircuit") + doCreateSubcircuit(); + if (item == "dcanalysis") + doDCAnalysis(); + if (item == "print") + doPrint(); + if (item == "recover") + doRecover(); + + if ((menu == "elm" || menu == "scopepop") && contextPanel != null) + contextPanel.hide(); + if (menu == "options" && item == "shortcuts") { + dialogShowing = new ShortcutsDialog(this); + dialogShowing.show(); + } + if (item == "search") { + dialogShowing = new SearchDialog(this); + dialogShowing.show(); + } + if (menu == "options" && item == "other") + doEdit(new EditOptions(this)); + if (item == "devtools") + toggleDevTools(); + if (item == "undo") + doUndo(); + if (item == "redo") + doRedo(); + + // if the mouse is hovering over an element, and a shortcut key is pressed, + // operate on that element (treat it like a context menu item selection) + if (menu == "key" && mouseElm != null) { + menuElm = mouseElm; + menu = "elm"; + } + + if (item == "cut") { + if (menu != "elm") + menuElm = null; + doCut(); + } + if (item == "copy") { + if (menu != "elm") + menuElm = null; + doCopy(); + } + if (item == "paste") + doPaste(null); + if (item == "duplicate") { + if (menu != "elm") + menuElm = null; + doDuplicate(); + } + if (item == "flip") + doFlip(); + if (item == "split") + doSplit(menuElm); + if (item == "selectAll") + doSelectAll(); + // if (e.getSource() == exitItem) { + // destroyFrame(); + // return; + // } + + if (item == "centrecircuit") { + pushUndo(); + centreCircuit(); + } + if (item == "stackAll") + stackAll(); + if (item == "unstackAll") + unstackAll(); + if (item == "combineAll") + combineAll(); + if (item == "separateAll") + separateAll(); + if (item == "zoomin") + zoomCircuit(20, true); + if (item == "zoomout") + zoomCircuit(-20, true); + if (item == "zoom100") + setCircuitScale(1, true); + if (menu == "elm" && item == "edit") + doEdit(menuElm); + if (item == "delete") { + if (menu != "elm") + menuElm = null; + pushUndo(); + doDelete(true); + } + if (item == "sliders") + doSliders(menuElm); + + if (item == "viewInScope" && menuElm != null) { + int i; + for (i = 0; i != scopeCount; i++) + if (scopes[i].getElm() == null) + break; + if (i == scopeCount) { + if (scopeCount == scopes.length) + return; + scopeCount++; + scopes[i] = new Scope(this); + scopes[i].position = i; + // handleResize(); + } + scopes[i].setElm(menuElm); + if (i > 0) + scopes[i].speed = scopes[i - 1].speed; + } + + if (item == "viewInFloatScope" && menuElm != null) { + ScopeElm newScope = new ScopeElm(snapGrid(menuElm.x + 50), snapGrid(menuElm.y + 50)); + elmList.addElement(newScope); + newScope.setScopeElm(menuElm); + + // need to rebuild scopeElmArr + needAnalyze(); + } + + if (item.startsWith("addToScope") && menuElm != null) { + int n; + n = Integer.parseInt(item.substring(10)); + if (n < scopeCount + countScopeElms()) { + if (n < scopeCount) + scopes[n].addElm(menuElm); + else + getNthScopeElm(n - scopeCount).elmScope.addElm(menuElm); + } + scopeMenuSelected = -1; + } + + if (menu == "scopepop") { + pushUndo(); + Scope s; + if (menuScope != -1) + s = scopes[menuScope]; + else + s = ((ScopeElm) mouseElm).elmScope; + + if (item == "dock") { + if (scopeCount == scopes.length) + return; + scopes[scopeCount] = ((ScopeElm) mouseElm).elmScope; + ((ScopeElm) mouseElm).clearElmScope(); + scopes[scopeCount].position = scopeCount; + scopeCount++; + doDelete(false); + } + if (item == "undock") { + ScopeElm newScope = new ScopeElm(snapGrid(menuElm.x + 50), snapGrid(menuElm.y + 50)); + elmList.addElement(newScope); + newScope.setElmScope(scopes[menuScope]); + + int i; + // remove scope from list. setupScopes() will fix the positions + for (i = menuScope; i < scopeCount; i++) + scopes[i] = scopes[i + 1]; + scopeCount--; + + needAnalyze(); // need to rebuild scopeElmArr + } + if (item == "remove") + s.setElm(null); // setupScopes() will clean this up + if (item == "removeplot") + s.removePlot(menuPlot); + if (item == "speed2") + s.speedUp(); + if (item == "speed1/2") + s.slowDown(); + // if (item=="scale") + // scopes[menuScope].adjustScale(.5); + if (item == "maxscale") + s.maxScale(); + if (item == "stack") + stackScope(menuScope); + if (item == "unstack") + unstackScope(menuScope); + if (item == "combine") + combineScope(menuScope); + if (item == "selecty") + s.selectY(); + if (item == "reset") + s.resetGraph(true); + if (item == "properties") + s.properties(); + deleteUnusedScopeElms(); + } + if (menu == "circuits" && item.indexOf("setup ") == 0) { + pushUndo(); + int sp = item.indexOf(' ', 6); + readSetupFile(item.substring(6, sp), item.substring(sp + 1)); + } + if (item == "newblankcircuit") { + pushUndo(); + readSetupFile("blank.txt", "Blank Circuit"); + } + + // if (ac.indexOf("setup ") == 0) { + // pushUndo(); + // readSetupFile(ac.substring(6), + // ((MenuItem) e.getSource()).getLabel()); + // } + + // IES: Moved from itemStateChanged() + if (menu == "main") { + if (contextPanel != null) + contextPanel.hide(); + // MenuItem mmi = (MenuItem) mi; + // int prevMouseMode = mouseMode; + setMouseMode(MODE_ADD_ELM); + String s = item; + if (s.length() > 0) + mouseModeStr = s; + if (s.compareTo("DragAll") == 0) + setMouseMode(MODE_DRAG_ALL); + else if (s.compareTo("DragRow") == 0) + setMouseMode(MODE_DRAG_ROW); + else if (s.compareTo("DragColumn") == 0) + setMouseMode(MODE_DRAG_COLUMN); + else if (s.compareTo("DragSelected") == 0) + setMouseMode(MODE_DRAG_SELECTED); + else if (s.compareTo("DragPost") == 0) + setMouseMode(MODE_DRAG_POST); + else if (s.compareTo("Select") == 0) + setMouseMode(MODE_SELECT); + // else if (s.length() > 0) { + // try { + // addingClass = Class.forName(s); + // } catch (Exception ee) { + // ee.printStackTrace(); + // } + // } + // else + // setMouseMode(prevMouseMode); + tempMouseMode = mouseMode; + } + if (item == "fullscreen") { + if (!Graphics.isFullScreen) + Graphics.viewFullScreen(); + else + Graphics.exitFullScreen(); + centreCircuit(); + } + + repaint(); + } + + int countScopeElms() { + int c = 0; + for (int i = 0; i != elmList.size(); i++) { + if (elmList.get(i) instanceof ScopeElm) + c++; + } + return c; + } + + ScopeElm getNthScopeElm(int n) { + for (int i = 0; i != elmList.size(); i++) { + if (elmList.get(i) instanceof ScopeElm) { + n--; + if (n < 0) + return (ScopeElm) elmList.get(i); + } + } + return (ScopeElm) null; + } + + boolean canStackScope(int s) { + if (scopeCount < 2) return false; - if (s==0) - s=1; - if (scopes[s].position != scopes[s-1].position) { - if ( s + 1 < scopeCount && scopes[s+1].position == scopes[s].position) // Allow you to unstack by selecting the top scope in the stack - return true; - else - return false; - } + if (s == 0) + s = 1; + if (scopes[s].position == scopes[s - 1].position) + return false; + return true; + } + + boolean canCombineScope(int s) { + return scopeCount >= 2; + } + + boolean canUnstackScope(int s) { + if (scopeCount < 2) + return false; + if (s == 0) + s = 1; + if (scopes[s].position != scopes[s - 1].position) { + if (s + 1 < scopeCount && scopes[s + 1].position == scopes[s].position) // Allow you to unstack by selecting + // the top scope in the stack + return true; + else + return false; + } return true; } void stackScope(int s) { - if (! canStackScope(s) ) + if (!canStackScope(s)) return; - if (s == 0) { - s = 1; - } - scopes[s].position = scopes[s-1].position; - for (s++; s < scopeCount; s++) - scopes[s].position--; + if (s == 0) { + s = 1; + } + scopes[s].position = scopes[s - 1].position; + for (s++; s < scopeCount; s++) + scopes[s].position--; } void unstackScope(int s) { - if (! canUnstackScope(s) ) + if (!canUnstackScope(s)) return; - if (s == 0) { - s = 1; - } - if (scopes[s].position != scopes[s-1].position) // Allow you to unstack by selecting the top scope in the stack - s++; - for (; s < scopeCount; s++) - scopes[s].position++; + if (s == 0) { + s = 1; + } + if (scopes[s].position != scopes[s - 1].position) // Allow you to unstack by selecting the top scope in the + // stack + s++; + for (; s < scopeCount; s++) + scopes[s].position++; } void combineScope(int s) { - if (! canCombineScope(s)) + if (!canCombineScope(s)) return; - if (s == 0) { - s = 1; - } - scopes[s-1].combine(scopes[s]); - scopes[s].setElm(null); + if (s == 0) { + s = 1; + } + scopes[s - 1].combine(scopes[s]); + scopes[s].setElm(null); } - void stackAll() { - int i; - for (i = 0; i != scopeCount; i++) { - scopes[i].position = 0; - scopes[i].showMax = scopes[i].showMin = false; - } + int i; + for (i = 0; i != scopeCount; i++) { + scopes[i].position = 0; + scopes[i].showMax = scopes[i].showMin = false; + } } void unstackAll() { - int i; - for (i = 0; i != scopeCount; i++) { - scopes[i].position = i; - scopes[i].showMax = true; - } + int i; + for (i = 0; i != scopeCount; i++) { + scopes[i].position = i; + scopes[i].showMax = true; + } } void combineAll() { - int i; - for (i = scopeCount-2; i >= 0; i--) { - scopes[i].combine(scopes[i+1]); - scopes[i+1].setElm(null); - } + int i; + for (i = scopeCount - 2; i >= 0; i--) { + scopes[i].combine(scopes[i + 1]); + scopes[i + 1].setElm(null); + } } - + void separateAll() { - int i; + int i; Scope newscopes[] = new Scope[20]; int ct = 0; - for (i = 0; i < scopeCount; i++) - ct = scopes[i].separate(newscopes, ct); + for (i = 0; i < scopeCount; i++) + ct = scopes[i].separate(newscopes, ct); scopes = newscopes; scopeCount = ct; } void doEdit(Editable eable) { - clearSelection(); - pushUndo(); - if (editDialog != null) { - // requestFocus(); - editDialog.setVisible(false); - editDialog = null; - } - editDialog = new EditDialog(eable, this); - editDialog.show(); + clearSelection(); + pushUndo(); + if (editDialog != null) { + // requestFocus(); + editDialog.setVisible(false); + editDialog = null; + } + editDialog = new EditDialog(eable, this); + editDialog.show(); } - + void doSliders(CircuitElm ce) { clearSelection(); pushUndo(); @@ -3596,49 +3693,44 @@ void doSliders(CircuitElm ce) { dialogShowing.show(); } - - void doExportAsUrl() - { - String dump = dumpCircuit(); + void doExportAsUrl() { + String dump = dumpCircuit(); dialogShowing = new ExportAsUrlDialog(dump); dialogShowing.show(); } - - void doExportAsText() - { - String dump = dumpCircuit(); - dialogShowing = new ExportAsTextDialog(this, dump); - dialogShowing.show(); + + void doExportAsText() { + String dump = dumpCircuit(); + dialogShowing = new ExportAsTextDialog(this, dump); + dialogShowing.show(); } - void doExportAsImage() - { - dialogShowing = new ExportAsImageDialog(CAC_IMAGE); - dialogShowing.show(); + void doExportAsImage() { + dialogShowing = new ExportAsImageDialog(CAC_IMAGE); + dialogShowing.show(); } - - void doCreateSubcircuit() - { - EditCompositeModelDialog dlg = new EditCompositeModelDialog(); - if (!dlg.createModel()) - return; - dlg.createDialog(); - dialogShowing = dlg; - dialogShowing.show(); + + void doCreateSubcircuit() { + EditCompositeModelDialog dlg = new EditCompositeModelDialog(); + if (!dlg.createModel()) + return; + dlg.createDialog(); + dialogShowing = dlg; + dialogShowing.show(); } - + void doExportAsLocalFile() { - String dump = dumpCircuit(); - dialogShowing = new ExportAsLocalFileDialog(dump); - dialogShowing.show(); + String dump = dumpCircuit(); + dialogShowing = new ExportAsLocalFileDialog(dump); + dialogShowing.show(); } public void importCircuitFromText(String circuitText, boolean subcircuitsOnly) { - int flags = subcircuitsOnly ? (CirSim.RC_SUBCIRCUITS | CirSim.RC_RETAIN) : 0; - if (circuitText != null) { - readCircuit(circuitText, flags); - allowSave(false); - } + int flags = subcircuitsOnly ? (CirSim.RC_SUBCIRCUITS | CirSim.RC_RETAIN) : 0; + if (circuitText != null) { + readCircuit(circuitText, flags); + allowSave(false); + } } String dumpOptions() { @@ -3649,22 +3741,20 @@ String dumpOptions() { f |= (showValuesCheckItem.getState()) ? 0 : 16; // 32 = linear scale in afilter f |= adjustTimeStep ? 64 : 0; - String dump = "$ " + f + " " + - maxTimeStep + " " + getIterCount() + " " + - currentBar.getValue() + " " + CircuitElm.voltageRange + " " + - powerBar.getValue() + " " + minTimeStep + "\n"; + String dump = "$ " + f + " " + maxTimeStep + " " + getIterCount() + " " + currentBar.getValue() + " " + + CircuitElm.voltageRange + " " + powerBar.getValue() + " " + minTimeStep + "\n"; return dump; } - + String dumpCircuit() { int i; CustomLogicModel.clearDumpedFlags(); CustomCompositeModel.clearDumpedFlags(); DiodeModel.clearDumpedFlags(); TransistorModel.clearDumpedFlags(); - + String dump = dumpOptions(); - + for (i = 0; i != elmList.size(); i++) { CircuitElm ce = getElm(i); String m = ce.dumpModel(); @@ -3682,94 +3772,92 @@ String dumpCircuit() { dump += "38 " + adj.dump() + "\n"; } if (hintType != -1) - dump += "h " + hintType + " " + hintItem1 + " " + - hintItem2 + "\n"; + dump += "h " + hintType + " " + hintItem1 + " " + hintItem2 + "\n"; return dump; } void getSetupList(final boolean openDefault) { - String url; - url = GWT.getModuleBaseURL()+"setuplist.txt"+"?v="+random.nextInt(); - RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); - try { - requestBuilder.sendRequest(null, new RequestCallback() { - public void onError(Request request, Throwable exception) { - Window.alert(Locale.LS("Can't load circuit list!")); - GWT.log("File Error Response", exception); - } - - public void onResponseReceived(Request request, Response response) { - // processing goes here - if (response.getStatusCode()==Response.SC_OK) { - String text = response.getText(); - processSetupList(text.getBytes(), openDefault); - // end or processing - } - else { - Window.alert(Locale.LS("Can't load circuit list!")); - GWT.log("Bad file server response:"+response.getStatusText() ); - } - } - }); - } catch (RequestException e) { - GWT.log("failed file reading", e); + String url; + url = GWT.getModuleBaseURL() + "setuplist.txt" + "?v=" + random.nextInt(); + RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); + try { + requestBuilder.sendRequest(null, new RequestCallback() { + public void onError(Request request, Throwable exception) { + Window.alert(Locale.LS("Can't load circuit list!")); + GWT.log("File Error Response", exception); + } + + public void onResponseReceived(Request request, Response response) { + // processing goes here + if (response.getStatusCode() == Response.SC_OK) { + String text = response.getText(); + processSetupList(text.getBytes(), openDefault); + // end or processing + } else { + Window.alert(Locale.LS("Can't load circuit list!")); + GWT.log("Bad file server response:" + response.getStatusText()); + } } + }); + } catch (RequestException e) { + GWT.log("failed file reading", e); + } } - + void processSetupList(byte b[], final boolean openDefault) { int len = b.length; - MenuBar currentMenuBar; - MenuBar stack[] = new MenuBar[6]; - int stackptr = 0; - currentMenuBar=new MenuBar(true); - currentMenuBar.setAutoOpen(true); - menuBar.addItem(Locale.LS("Circuits"), currentMenuBar); - stack[stackptr++] = currentMenuBar; - int p; - for (p = 0; p < len; ) { - int l; - for (l = 0; l != len-p; l++) - if (b[l+p] == '\n' || b[l+p] == '\r') { - l++; - break; - } - String line = new String(b, p, l-1); - if (line.charAt(0) == '#') - ; - else if (line.charAt(0) == '+') { - // MenuBar n = new Menu(line.substring(1)); - MenuBar n = new MenuBar(true); - n.setAutoOpen(true); - currentMenuBar.addItem(Locale.LS(line.substring(1)),n); - currentMenuBar = stack[stackptr++] = n; - } else if (line.charAt(0) == '-') { - currentMenuBar = stack[--stackptr-1]; - } else { - int i = line.indexOf(' '); - if (i > 0) { - String title = Locale.LS(line.substring(i+1)); - boolean first = false; - if (line.charAt(0) == '>') - first = true; - String file = line.substring(first ? 1 : 0, i); - currentMenuBar.addItem(new MenuItem(title, - new MyCommand("circuits", "setup "+file+" " + title))); - if (file.equals(startCircuit) && startLabel == null) { - startLabel = title; - titleLabel.setText(title); - } - if (first && startCircuit == null) { - startCircuit = file; - startLabel = title; - if (openDefault && stopMessage == null) - readSetupFile(startCircuit, startLabel); - } - } - } - p += l; - } -} + MenuBar currentMenuBar; + MenuBar stack[] = new MenuBar[6]; + int stackptr = 0; + currentMenuBar = new MenuBar(true); + currentMenuBar.setAutoOpen(true); + menuBar.addItem(Locale.LS("Circuits"), currentMenuBar); + stack[stackptr++] = currentMenuBar; + int p; + for (p = 0; p < len;) { + int l; + for (l = 0; l != len - p; l++) + if (b[l + p] == '\n' || b[l + p] == '\r') { + l++; + break; + } + String line = new String(b, p, l - 1); + if (line.charAt(0) == '#') + ; + else if (line.charAt(0) == '+') { + // MenuBar n = new Menu(line.substring(1)); + MenuBar n = new MenuBar(true); + n.setAutoOpen(true); + currentMenuBar.addItem(Locale.LS(line.substring(1)), n); + currentMenuBar = stack[stackptr++] = n; + } else if (line.charAt(0) == '-') { + currentMenuBar = stack[--stackptr - 1]; + } else { + int i = line.indexOf(' '); + if (i > 0) { + String title = Locale.LS(line.substring(i + 1)); + boolean first = false; + if (line.charAt(0) == '>') + first = true; + String file = line.substring(first ? 1 : 0, i); + currentMenuBar + .addItem(new MenuItem(title, new MyCommand("circuits", "setup " + file + " " + title))); + if (file.equals(startCircuit) && startLabel == null) { + startLabel = title; + titleLabel.setText(title); + } + if (first && startCircuit == null) { + startCircuit = file; + startLabel = title; + if (openDefault && stopMessage == null) + readSetupFile(startCircuit, startLabel); + } + } + } + p += l; + } + } void readCircuit(String text, int flags) { readCircuit(text.getBytes(), flags); @@ -3786,46 +3874,45 @@ void setCircuitTitle(String s) { if (s != null) titleLabel.setText(s); } - - void readSetupFile(String str, String title) { - System.out.println(str); - // TODO: Maybe think about some better approach to cache management! - String url=GWT.getModuleBaseURL()+"circuits/"+str+"?v="+random.nextInt(); - loadFileFromURL(url); - if (title != null) - titleLabel.setText(title); - unsavedChanges = false; - } - - void loadFileFromURL(String url) { - RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); - - try { - requestBuilder.sendRequest(null, new RequestCallback() { - public void onError(Request request, Throwable exception) { - Window.alert(Locale.LS("Can't load circuit!")); - GWT.log("File Error Response", exception); - } - public void onResponseReceived(Request request, Response response) { - if (response.getStatusCode()==Response.SC_OK) { - String text = response.getText(); - readCircuit(text, RC_KEEP_TITLE); - allowSave(false); - unsavedChanges = false; - } - else { - Window.alert(Locale.LS("Can't load circuit!")); - GWT.log("Bad file server response:"+response.getStatusText() ); - } - } - }); - } catch (RequestException e) { - GWT.log("failed file reading", e); - } + void readSetupFile(String str, String title) { + System.out.println(str); + // TODO: Maybe think about some better approach to cache management! + String url = GWT.getModuleBaseURL() + "circuits/" + str + "?v=" + random.nextInt(); + loadFileFromURL(url); + if (title != null) + titleLabel.setText(title); + unsavedChanges = false; + } + + void loadFileFromURL(String url) { + RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); + + try { + requestBuilder.sendRequest(null, new RequestCallback() { + public void onError(Request request, Throwable exception) { + Window.alert(Locale.LS("Can't load circuit!")); + GWT.log("File Error Response", exception); + } + public void onResponseReceived(Request request, Response response) { + if (response.getStatusCode() == Response.SC_OK) { + String text = response.getText(); + readCircuit(text, RC_KEEP_TITLE); + allowSave(false); + unsavedChanges = false; + } else { + Window.alert(Locale.LS("Can't load circuit!")); + GWT.log("Bad file server response:" + response.getStatusText()); + } + } + }); + } catch (RequestException e) { + GWT.log("failed file reading", e); } + } + static final int RC_RETAIN = 1; static final int RC_NO_CENTER = 2; static final int RC_SUBCIRCUITS = 4; @@ -3859,15 +3946,15 @@ void readCircuit(byte b[], int flags) { lastIterTime = 0; } boolean subs = (flags & RC_SUBCIRCUITS) != 0; - //cv.repaint(); + // cv.repaint(); int p; - for (p = 0; p < len; ) { + for (p = 0; p < len;) { int l; - int linelen = len-p; // IES - changed to allow the last line to not end with a delim. - for (l = 0; l != len-p; l++) - if (b[l+p] == '\n' || b[l+p] == '\r') { + int linelen = len - p; // IES - changed to allow the last line to not end with a delim. + for (l = 0; l != len - p; l++) + if (b[l + p] == '\n' || b[l + p] == '\r') { linelen = l++; - if (l+p < b.length && b[l+p] == '\n') + if (l + p < b.length && b[l + p] == '\n') l++; break; } @@ -3903,11 +3990,11 @@ void readCircuit(byte b[], int flags) { break; } // do not add new symbols here without testing export as link - + // if first character is a digit then parse the type as a number if (tint >= '0' && tint <= '9') - tint = new Integer(type).intValue(); - + tint = Integer.valueOf(type).intValue(); + if (tint == 34) { DiodeModel.undumpModel(st); break; @@ -3926,24 +4013,22 @@ void readCircuit(byte b[], int flags) { CustomCompositeModel.undumpModel(st); break; } - int x1 = new Integer(st.nextToken()).intValue(); - int y1 = new Integer(st.nextToken()).intValue(); - int x2 = new Integer(st.nextToken()).intValue(); - int y2 = new Integer(st.nextToken()).intValue(); - int f = new Integer(st.nextToken()).intValue(); - + int x1 = Integer.valueOf(st.nextToken()).intValue(); + int y1 = Integer.valueOf(st.nextToken()).intValue(); + int x2 = Integer.valueOf(st.nextToken()).intValue(); + int y2 = Integer.valueOf(st.nextToken()).intValue(); + int f = Integer.valueOf(st.nextToken()).intValue(); + CircuitElm newce = createCe(tint, x1, y1, x2, y2, f, st); - if (newce==null) { + if (newce == null) { System.out.println("unrecognized dump type: " + type); break; } /* - * debug code to check if allocNodes() is called in constructor. It gets called in - * setPoints() but that doesn't get called for subcircuits. - double vv[] = newce.volts; - int vc = newce.getPostCount() + newce.getInternalNodeCount(); - if (vv.length != vc) - console("allocnodes not called! " + tint); + * debug code to check if allocNodes() is called in constructor. It gets called + * in setPoints() but that doesn't get called for subcircuits. double vv[] = + * newce.volts; int vc = newce.getPostCount() + newce.getInternalNodeCount(); if + * (vv.length != vc) console("allocnodes not called! " + tint); */ newce.setPoints(); elmList.addElement(newce); @@ -3955,7 +4040,7 @@ void readCircuit(byte b[], int flags) { break; } p += l; - + } setPowerBarEnable(); enableItems(); @@ -3966,16 +4051,16 @@ void readCircuit(byte b[], int flags) { adjustables.remove(i--); } } -// if (!retain) - // handleResize(); // for scopes + // if (!retain) + // handleResize(); // for scopes needAnalyze(); if ((flags & RC_NO_CENTER) == 0) - centreCircuit(); + centreCircuit(); if ((flags & RC_SUBCIRCUITS) != 0) updateModels(); - - AudioInputElm.clearCache(); // to save memory - DataInputElm.clearCache(); // to save memory + + AudioInputElm.clearCache(); // to save memory + DataInputElm.clearCache(); // to save memory } // delete sliders for an element @@ -3983,7 +4068,7 @@ void deleteSliders(CircuitElm elm) { int i; if (adjustables == null) return; - for (i = adjustables.size()-1; i >= 0; i--) { + for (i = adjustables.size() - 1; i >= 0; i--) { Adjustable adj = adjustables.get(i); if (adj.elm == elm) { adj.deleteSlider(this); @@ -3991,62 +4076,62 @@ void deleteSliders(CircuitElm elm) { } } } - + void readHint(StringTokenizer st) { - hintType = new Integer(st.nextToken()).intValue(); - hintItem1 = new Integer(st.nextToken()).intValue(); - hintItem2 = new Integer(st.nextToken()).intValue(); + hintType = Integer.valueOf(st.nextToken()).intValue(); + hintItem1 = Integer.valueOf(st.nextToken()).intValue(); + hintItem2 = Integer.valueOf(st.nextToken()).intValue(); } void readOptions(StringTokenizer st, int importFlags) { - int flags = new Integer(st.nextToken()).intValue(); - + int flags = Integer.valueOf(st.nextToken()).intValue(); + if ((importFlags & RC_RETAIN) != 0) { - // need to set small grid if pasted circuit uses it + // need to set small grid if pasted circuit uses it if ((flags & 2) != 0) smallGridCheckItem.setState(true); return; } - + dotsCheckItem.setState((flags & 1) != 0); smallGridCheckItem.setState((flags & 2) != 0); voltsCheckItem.setState((flags & 4) == 0); powerCheckItem.setState((flags & 8) == 8); showValuesCheckItem.setState((flags & 16) == 0); adjustTimeStep = (flags & 64) != 0; - maxTimeStep = timeStep = new Double (st.nextToken()).doubleValue(); - double sp = new Double(st.nextToken()).doubleValue(); - int sp2 = (int) (Math.log(10*sp)*24+61.5); - //int sp2 = (int) (Math.log(sp)*24+1.5); + maxTimeStep = timeStep = Double.valueOf(st.nextToken()).doubleValue(); + double sp = Double.valueOf(st.nextToken()).doubleValue(); + int sp2 = (int) (Math.log(10 * sp) * 24 + 61.5); + // int sp2 = (int) (Math.log(sp)*24+1.5); speedBar.setValue(sp2); - currentBar.setValue(new Integer(st.nextToken()).intValue()); - CircuitElm.voltageRange = new Double (st.nextToken()).doubleValue(); + currentBar.setValue(Integer.valueOf(st.nextToken()).intValue()); + CircuitElm.voltageRange = Double.valueOf(st.nextToken()).doubleValue(); try { - powerBar.setValue(new Integer(st.nextToken()).intValue()); + powerBar.setValue(Integer.valueOf(st.nextToken()).intValue()); minTimeStep = Double.parseDouble(st.nextToken()); } catch (Exception e) { } setGrid(); } - + int snapGrid(int x) { - return (x+gridRound) & gridMask; + return (x + gridRound) & gridMask; } - boolean doSwitch(int x, int y) { - if (mouseElm == null || !(mouseElm instanceof SwitchElm)) - return false; - SwitchElm se = (SwitchElm) mouseElm; - if (!se.getSwitchRect().contains(x, y)) - return false; - se.toggle(); - if (se.momentary) - heldSwitchElm = se; - if (!(se instanceof LogicInputElm)) - needAnalyze(); - return true; - } + boolean doSwitch(int x, int y) { + if (mouseElm == null || !(mouseElm instanceof SwitchElm)) + return false; + SwitchElm se = (SwitchElm) mouseElm; + if (!se.getSwitchRect().contains(x, y)) + return false; + se.toggle(); + if (se.momentary) + heldSwitchElm = se; + if (!(se instanceof LogicInputElm)) + needAnalyze(); + return true; + } int locateElm(CircuitElm elm) { int i; @@ -4055,231 +4140,228 @@ int locateElm(CircuitElm elm) { return i; return -1; } - + public void mouseDragged(MouseMoveEvent e) { - // ignore right mouse button with no modifiers (needed on PC) - if (e.getNativeButton()==NativeEvent.BUTTON_RIGHT) { - if (!(e.isMetaKeyDown() || - e.isShiftKeyDown() || - e.isControlKeyDown() || - e.isAltKeyDown())) - return; - } - - if (tempMouseMode==MODE_DRAG_SPLITTER) { - dragSplitter(e.getX(), e.getY()); - return; - } - int gx = inverseTransformX(e.getX()); - int gy = inverseTransformY(e.getY()); - if (!circuitArea.contains(e.getX(), e.getY())) - return; - boolean changed = false; - if (dragElm != null) - dragElm.drag(gx, gy); - boolean success = true; - switch (tempMouseMode) { - case MODE_DRAG_ALL: - dragAll(e.getX(), e.getY()); - break; - case MODE_DRAG_ROW: - dragRow(snapGrid(gx), snapGrid(gy)); - changed = true; - break; - case MODE_DRAG_COLUMN: - dragColumn(snapGrid(gx), snapGrid(gy)); - changed = true; - break; - case MODE_DRAG_POST: - if (mouseElm != null) { - dragPost(snapGrid(gx), snapGrid(gy), e.isShiftKeyDown()); - changed = true; - } - break; - case MODE_SELECT: - if (mouseElm == null) - selectArea(gx, gy, e.isShiftKeyDown()); - else if (!noEditCheckItem.getState()) { - // wait short delay before dragging. This is to fix problem where switches were accidentally getting - // dragged when tapped on mobile devices - if (System.currentTimeMillis()-mouseDownTime < 150) - return; - - tempMouseMode = MODE_DRAG_SELECTED; - changed = success = dragSelected(gx, gy); - } - break; - case MODE_DRAG_SELECTED: - changed = success = dragSelected(gx, gy); - break; + // ignore right mouse button with no modifiers (needed on PC) + if (e.getNativeButton() == NativeEvent.BUTTON_RIGHT) { + if (!(e.isMetaKeyDown() || e.isShiftKeyDown() || e.isControlKeyDown() || e.isAltKeyDown())) + return; + } - } - dragging = true; - if (success) { - dragScreenX = e.getX(); - dragScreenY = e.getY(); - // console("setting dragGridx in mousedragged"); - dragGridX = inverseTransformX(dragScreenX); - dragGridY = inverseTransformY(dragScreenY); - if (!(tempMouseMode == MODE_DRAG_SELECTED && onlyGraphicsElmsSelected())) { - dragGridX = snapGrid(dragGridX); - dragGridY = snapGrid(dragGridY); - } - } - if (changed) - writeRecoveryToStorage(); - repaint(); + if (tempMouseMode == MODE_DRAG_SPLITTER) { + dragSplitter(e.getX(), e.getY()); + return; + } + int gx = inverseTransformX(e.getX()); + int gy = inverseTransformY(e.getY()); + if (!circuitArea.contains(e.getX(), e.getY())) + return; + boolean changed = false; + if (dragElm != null) + dragElm.drag(gx, gy); + boolean success = true; + switch (tempMouseMode) { + case MODE_DRAG_ALL: + dragAll(e.getX(), e.getY()); + break; + case MODE_DRAG_ROW: + dragRow(snapGrid(gx), snapGrid(gy)); + changed = true; + break; + case MODE_DRAG_COLUMN: + dragColumn(snapGrid(gx), snapGrid(gy)); + changed = true; + break; + case MODE_DRAG_POST: + if (mouseElm != null) { + dragPost(snapGrid(gx), snapGrid(gy), e.isShiftKeyDown()); + changed = true; + } + break; + case MODE_SELECT: + if (mouseElm == null) + selectArea(gx, gy, e.isShiftKeyDown()); + else if (!noEditCheckItem.getState()) { + // wait short delay before dragging. This is to fix problem where switches were + // accidentally getting + // dragged when tapped on mobile devices + if (System.currentTimeMillis() - mouseDownTime < 150) + return; + + tempMouseMode = MODE_DRAG_SELECTED; + changed = success = dragSelected(gx, gy); + } + break; + case MODE_DRAG_SELECTED: + changed = success = dragSelected(gx, gy); + break; + + } + dragging = true; + if (success) { + dragScreenX = e.getX(); + dragScreenY = e.getY(); + // console("setting dragGridx in mousedragged"); + dragGridX = inverseTransformX(dragScreenX); + dragGridY = inverseTransformY(dragScreenY); + if (!(tempMouseMode == MODE_DRAG_SELECTED && onlyGraphicsElmsSelected())) { + dragGridX = snapGrid(dragGridX); + dragGridY = snapGrid(dragGridY); + } + } + if (changed) + writeRecoveryToStorage(); + repaint(); } - + void dragSplitter(int x, int y) { - double h = (double) canvasHeight; - if (h<1) - h=1; - scopeHeightFraction=1.0-(((double)y)/h); - if (scopeHeightFraction<0.1) - scopeHeightFraction=0.1; - if (scopeHeightFraction>0.9) - scopeHeightFraction=0.9; - setCircuitArea(); - repaint(); + double h = (double) canvasHeight; + if (h < 1) + h = 1; + scopeHeightFraction = 1.0 - (((double) y) / h); + if (scopeHeightFraction < 0.1) + scopeHeightFraction = 0.1; + if (scopeHeightFraction > 0.9) + scopeHeightFraction = 0.9; + setCircuitArea(); + repaint(); } void dragAll(int x, int y) { - int dx = x-dragScreenX; - int dy = y-dragScreenY; - if (dx == 0 && dy == 0) - return; - transform[4] += dx; - transform[5] += dy; - dragScreenX = x; - dragScreenY = y; + int dx = x - dragScreenX; + int dy = y - dragScreenY; + if (dx == 0 && dy == 0) + return; + transform[4] += dx; + transform[5] += dy; + dragScreenX = x; + dragScreenY = y; } void dragRow(int x, int y) { - int dy = y-dragGridY; - if (dy == 0) - return; - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (ce.y == dragGridY) - ce.movePoint(0, 0, dy); - if (ce.y2 == dragGridY) - ce.movePoint(1, 0, dy); - } - removeZeroLengthElements(); + int dy = y - dragGridY; + if (dy == 0) + return; + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce.y == dragGridY) + ce.movePoint(0, 0, dy); + if (ce.y2 == dragGridY) + ce.movePoint(1, 0, dy); + } + removeZeroLengthElements(); } void dragColumn(int x, int y) { - int dx = x-dragGridX; - if (dx == 0) - return; - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (ce.x == dragGridX) - ce.movePoint(0, dx, 0); - if (ce.x2 == dragGridX) - ce.movePoint(1, dx, 0); - } - removeZeroLengthElements(); + int dx = x - dragGridX; + if (dx == 0) + return; + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce.x == dragGridX) + ce.movePoint(0, dx, 0); + if (ce.x2 == dragGridX) + ce.movePoint(1, dx, 0); + } + removeZeroLengthElements(); } boolean onlyGraphicsElmsSelected() { - if (mouseElm!=null && !(mouseElm instanceof GraphicElm)) + if (mouseElm != null && !(mouseElm instanceof GraphicElm)) return false; - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if ( ce.isSelected() && !(ce instanceof GraphicElm) ) - return false; - } - return true; + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce.isSelected() && !(ce instanceof GraphicElm)) + return false; + } + return true; } - + boolean dragSelected(int x, int y) { - boolean me = false; - int i; - if (mouseElm != null && !mouseElm.isSelected()) - mouseElm.setSelected(me = true); - - if (! onlyGraphicsElmsSelected()) { - // console("Snapping x and y"); - x = snapGrid(x); - y = snapGrid(y); - } + boolean me = false; + int i; + if (mouseElm != null && !mouseElm.isSelected()) + mouseElm.setSelected(me = true); - int dx = x-dragGridX; - // console("dx="+dx+"dragGridx="+dragGridX); - int dy = y-dragGridY; - if (dx == 0 && dy == 0) { - // don't leave mouseElm selected if we selected it above - if (me) - mouseElm.setSelected(false); - return false; - } - boolean allowed = true; + if (!onlyGraphicsElmsSelected()) { + // console("Snapping x and y"); + x = snapGrid(x); + y = snapGrid(y); + } - // check if moves are allowed - for (i = 0; allowed && i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (ce.isSelected() && !ce.allowMove(dx, dy)) - allowed = false; - } + int dx = x - dragGridX; + // console("dx="+dx+"dragGridx="+dragGridX); + int dy = y - dragGridY; + if (dx == 0 && dy == 0) { + // don't leave mouseElm selected if we selected it above + if (me) + mouseElm.setSelected(false); + return false; + } + boolean allowed = true; - if (allowed) { - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (ce.isSelected()) - ce.move(dx, dy); - } - needAnalyze(); - } + // check if moves are allowed + for (i = 0; allowed && i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce.isSelected() && !ce.allowMove(dx, dy)) + allowed = false; + } + + if (allowed) { + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce.isSelected()) + ce.move(dx, dy); + } + needAnalyze(); + } - // don't leave mouseElm selected if we selected it above - if (me) - mouseElm.setSelected(false); + // don't leave mouseElm selected if we selected it above + if (me) + mouseElm.setSelected(false); - return allowed; + return allowed; } void dragPost(int x, int y, boolean all) { - if (draggingPost == -1) { - draggingPost = - (Graphics.distanceSq(mouseElm.x , mouseElm.y , x, y) > - Graphics.distanceSq(mouseElm.x2, mouseElm.y2, x, y)) ? 1 : 0; - } - int dx = x-dragGridX; - int dy = y-dragGridY; - if (dx == 0 && dy == 0) - return; - - if (all) { - // go through all elms - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm e = elmList.get(i); - - // which post do we move? - int p = 0; - if (e.x == dragGridX && e.y == dragGridY) - p = 0; - else if (e.x2 == dragGridX && e.y2 == dragGridY) - p = 1; - else - continue; - e.movePoint(p, dx, dy); - } - } else - mouseElm.movePoint(draggingPost, dx, dy); - needAnalyze(); + if (draggingPost == -1) { + draggingPost = (Graphics.distanceSq(mouseElm.x, mouseElm.y, x, y) > Graphics.distanceSq(mouseElm.x2, + mouseElm.y2, x, y)) ? 1 : 0; + } + int dx = x - dragGridX; + int dy = y - dragGridY; + if (dx == 0 && dy == 0) + return; + + if (all) { + // go through all elms + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm e = elmList.get(i); + + // which post do we move? + int p = 0; + if (e.x == dragGridX && e.y == dragGridY) + p = 0; + else if (e.x2 == dragGridX && e.y2 == dragGridY) + p = 1; + else + continue; + e.movePoint(p, dx, dy); + } + } else + mouseElm.movePoint(draggingPost, dx, dy); + needAnalyze(); } void doFlip() { menuElm.flipPosts(); - needAnalyze(); + needAnalyze(); } - + void doSplit(CircuitElm ce) { int x = snapGrid(inverseTransformX(menuX)); int y = snapGrid(inverseTransformY(menuY)); @@ -4289,306 +4371,300 @@ void doSplit(CircuitElm ce) { x = ce.x; else y = ce.y; - + // don't create zero-length wire if (x == ce.x && y == ce.y || x == ce.x2 && y == ce.y2) return; - + WireElm newWire = new WireElm(x, y); newWire.drag(ce.x2, ce.y2); ce.drag(x, y); elmList.addElement(newWire); needAnalyze(); } - + void selectArea(int x, int y, boolean add) { - int x1 = min(x, initDragGridX); - int x2 = max(x, initDragGridX); - int y1 = min(y, initDragGridY); - int y2 = max(y, initDragGridY); - selectedArea = new Rectangle(x1, y1, x2-x1, y2-y1); - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - ce.selectRect(selectedArea, add); - } + int x1 = min(x, initDragGridX); + int x2 = max(x, initDragGridX); + int y1 = min(y, initDragGridY); + int y2 = max(y, initDragGridY); + selectedArea = new Rectangle(x1, y1, x2 - x1, y2 - y1); + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + ce.selectRect(selectedArea, add); + } } -// void setSelectedElm(CircuitElm cs) { -// int i; -// for (i = 0; i != elmList.size(); i++) { -// CircuitElm ce = getElm(i); -// ce.setSelected(ce == cs); -// } -// mouseElm = cs; -// } - + // void setSelectedElm(CircuitElm cs) { + // int i; + // for (i = 0; i != elmList.size(); i++) { + // CircuitElm ce = getElm(i); + // ce.setSelected(ce == cs); + // } + // mouseElm = cs; + // } + void setMouseElm(CircuitElm ce) { - if (ce!=mouseElm) { - if (mouseElm!=null) - mouseElm.setMouseElm(false); - if (ce!=null) - ce.setMouseElm(true); - mouseElm=ce; - int i; - for (i = 0; i < adjustables.size(); i++) - adjustables.get(i).setMouseElm(ce); - } + if (ce != mouseElm) { + if (mouseElm != null) + mouseElm.setMouseElm(false); + if (ce != null) + ce.setMouseElm(true); + mouseElm = ce; + int i; + for (i = 0; i < adjustables.size(); i++) + adjustables.get(i).setMouseElm(ce); + } } void removeZeroLengthElements() { - int i; - boolean changed = false; - for (i = elmList.size()-1; i >= 0; i--) { - CircuitElm ce = getElm(i); - if (ce.x == ce.x2 && ce.y == ce.y2) { - elmList.removeElementAt(i); - ce.delete(); - changed = true; - } - } - needAnalyze(); + int i; + boolean changed = false; + for (i = elmList.size() - 1; i >= 0; i--) { + CircuitElm ce = getElm(i); + if (ce.x == ce.x2 && ce.y == ce.y2) { + elmList.removeElementAt(i); + ce.delete(); + changed = true; + } + } + needAnalyze(); } - + boolean mouseIsOverSplitter(int x, int y) { - boolean isOverSplitter; - if (scopeCount == 0) - return false; - isOverSplitter =((x>=0) && (x=circuitArea.height-5) && (y= 0) && (x < circuitArea.width) && (y >= circuitArea.height - 5) + && (y < circuitArea.height)); + if (isOverSplitter != mouseWasOverSplitter) { + if (isOverSplitter) + setCursorStyle("cursorSplitter"); + else + setMouseMode(mouseMode); + } + mouseWasOverSplitter = isOverSplitter; + return isOverSplitter; } public void onMouseMove(MouseMoveEvent e) { - e.preventDefault(); - mouseCursorX=e.getX(); - mouseCursorY=e.getY(); - if (mouseDragging) { - mouseDragged(e); - return; - } - mouseSelect(e); - scopeMenuSelected = -1; + e.preventDefault(); + mouseCursorX = e.getX(); + mouseCursorY = e.getY(); + if (mouseDragging) { + mouseDragged(e); + return; + } + mouseSelect(e); + scopeMenuSelected = -1; } - + // convert screen coordinates to grid coordinates by inverting circuit transform int inverseTransformX(double x) { - return (int) ((x-transform[4])/transform[0]); + return (int) ((x - transform[4]) / transform[0]); } int inverseTransformY(double y) { - return (int) ((y-transform[5])/transform[3]); + return (int) ((y - transform[5]) / transform[3]); } - + // convert grid coordinates to screen coordinates int transformX(double x) { - return (int) ((x*transform[0]) + transform[4]); + return (int) ((x * transform[0]) + transform[4]); } - + int transformY(double y) { - return (int) ((y*transform[3]) + transform[5]); + return (int) ((y * transform[3]) + transform[5]); } - - // need to break this out into a separate routine to handle selection, // since we don't get mouse move events on mobile public void mouseSelect(MouseEvent e) { - // The following is in the original, but seems not to work/be needed for GWT - // if (e.getNativeButton()==NativeEvent.BUTTON_LEFT) - // return; - CircuitElm newMouseElm=null; - mouseCursorX=e.getX(); - mouseCursorY=e.getY(); - int sx = e.getX(); - int sy = e.getY(); - int gx = inverseTransformX(sx); - int gy = inverseTransformY(sy); - // console("Settingd draggridx in mouseEvent"); - dragGridX = snapGrid(gx); - dragGridY = snapGrid(gy); - dragScreenX = sx; - dragScreenY = sy; - draggingPost = -1; - int i; - // CircuitElm origMouse = mouseElm; - - mousePost = -1; - plotXElm = plotYElm = null; - - if (mouseIsOverSplitter(sx, sy)) { - setMouseElm(null); - return; - } - - if (circuitArea.contains(sx, sy)) { - if (mouseElm!=null && ( mouseElm.getHandleGrabbedClose(gx, gy, POSTGRABSQ, MINPOSTGRABSIZE)>=0)) { - newMouseElm=mouseElm; - } else { - int bestDist = 100000000; - int bestArea = 100000000; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (ce.boundingBox.contains(gx, gy)) { - int j; - int area = ce.boundingBox.width * ce.boundingBox.height; - int jn = ce.getPostCount(); - if (jn > 2) - jn = 2; - for (j = 0; j != jn; j++) { - Point pt = ce.getPost(j); - int dist = Graphics.distanceSq(gx, gy, pt.x, pt.y); - - // if multiple elements have overlapping bounding boxes, - // we prefer selecting elements that have posts close - // to the mouse pointer and that have a small bounding - // box area. - if (dist <= bestDist && area <= bestArea) { - bestDist = dist; - bestArea = area; - newMouseElm = ce; - } - } - // prefer selecting elements that have small bounding box area (for - // elements with no posts) - if (ce.getPostCount() == 0 && area <= bestArea) { - newMouseElm = ce; - bestArea = area; - } - } - } // for - } - } - scopeSelected = -1; - if (newMouseElm == null) { - for (i = 0; i != scopeCount; i++) { - Scope s = scopes[i]; - if (s.rect.contains(sx, sy)) { - newMouseElm=s.getElm(); - if (s.plotXY) { - plotXElm = s.getXElm(); - plotYElm = s.getYElm(); - } - scopeSelected = i; - } - } - // // the mouse pointer was not in any of the bounding boxes, but we - // // might still be close to a post - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (mouseMode==MODE_DRAG_POST ) { - if (ce.getHandleGrabbedClose(gx, gy, POSTGRABSQ, 0)> 0) - { - newMouseElm = ce; - break; - } - } - int j; - int jn = ce.getPostCount(); - for (j = 0; j != jn; j++) { - Point pt = ce.getPost(j); - // int dist = Graphics.distanceSq(x, y, pt.x, pt.y); - if (Graphics.distanceSq(pt.x, pt.y, gx, gy) < 26) { - newMouseElm = ce; - mousePost = j; - break; - } - } - } - } else { - mousePost = -1; - // look for post close to the mouse pointer - for (i = 0; i != newMouseElm.getPostCount(); i++) { - Point pt = newMouseElm.getPost(i); - if (Graphics.distanceSq(pt.x, pt.y, gx, gy) < 26) - mousePost = i; - } - } - repaint(); - setMouseElm(newMouseElm); - } + // The following is in the original, but seems not to work/be needed for GWT + // if (e.getNativeButton()==NativeEvent.BUTTON_LEFT) + // return; + CircuitElm newMouseElm = null; + mouseCursorX = e.getX(); + mouseCursorY = e.getY(); + int sx = e.getX(); + int sy = e.getY(); + int gx = inverseTransformX(sx); + int gy = inverseTransformY(sy); + // console("Settingd draggridx in mouseEvent"); + dragGridX = snapGrid(gx); + dragGridY = snapGrid(gy); + dragScreenX = sx; + dragScreenY = sy; + draggingPost = -1; + int i; + // CircuitElm origMouse = mouseElm; + mousePost = -1; + plotXElm = plotYElm = null; + if (mouseIsOverSplitter(sx, sy)) { + setMouseElm(null); + return; + } + + if (circuitArea.contains(sx, sy)) { + if (mouseElm != null && (mouseElm.getHandleGrabbedClose(gx, gy, POSTGRABSQ, MINPOSTGRABSIZE) >= 0)) { + newMouseElm = mouseElm; + } else { + int bestDist = 100000000; + int bestArea = 100000000; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce.boundingBox.contains(gx, gy)) { + int j; + int area = ce.boundingBox.width * ce.boundingBox.height; + int jn = ce.getPostCount(); + if (jn > 2) + jn = 2; + for (j = 0; j != jn; j++) { + Point pt = ce.getPost(j); + int dist = Graphics.distanceSq(gx, gy, pt.x, pt.y); + + // if multiple elements have overlapping bounding boxes, + // we prefer selecting elements that have posts close + // to the mouse pointer and that have a small bounding + // box area. + if (dist <= bestDist && area <= bestArea) { + bestDist = dist; + bestArea = area; + newMouseElm = ce; + } + } + // prefer selecting elements that have small bounding box area (for + // elements with no posts) + if (ce.getPostCount() == 0 && area <= bestArea) { + newMouseElm = ce; + bestArea = area; + } + } + } // for + } + } + scopeSelected = -1; + if (newMouseElm == null) { + for (i = 0; i != scopeCount; i++) { + Scope s = scopes[i]; + if (s.rect.contains(sx, sy)) { + newMouseElm = s.getElm(); + if (s.plotXY) { + plotXElm = s.getXElm(); + plotYElm = s.getYElm(); + } + scopeSelected = i; + } + } + // // the mouse pointer was not in any of the bounding boxes, but we + // // might still be close to a post + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (mouseMode == MODE_DRAG_POST) { + if (ce.getHandleGrabbedClose(gx, gy, POSTGRABSQ, 0) > 0) { + newMouseElm = ce; + break; + } + } + int j; + int jn = ce.getPostCount(); + for (j = 0; j != jn; j++) { + Point pt = ce.getPost(j); + // int dist = Graphics.distanceSq(x, y, pt.x, pt.y); + if (Graphics.distanceSq(pt.x, pt.y, gx, gy) < 26) { + newMouseElm = ce; + mousePost = j; + break; + } + } + } + } else { + mousePost = -1; + // look for post close to the mouse pointer + for (i = 0; i != newMouseElm.getPostCount(); i++) { + Point pt = newMouseElm.getPost(i); + if (Graphics.distanceSq(pt.x, pt.y, gx, gy) < 26) + mousePost = i; + } + } + repaint(); + setMouseElm(newMouseElm); + } public void onContextMenu(ContextMenuEvent e) { - e.preventDefault(); - if (!dialogIsShowing()) { - menuClientX = e.getNativeEvent().getClientX(); - menuClientY = e.getNativeEvent().getClientY(); - doPopupMenu(); - } + e.preventDefault(); + if (!dialogIsShowing()) { + menuClientX = e.getNativeEvent().getClientX(); + menuClientY = e.getNativeEvent().getClientY(); + doPopupMenu(); + } } - + @SuppressWarnings("deprecation") void doPopupMenu() { if (noEditCheckItem.getState() || dialogIsShowing()) return; - menuElm = mouseElm; - menuScope=-1; - menuPlot=-1; - int x, y; - if (scopeSelected!=-1) { - if (scopes[scopeSelected].canMenu()) { - menuScope=scopeSelected; - menuPlot=scopes[scopeSelected].selectedPlot; - scopePopupMenu.doScopePopupChecks(false, canStackScope(scopeSelected), canCombineScope(scopeSelected), - canUnstackScope(scopeSelected), scopes[scopeSelected]); - contextPanel=new PopupPanel(true); - contextPanel.add(scopePopupMenu.getMenuBar()); - y=Math.max(0, Math.min(menuClientY,canvasHeight-160)); - contextPanel.setPopupPosition(menuClientX, y); - contextPanel.show(); - } - } else if (mouseElm != null) { - if (! (mouseElm instanceof ScopeElm)) { - elmScopeMenuItem.setEnabled(mouseElm.canViewInScope()); - elmFloatScopeMenuItem.setEnabled(mouseElm.canViewInScope()); - if ((scopeCount + countScopeElms()) <= 1) { - elmAddScopeMenuItem.setCommand(new MyCommand("elm", "addToScope0")); - elmAddScopeMenuItem.setSubMenu(null); - elmAddScopeMenuItem.setEnabled(mouseElm.canViewInScope() && (scopeCount + countScopeElms())> 0); - } - else { - composeSelectScopeMenu(selectScopeMenuBar); - elmAddScopeMenuItem.setCommand(null); - elmAddScopeMenuItem.setSubMenu(selectScopeMenuBar); - elmAddScopeMenuItem.setEnabled(mouseElm.canViewInScope() ); - } - elmEditMenuItem .setEnabled(mouseElm.getEditInfo(0) != null); - elmFlipMenuItem .setEnabled(mouseElm.getPostCount() == 2); - elmSplitMenuItem.setEnabled(canSplit(mouseElm)); - elmSliderMenuItem.setEnabled(sliderItemEnabled(mouseElm)); - contextPanel=new PopupPanel(true); - contextPanel.add(elmMenuBar); - contextPanel.setPopupPosition(menuClientX, menuClientY); - contextPanel.show(); - } else { - ScopeElm s = (ScopeElm) mouseElm; - if (s.elmScope.canMenu()) { - menuPlot = s.elmScope.selectedPlot; - scopePopupMenu.doScopePopupChecks(true, false, false, false, s.elmScope); - contextPanel=new PopupPanel(true); - contextPanel.add(scopePopupMenu.getMenuBar()); - contextPanel.setPopupPosition(menuClientX, menuClientY); - contextPanel.show(); - } - } - } else { - doMainMenuChecks(); - contextPanel=new PopupPanel(true); - contextPanel.add(mainMenuBar); - x=Math.max(0, Math.min(menuClientX, canvasWidth-400)); - y=Math.max(0, Math.min(menuClientY, canvasHeight-450)); - contextPanel.setPopupPosition(x,y); - contextPanel.show(); - } + menuElm = mouseElm; + menuScope = -1; + menuPlot = -1; + int x, y; + if (scopeSelected != -1) { + if (scopes[scopeSelected].canMenu()) { + menuScope = scopeSelected; + menuPlot = scopes[scopeSelected].selectedPlot; + scopePopupMenu.doScopePopupChecks(false, canStackScope(scopeSelected), canCombineScope(scopeSelected), + canUnstackScope(scopeSelected), scopes[scopeSelected]); + contextPanel = new PopupPanel(true); + contextPanel.add(scopePopupMenu.getMenuBar()); + y = Math.max(0, Math.min(menuClientY, canvasHeight - 160)); + contextPanel.setPopupPosition(menuClientX, y); + contextPanel.show(); + } + } else if (mouseElm != null) { + if (!(mouseElm instanceof ScopeElm)) { + elmScopeMenuItem.setEnabled(mouseElm.canViewInScope()); + elmFloatScopeMenuItem.setEnabled(mouseElm.canViewInScope()); + if ((scopeCount + countScopeElms()) <= 1) { + elmAddScopeMenuItem.setCommand(new MyCommand("elm", "addToScope0")); + elmAddScopeMenuItem.setSubMenu(null); + elmAddScopeMenuItem.setEnabled(mouseElm.canViewInScope() && (scopeCount + countScopeElms()) > 0); + } else { + composeSelectScopeMenu(selectScopeMenuBar); + elmAddScopeMenuItem.setCommand(null); + elmAddScopeMenuItem.setSubMenu(selectScopeMenuBar); + elmAddScopeMenuItem.setEnabled(mouseElm.canViewInScope()); + } + elmEditMenuItem.setEnabled(mouseElm.getEditInfo(0) != null); + elmFlipMenuItem.setEnabled(mouseElm.getPostCount() == 2); + elmSplitMenuItem.setEnabled(canSplit(mouseElm)); + elmSliderMenuItem.setEnabled(sliderItemEnabled(mouseElm)); + contextPanel = new PopupPanel(true); + contextPanel.add(elmMenuBar); + contextPanel.setPopupPosition(menuClientX, menuClientY); + contextPanel.show(); + } else { + ScopeElm s = (ScopeElm) mouseElm; + if (s.elmScope.canMenu()) { + menuPlot = s.elmScope.selectedPlot; + scopePopupMenu.doScopePopupChecks(true, false, false, false, s.elmScope); + contextPanel = new PopupPanel(true); + contextPanel.add(scopePopupMenu.getMenuBar()); + contextPanel.setPopupPosition(menuClientX, menuClientY); + contextPanel.show(); + } + } + } else { + doMainMenuChecks(); + contextPanel = new PopupPanel(true); + contextPanel.add(mainMenuBar); + x = Math.max(0, Math.min(menuClientX, canvasWidth - 400)); + y = Math.max(0, Math.min(menuClientY, canvasHeight - 450)); + contextPanel.setPopupPosition(x, y); + contextPanel.show(); + } } boolean canSplit(CircuitElm ce) { @@ -4599,16 +4675,16 @@ boolean canSplit(CircuitElm ce) { return true; return false; } - + // check if the user can create sliders for this element boolean sliderItemEnabled(CircuitElm elm) { int i; - + // prevent confusion if (elm instanceof VarRailElm || elm instanceof PotElm) return false; - - for (i = 0; ; i++) { + + for (i = 0;; i++) { EditInfo ei = elm.getEditInfo(i); if (ei == null) return false; @@ -4620,81 +4696,82 @@ boolean sliderItemEnabled(CircuitElm elm) { void longPress() { doPopupMenu(); } - + void twoFingerTouch(int x, int y) { tempMouseMode = MODE_DRAG_ALL; dragScreenX = x; dragScreenY = y; } - -// public void mouseClicked(MouseEvent e) { + + // public void mouseClicked(MouseEvent e) { public void onClick(ClickEvent e) { - e.preventDefault(); -// //IES - remove inteaction -//// if ( e.getClickCount() == 2 && !didSwitch ) -//// doEditMenu(e); -// if (e.getNativeButton() == NativeEvent.BUTTON_LEFT) { -// if (mouseMode == MODE_SELECT || mouseMode == MODE_DRAG_SELECTED) -// clearSelection(); -// } - if ((e.getNativeButton() == NativeEvent.BUTTON_MIDDLE)) - scrollValues(e.getNativeEvent().getClientX(), e.getNativeEvent().getClientY(), 0); + e.preventDefault(); + // //IES - remove inteaction + //// if ( e.getClickCount() == 2 && !didSwitch ) + //// doEditMenu(e); + // if (e.getNativeButton() == NativeEvent.BUTTON_LEFT) { + // if (mouseMode == MODE_SELECT || mouseMode == MODE_DRAG_SELECTED) + // clearSelection(); + // } + if ((e.getNativeButton() == NativeEvent.BUTTON_MIDDLE)) + scrollValues(e.getNativeEvent().getClientX(), e.getNativeEvent().getClientY(), 0); } - - public void onDoubleClick(DoubleClickEvent e){ - e.preventDefault(); - // if (!didSwitch && mouseElm != null) - if (mouseElm != null && !(mouseElm instanceof SwitchElm) && !noEditCheckItem.getState()) - doEdit(mouseElm); + + public void onDoubleClick(DoubleClickEvent e) { + e.preventDefault(); + // if (!didSwitch && mouseElm != null) + if (mouseElm != null && !(mouseElm instanceof SwitchElm) && !noEditCheckItem.getState()) + doEdit(mouseElm); } - -// public void mouseEntered(MouseEvent e) { -// } - + + // public void mouseEntered(MouseEvent e) { + // } + public void onMouseOut(MouseOutEvent e) { - mouseCursorX=-1; + mouseCursorX = -1; } void clearMouseElm() { - scopeSelected = -1; - setMouseElm(null); - plotXElm = plotYElm = null; + scopeSelected = -1; + setMouseElm(null); + plotXElm = plotYElm = null; } - + int menuClientX, menuClientY; int menuX, menuY; - + public void onMouseDown(MouseDownEvent e) { -// public void mousePressed(MouseEvent e) { - e.preventDefault(); - - // make sure canvas has focus, not stop button or something else, so all shortcuts work - cv.setFocus(true); - - stopElm = null; // if stopped, allow user to select other elements to fix circuit - menuX = menuClientX = e.getX(); - menuY = menuClientY = e.getY(); - mouseDownTime = System.currentTimeMillis(); - - // maybe someone did copy in another window? should really do this when - // window receives focus - enablePaste(); - - if (e.getNativeButton() != NativeEvent.BUTTON_LEFT && e.getNativeButton() != NativeEvent.BUTTON_MIDDLE) - return; - - // set mouseElm in case we are on mobile - mouseSelect(e); - - mouseDragging=true; - didSwitch = false; - - if (mouseWasOverSplitter) { - tempMouseMode = MODE_DRAG_SPLITTER; - return; - } + // public void mousePressed(MouseEvent e) { + e.preventDefault(); + + // make sure canvas has focus, not stop button or something else, so all + // shortcuts work + cv.setFocus(true); + + stopElm = null; // if stopped, allow user to select other elements to fix circuit + menuX = menuClientX = e.getX(); + menuY = menuClientY = e.getY(); + mouseDownTime = System.currentTimeMillis(); + + // maybe someone did copy in another window? should really do this when + // window receives focus + enablePaste(); + + if (e.getNativeButton() != NativeEvent.BUTTON_LEFT && e.getNativeButton() != NativeEvent.BUTTON_MIDDLE) + return; + + // set mouseElm in case we are on mobile + mouseSelect(e); + + mouseDragging = true; + didSwitch = false; + + if (mouseWasOverSplitter) { + tempMouseMode = MODE_DRAG_SPLITTER; + return; + } if (e.getNativeButton() == NativeEvent.BUTTON_LEFT) { -// // left mouse + // // left mouse tempMouseMode = mouseMode; if (e.isAltKeyDown() && e.isMetaKeyDown()) tempMouseMode = MODE_DRAG_COLUMN; @@ -4708,41 +4785,42 @@ else if (e.isControlKeyDown() || e.isMetaKeyDown()) tempMouseMode = MODE_DRAG_POST; } else tempMouseMode = MODE_DRAG_ALL; - if (noEditCheckItem.getState()) tempMouseMode = MODE_SELECT; - - if (!(dialogIsShowing()) && ((scopeSelected != -1 && scopes[scopeSelected].cursorInSettingsWheel()) || - ( scopeSelected == -1 && mouseElm instanceof ScopeElm && ((ScopeElm)mouseElm).elmScope.cursorInSettingsWheel()))){ + + if (!(dialogIsShowing()) + && ((scopeSelected != -1 && scopes[scopeSelected].cursorInSettingsWheel()) || (scopeSelected == -1 + && mouseElm instanceof ScopeElm && ((ScopeElm) mouseElm).elmScope.cursorInSettingsWheel()))) { if (noEditCheckItem.getState()) return; Scope s; if (scopeSelected != -1) - s=scopes[scopeSelected]; - else - s=((ScopeElm)mouseElm).elmScope; + s = scopes[scopeSelected]; + else + s = ((ScopeElm) mouseElm).elmScope; s.properties(); clearSelection(); - mouseDragging=false; + mouseDragging = false; return; } int gx = inverseTransformX(e.getX()); int gy = inverseTransformY(e.getY()); if (doSwitch(gx, gy)) { - // do this BEFORE we change the mouse mode to MODE_DRAG_POST! Or else logic inputs + // do this BEFORE we change the mouse mode to MODE_DRAG_POST! Or else logic + // inputs // will add dots to the whole circuit when we click on them! - didSwitch = true; + didSwitch = true; return; } - - // IES - Grab resize handles in select mode if they are far enough apart and you are on top of them - if (tempMouseMode == MODE_SELECT && mouseElm!=null && !noEditCheckItem.getState() && - mouseElm.getHandleGrabbedClose(gx, gy, POSTGRABSQ, MINPOSTGRABSIZE) >=0 && - !anySelectedButMouse()) + + // IES - Grab resize handles in select mode if they are far enough apart and you + // are on top of them + if (tempMouseMode == MODE_SELECT && mouseElm != null && !noEditCheckItem.getState() + && mouseElm.getHandleGrabbedClose(gx, gy, POSTGRABSQ, MINPOSTGRABSIZE) >= 0 && !anySelectedButMouse()) tempMouseMode = MODE_DRAG_POST; - + if (tempMouseMode != MODE_SELECT && tempMouseMode != MODE_DRAG_SELECTED) clearSelection(); @@ -4750,9 +4828,9 @@ else if (e.isControlKeyDown() || e.isMetaKeyDown()) initDragGridX = gx; initDragGridY = gy; dragging = true; - if (tempMouseMode !=MODE_ADD_ELM) - return; -// + if (tempMouseMode != MODE_ADD_ELM) + return; + // int x0 = snapGrid(gx); int y0 = snapGrid(gy); if (!circuitArea.contains(e.getX(), e.getY())) @@ -4766,183 +4844,185 @@ else if (e.isControlKeyDown() || e.isMetaKeyDown()) } static int lastSubcircuitMenuUpdate; - - // check/uncheck/enable/disable menu items as appropriate when menu bar clicked on, or when - // right mouse menu accessed. also displays shortcuts as a side effect + + // check/uncheck/enable/disable menu items as appropriate when menu bar clicked + // on, or when + // right mouse menu accessed. also displays shortcuts as a side effect void doMainMenuChecks() { - int c = mainMenuItems.size(); - int i; - for (i=0; i 3 && s.substring(s.length()-3)=="Elm") - //mainMenuItems.get(i).setEnabled(!noEditCheckItem.getState()); - } - stackAllItem.setEnabled(scopeCount > 1 && scopes[scopeCount-1].position > 0); - unstackAllItem.setEnabled(scopeCount > 1 && scopes[scopeCount-1].position != scopeCount -1); - combineAllItem.setEnabled(scopeCount > 1); - separateAllItem.setEnabled(scopeCount > 0); - - // also update the subcircuit menu if necessary - if (lastSubcircuitMenuUpdate != CustomCompositeModel.sequenceNumber) - composeSubcircuitMenu(); + int c = mainMenuItems.size(); + int i; + for (i = 0; i < c; i++) { + String s = mainMenuItemNames.get(i); + mainMenuItems.get(i).setState(s == mouseModeStr); + + // Code to disable draw menu items when cct is not editable, but no used in this + // version as it + // puts up a dialog box instead (see menuPerformed). + // if (s.length() > 3 && s.substring(s.length()-3)=="Elm") + // mainMenuItems.get(i).setEnabled(!noEditCheckItem.getState()); + } + stackAllItem.setEnabled(scopeCount > 1 && scopes[scopeCount - 1].position > 0); + unstackAllItem.setEnabled(scopeCount > 1 && scopes[scopeCount - 1].position != scopeCount - 1); + combineAllItem.setEnabled(scopeCount > 1); + separateAllItem.setEnabled(scopeCount > 0); + + // also update the subcircuit menu if necessary + if (lastSubcircuitMenuUpdate != CustomCompositeModel.sequenceNumber) + composeSubcircuitMenu(); } - - + public void onMouseUp(MouseUpEvent e) { - e.preventDefault(); - mouseDragging=false; - - // click to clear selection - if (tempMouseMode == MODE_SELECT && selectedArea == null) - clearSelection(); - - // cmd-click = split wire - if (tempMouseMode == MODE_DRAG_POST && draggingPost == -1) - doSplit(mouseElm); - - tempMouseMode = mouseMode; - selectedArea = null; - dragging = false; - boolean circuitChanged = false; - if (heldSwitchElm != null) { - heldSwitchElm.mouseUp(); - heldSwitchElm = null; - circuitChanged = true; - } - if (dragElm != null) { - // if the element is zero size then don't create it - // IES - and disable any previous selection - if (dragElm.creationFailed()) { - dragElm.delete(); - if (mouseMode == MODE_SELECT || mouseMode == MODE_DRAG_SELECTED) - clearSelection(); - } - else { - elmList.addElement(dragElm); - dragElm.draggingDone(); - circuitChanged = true; - writeRecoveryToStorage(); - unsavedChanges = true; - } - dragElm = null; - } - if (circuitChanged) { - needAnalyze(); - pushUndo(); - } - if (dragElm != null) - dragElm.delete(); - dragElm = null; - repaint(); + e.preventDefault(); + mouseDragging = false; + + // click to clear selection + if (tempMouseMode == MODE_SELECT && selectedArea == null) + clearSelection(); + + // cmd-click = split wire + if (tempMouseMode == MODE_DRAG_POST && draggingPost == -1) + doSplit(mouseElm); + + tempMouseMode = mouseMode; + selectedArea = null; + dragging = false; + boolean circuitChanged = false; + if (heldSwitchElm != null) { + heldSwitchElm.mouseUp(); + heldSwitchElm = null; + circuitChanged = true; + } + if (dragElm != null) { + // if the element is zero size then don't create it + // IES - and disable any previous selection + if (dragElm.creationFailed()) { + dragElm.delete(); + if (mouseMode == MODE_SELECT || mouseMode == MODE_DRAG_SELECTED) + clearSelection(); + } else { + elmList.addElement(dragElm); + dragElm.draggingDone(); + circuitChanged = true; + writeRecoveryToStorage(); + unsavedChanges = true; + } + dragElm = null; + } + if (circuitChanged) { + needAnalyze(); + pushUndo(); + } + if (dragElm != null) + dragElm.delete(); + dragElm = null; + repaint(); } - + public void onMouseWheel(MouseWheelEvent e) { - e.preventDefault(); - - // once we start zooming, don't allow other uses of mouse wheel for a while - // so we don't accidentally edit a resistor value while zooming - boolean zoomOnly = System.currentTimeMillis() < zoomTime+1000; - - if (noEditCheckItem.getState() || !mouseWheelEditCheckItem.getState()) - zoomOnly = true; - - if (!zoomOnly) - scrollValues(e.getNativeEvent().getClientX(), e.getNativeEvent().getClientY(), e.getDeltaY()); - - if (mouseElm instanceof MouseWheelHandler && !zoomOnly) - ((MouseWheelHandler) mouseElm).onMouseWheel(e); - else if (scopeSelected != -1 && !zoomOnly) - scopes[scopeSelected].onMouseWheel(e); - else if (!dialogIsShowing()) { - mouseCursorX=e.getX(); - mouseCursorY=e.getY(); - zoomCircuit(-e.getDeltaY(), false); - zoomTime = System.currentTimeMillis(); - } - repaint(); - } - - void zoomCircuit(double dy) { zoomCircuit(dy, false); } + e.preventDefault(); + + // once we start zooming, don't allow other uses of mouse wheel for a while + // so we don't accidentally edit a resistor value while zooming + boolean zoomOnly = System.currentTimeMillis() < zoomTime + 1000; + + if (noEditCheckItem.getState() || !mouseWheelEditCheckItem.getState()) + zoomOnly = true; + + if (!zoomOnly) + scrollValues(e.getNativeEvent().getClientX(), e.getNativeEvent().getClientY(), e.getDeltaY()); + + if (mouseElm instanceof MouseWheelHandler && !zoomOnly) + ((MouseWheelHandler) mouseElm).onMouseWheel(e); + else if (scopeSelected != -1 && !zoomOnly) + scopes[scopeSelected].onMouseWheel(e); + else if (!dialogIsShowing()) { + mouseCursorX = e.getX(); + mouseCursorY = e.getY(); + zoomCircuit(-e.getDeltaY(), false); + zoomTime = System.currentTimeMillis(); + } + repaint(); + } + + void zoomCircuit(double dy) { + zoomCircuit(dy, false); + } void zoomCircuit(double dy, boolean menu) { double newScale; - double oldScale = transform[0]; - double val = dy*.01; - newScale = Math.max(oldScale+val, .2); - newScale = Math.min(newScale, 2.5); - setCircuitScale(newScale, menu); + double oldScale = transform[0]; + double val = dy * .01; + newScale = Math.max(oldScale + val, .2); + newScale = Math.min(newScale, 2.5); + setCircuitScale(newScale, menu); } - + void setCircuitScale(double newScale, boolean menu) { - int constX = !menu ? mouseCursorX : circuitArea.width/2; - int constY = !menu ? mouseCursorY : circuitArea.height/2; + int constX = !menu ? mouseCursorX : circuitArea.width / 2; + int constY = !menu ? mouseCursorY : circuitArea.height / 2; int cx = inverseTransformX(constX); int cy = inverseTransformY(constY); transform[0] = transform[3] = newScale; // adjust translation to keep center of screen constant // inverse transform = (x-t4)/t0 - transform[4] = constX - cx*newScale; - transform[5] = constY - cy*newScale; + transform[4] = constX - cx * newScale; + transform[5] = constY - cy * newScale; } - + void setPowerBarEnable() { - if (powerCheckItem.getState()) { - powerLabel.setStyleName("disabled", false); - powerBar.enable(); - } else { - powerLabel.setStyleName("disabled", true); - powerBar.disable(); - } + if (powerCheckItem.getState()) { + powerLabel.setStyleName("disabled", false); + powerBar.enable(); + } else { + powerLabel.setStyleName("disabled", true); + powerBar.disable(); + } } void scrollValues(int x, int y, int deltay) { - if (mouseElm!=null && !dialogIsShowing() && scopeSelected == -1) - if (mouseElm instanceof ResistorElm || mouseElm instanceof CapacitorElm || mouseElm instanceof InductorElm) { - scrollValuePopup = new ScrollValuePopup(x, y, deltay, mouseElm, this); - } + if (mouseElm != null && !dialogIsShowing() && scopeSelected == -1) + if (mouseElm instanceof ResistorElm || mouseElm instanceof CapacitorElm + || mouseElm instanceof InductorElm) { + scrollValuePopup = new ScrollValuePopup(x, y, deltay, mouseElm, this); + } } - + void enableItems() { } - + void setGrid() { gridSize = (smallGridCheckItem.getState()) ? 8 : 16; - gridMask = ~(gridSize-1); - gridRound = gridSize/2-1; + gridMask = ~(gridSize - 1); + gridRound = gridSize / 2 - 1; } void pushUndo() { - redoStack.removeAllElements(); - String s = dumpCircuit(); - if (undoStack.size() > 0 && - s.compareTo(undoStack.lastElement().dump) == 0) - return; - undoStack.add(new UndoItem(s)); - enableUndoRedo(); - savedFlag = false; + redoStack.removeAllElements(); + String s = dumpCircuit(); + if (undoStack.size() > 0 && s.compareTo(undoStack.lastElement().dump) == 0) + return; + undoStack.add(new UndoItem(s)); + enableUndoRedo(); + savedFlag = false; } void doUndo() { - if (undoStack.size() == 0) - return; - redoStack.add(new UndoItem(dumpCircuit())); - UndoItem ui = undoStack.remove(undoStack.size()-1); - loadUndoItem(ui); - enableUndoRedo(); + if (undoStack.size() == 0) + return; + redoStack.add(new UndoItem(dumpCircuit())); + UndoItem ui = undoStack.remove(undoStack.size() - 1); + loadUndoItem(ui); + enableUndoRedo(); } void doRedo() { - if (redoStack.size() == 0) - return; - undoStack.add(new UndoItem(dumpCircuit())); - UndoItem ui = redoStack.remove(redoStack.size()-1); - loadUndoItem(ui); - enableUndoRedo(); + if (redoStack.size() == 0) + return; + undoStack.add(new UndoItem(dumpCircuit())); + UndoItem ui = redoStack.remove(redoStack.size() - 1); + loadUndoItem(ui); + enableUndoRedo(); } void loadUndoItem(UndoItem ui) { @@ -4951,153 +5031,151 @@ void loadUndoItem(UndoItem ui) { transform[4] = ui.transform4; transform[5] = ui.transform5; } - + void doRecover() { pushUndo(); readCircuit(recovery); allowSave(false); recoverItem.setEnabled(false); } - + void enableUndoRedo() { - redoItem.setEnabled(redoStack.size() > 0); - undoItem.setEnabled(undoStack.size() > 0); + redoItem.setEnabled(redoStack.size() > 0); + undoItem.setEnabled(undoStack.size() > 0); } - void setMouseMode(int mode) - { - mouseMode = mode; - if ( mode == MODE_ADD_ELM ) { - setCursorStyle("cursorCross"); - } else { - setCursorStyle("cursorPointer"); - } + void setMouseMode(int mode) { + mouseMode = mode; + if (mode == MODE_ADD_ELM) { + setCursorStyle("cursorCross"); + } else { + setCursorStyle("cursorPointer"); + } } - + void setCursorStyle(String s) { - if (lastCursorStyle!=null) - cv.removeStyleName(lastCursorStyle); - cv.addStyleName(s); - lastCursorStyle=s; + if (lastCursorStyle != null) + cv.removeStyleName(lastCursorStyle); + cv.addStyleName(s); + lastCursorStyle = s; } - - void setMenuSelection() { - if (menuElm != null) { - if (menuElm.selected) - return; - clearSelection(); - menuElm.setSelected(true); - } + if (menuElm != null) { + if (menuElm.selected) + return; + clearSelection(); + menuElm.setSelected(true); + } } void doCut() { - int i; - pushUndo(); - setMenuSelection(); - clipboard = ""; - for (i = elmList.size()-1; i >= 0; i--) { - CircuitElm ce = getElm(i); - // ScopeElms don't cut-paste well because their reference to a parent - // elm by number get's messed up in the dump. For now we will just ignore them - // until I can be bothered to come up with something better - if (willDelete(ce) && !(ce instanceof ScopeElm) ) { - clipboard += ce.dump() + "\n"; - } - } - writeClipboardToStorage(); - doDelete(true); - enablePaste(); + int i; + pushUndo(); + setMenuSelection(); + clipboard = ""; + for (i = elmList.size() - 1; i >= 0; i--) { + CircuitElm ce = getElm(i); + // ScopeElms don't cut-paste well because their reference to a parent + // elm by number get's messed up in the dump. For now we will just ignore them + // until I can be bothered to come up with something better + if (willDelete(ce) && !(ce instanceof ScopeElm)) { + clipboard += ce.dump() + "\n"; + } + } + writeClipboardToStorage(); + doDelete(true); + enablePaste(); } void writeClipboardToStorage() { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - stor.setItem("circuitClipboard", clipboard); + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + stor.setItem("circuitClipboard", clipboard); } - + void readClipboardFromStorage() { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - clipboard = stor.getItem("circuitClipboard"); + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + clipboard = stor.getItem("circuitClipboard"); } void writeRecoveryToStorage() { console("write recovery"); - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - String s = dumpCircuit(); - stor.setItem("circuitRecovery", s); + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + String s = dumpCircuit(); + stor.setItem("circuitRecovery", s); } void readRecovery() { Storage stor = Storage.getLocalStorageIfSupported(); if (stor == null) - return; + return; recovery = stor.getItem("circuitRecovery"); } - void deleteUnusedScopeElms() { // Remove any scopeElms for elements that no longer exist - for (int i = elmList.size()-1; i >= 0; i--) { - CircuitElm ce = getElm(i); - if (ce instanceof ScopeElm && (((ScopeElm) ce).elmScope.needToRemove() )) { - ce.delete(); - elmList.removeElementAt(i); - - // need to rebuild scopeElmArr - needAnalyze(); - } - } - + for (int i = elmList.size() - 1; i >= 0; i--) { + CircuitElm ce = getElm(i); + if (ce instanceof ScopeElm && (((ScopeElm) ce).elmScope.needToRemove())) { + ce.delete(); + elmList.removeElementAt(i); + + // need to rebuild scopeElmArr + needAnalyze(); + } + } + } - + void doDelete(boolean pushUndoFlag) { - int i; - if (pushUndoFlag) - pushUndo(); - boolean hasDeleted = false; - - for (i = elmList.size()-1; i >= 0; i--) { - CircuitElm ce = getElm(i); - if (willDelete(ce)) { - if (ce.isMouseElm()) - setMouseElm(null); - ce.delete(); - elmList.removeElementAt(i); - hasDeleted = true; - } - } - if ( hasDeleted ) { - deleteUnusedScopeElms(); - needAnalyze(); - writeRecoveryToStorage(); - } + int i; + if (pushUndoFlag) + pushUndo(); + boolean hasDeleted = false; + + for (i = elmList.size() - 1; i >= 0; i--) { + CircuitElm ce = getElm(i); + if (willDelete(ce)) { + if (ce.isMouseElm()) + setMouseElm(null); + ce.delete(); + elmList.removeElementAt(i); + hasDeleted = true; + } + } + if (hasDeleted) { + deleteUnusedScopeElms(); + needAnalyze(); + writeRecoveryToStorage(); + } } - - boolean willDelete( CircuitElm ce ) { + + boolean willDelete(CircuitElm ce) { // Is this element in the list to be deleted. // This changes the logic from the previous version which would initially only - // delete selected elements (which could include the mouseElm) and then delete the - // mouseElm if there were no selected elements. Not really sure this added anything useful + // delete selected elements (which could include the mouseElm) and then delete + // the + // mouseElm if there were no selected elements. Not really sure this added + // anything useful // to the user experience. // // BTW, the old logic could also leave mouseElm pointing to a deleted element. return ce.isSelected() || ce.isMouseElm(); } - + String copyOfSelectedElms() { String r = dumpOptions(); CustomLogicModel.clearDumpedFlags(); CustomCompositeModel.clearDumpedFlags(); DiodeModel.clearDumpedFlags(); TransistorModel.clearDumpedFlags(); - for (int i = elmList.size()-1; i >= 0; i--) { + for (int i = elmList.size() - 1; i >= 0; i--) { CircuitElm ce = getElm(i); String m = ce.dumpModel(); if (m != null && !m.isEmpty()) @@ -5108,125 +5186,128 @@ String copyOfSelectedElms() { } return r; } - + void doCopy() { - // clear selection when we're done if we're copying a single element using the context menu - boolean clearSel = (menuElm != null && !menuElm.selected); - - setMenuSelection(); - clipboard=copyOfSelectedElms(); - - if (clearSel) - clearSelection(); - - writeClipboardToStorage(); - enablePaste(); + // clear selection when we're done if we're copying a single element using the + // context menu + boolean clearSel = (menuElm != null && !menuElm.selected); + + setMenuSelection(); + clipboard = copyOfSelectedElms(); + + if (clearSel) + clearSelection(); + + writeClipboardToStorage(); + enablePaste(); } void enablePaste() { - if (clipboard == null || clipboard.length() == 0) - readClipboardFromStorage(); - pasteItem.setEnabled(clipboard != null && clipboard.length() > 0); + if (clipboard == null || clipboard.length() == 0) + readClipboardFromStorage(); + pasteItem.setEnabled(clipboard != null && clipboard.length() > 0); } void doDuplicate() { - String s; - setMenuSelection(); - s=copyOfSelectedElms(); - doPaste(s); + String s; + setMenuSelection(); + s = copyOfSelectedElms(); + doPaste(s); } - + void doPaste(String dump) { - pushUndo(); - clearSelection(); - int i; - Rectangle oldbb = null; - - // get old bounding box - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - Rectangle bb = ce.getBoundingBox(); - if (oldbb != null) - oldbb = oldbb.union(bb); - else - oldbb = bb; - } - - // add new items - int oldsz = elmList.size(); - int flags = RC_RETAIN; - - // don't recenter circuit if we're going to paste in place because that will change the transform -// if (mouseCursorX > 0 && circuitArea.contains(mouseCursorX, mouseCursorY)) - - // in fact, don't ever recenter circuit, unless old circuit was empty - if (oldsz > 0) - flags |= RC_NO_CENTER; - - if (dump != null) - readCircuit(dump, flags); - else { - readClipboardFromStorage(); - readCircuit(clipboard, flags); - } + pushUndo(); + clearSelection(); + int i; + Rectangle oldbb = null; - // select new items and get their bounding box - Rectangle newbb = null; - for (i = oldsz; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - ce.setSelected(true); - Rectangle bb = ce.getBoundingBox(); - if (newbb != null) - newbb = newbb.union(bb); - else - newbb = bb; - } - - if (oldbb != null && newbb != null /*&& oldbb.intersects(newbb)*/) { - // find a place on the edge for new items - int dx = 0, dy = 0; - int spacew = circuitArea.width - oldbb.width - newbb.width; - int spaceh = circuitArea.height - oldbb.height - newbb.height; - - if (!oldbb.intersects(newbb)) { - // old coordinates may be really far away so move them to same origin as current circuit - dx = snapGrid(oldbb.x - newbb.x); - dy = snapGrid(oldbb.y - newbb.y); - } - - if (spacew > spaceh) { - dx = snapGrid(oldbb.x + oldbb.width - newbb.x + gridSize); - } else { - dy = snapGrid(oldbb.y + oldbb.height - newbb.y + gridSize); - } - - // move new items near the mouse if possible - if (mouseCursorX > 0 && circuitArea.contains(mouseCursorX, mouseCursorY)) { - int gx = inverseTransformX(mouseCursorX); - int gy = inverseTransformY(mouseCursorY); - int mdx = snapGrid(gx-(newbb.x+newbb.width/2)); - int mdy = snapGrid(gy-(newbb.y+newbb.height/2)); - for (i = oldsz; i != elmList.size(); i++) { - if (!getElm(i).allowMove(mdx, mdy)) - break; - } - if (i == elmList.size()) { - dx = mdx; - dy = mdy; - } - } - - // move the new items - for (i = oldsz; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - ce.move(dx, dy); - } - - // center circuit - // handleResize(); - } - needAnalyze(); - writeRecoveryToStorage(); + // get old bounding box + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + Rectangle bb = ce.getBoundingBox(); + if (oldbb != null) + oldbb = oldbb.union(bb); + else + oldbb = bb; + } + + // add new items + int oldsz = elmList.size(); + int flags = RC_RETAIN; + + // don't recenter circuit if we're going to paste in place because that will + // change the transform + // if (mouseCursorX > 0 && circuitArea.contains(mouseCursorX, mouseCursorY)) + + // in fact, don't ever recenter circuit, unless old circuit was empty + if (oldsz > 0) + flags |= RC_NO_CENTER; + + if (dump != null) + readCircuit(dump, flags); + else { + readClipboardFromStorage(); + readCircuit(clipboard, flags); + } + + // select new items and get their bounding box + Rectangle newbb = null; + for (i = oldsz; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + ce.setSelected(true); + Rectangle bb = ce.getBoundingBox(); + if (newbb != null) + newbb = newbb.union(bb); + else + newbb = bb; + } + + if (oldbb != null && newbb != null /* && oldbb.intersects(newbb) */) { + // find a place on the edge for new items + int dx = 0, dy = 0; + int spacew = circuitArea.width - oldbb.width - newbb.width; + int spaceh = circuitArea.height - oldbb.height - newbb.height; + + if (!oldbb.intersects(newbb)) { + // old coordinates may be really far away so move them to same origin as current + // circuit + dx = snapGrid(oldbb.x - newbb.x); + dy = snapGrid(oldbb.y - newbb.y); + } + + if (spacew > spaceh) { + dx = snapGrid(oldbb.x + oldbb.width - newbb.x + gridSize); + } else { + dy = snapGrid(oldbb.y + oldbb.height - newbb.y + gridSize); + } + + // move new items near the mouse if possible + if (mouseCursorX > 0 && circuitArea.contains(mouseCursorX, mouseCursorY)) { + int gx = inverseTransformX(mouseCursorX); + int gy = inverseTransformY(mouseCursorY); + int mdx = snapGrid(gx - (newbb.x + newbb.width / 2)); + int mdy = snapGrid(gy - (newbb.y + newbb.height / 2)); + for (i = oldsz; i != elmList.size(); i++) { + if (!getElm(i).allowMove(mdx, mdy)) + break; + } + if (i == elmList.size()) { + dx = mdx; + dy = mdy; + } + } + + // move the new items + for (i = oldsz; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + ce.move(dx, dy); + } + + // center circuit + // handleResize(); + } + needAnalyze(); + writeRecoveryToStorage(); } void clearSelection() { @@ -5236,197 +5317,195 @@ void clearSelection() { ce.setSelected(false); } } - + void doSelectAll() { - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - ce.setSelected(true); - } + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + ce.setSelected(true); + } } - + boolean anySelectedButMouse() { - for (int i=0; i != elmList.size(); i++) - if (getElm(i)!= mouseElm && getElm(i).selected) - return true; - return false; + for (int i = 0; i != elmList.size(); i++) + if (getElm(i) != mouseElm && getElm(i).selected) + return true; + return false; } -// public void keyPressed(KeyEvent e) {} -// public void keyReleased(KeyEvent e) {} - + // public void keyPressed(KeyEvent e) {} + // public void keyReleased(KeyEvent e) {} + boolean dialogIsShowing() { - if (editDialog!=null && editDialog.isShowing()) - return true; - if (customLogicEditDialog!=null && customLogicEditDialog.isShowing()) - return true; - if (diodeModelEditDialog!=null && diodeModelEditDialog.isShowing()) - return true; - if (dialogShowing != null && dialogShowing.isShowing()) - return true; - if (contextPanel!=null && contextPanel.isShowing()) - return true; - if (scrollValuePopup != null && scrollValuePopup.isShowing()) - return true; - if (aboutBox !=null && aboutBox.isShowing()) - return true; - return false; + if (editDialog != null && editDialog.isShowing()) + return true; + if (customLogicEditDialog != null && customLogicEditDialog.isShowing()) + return true; + if (diodeModelEditDialog != null && diodeModelEditDialog.isShowing()) + return true; + if (dialogShowing != null && dialogShowing.isShowing()) + return true; + if (contextPanel != null && contextPanel.isShowing()) + return true; + if (scrollValuePopup != null && scrollValuePopup.isShowing()) + return true; + if (aboutBox != null && aboutBox.isShowing()) + return true; + return false; } - + public void onPreviewNativeEvent(NativePreviewEvent e) { - int cc=e.getNativeEvent().getCharCode(); - int t=e.getTypeInt(); - int code=e.getNativeEvent().getKeyCode(); - if (dialogIsShowing()) { - if (scrollValuePopup != null && scrollValuePopup.isShowing() && - (t & Event.ONKEYDOWN)!=0) { - if (code==KEY_ESCAPE || code==KEY_SPACE) - scrollValuePopup.close(false); - if (code==KEY_ENTER) - scrollValuePopup.close(true); - } - - // process escape/enter for dialogs - // multiple edit dialogs could be displayed at once, pick the one in front - Dialog dlg = editDialog; - if (diodeModelEditDialog != null) - dlg = diodeModelEditDialog; - if (customLogicEditDialog != null) - dlg = customLogicEditDialog; - if (dialogShowing != null) - dlg = dialogShowing; - if (dlg!=null && dlg.isShowing() && - (t & Event.ONKEYDOWN)!=0) { - if (code==KEY_ESCAPE) - dlg.closeDialog(); - if (code==KEY_ENTER) - dlg.enterPressed(); - } - return; - } - - if ((t&Event.ONKEYPRESS)!=0) { - if (cc=='-') { - menuPerformed("key", "zoomout"); - e.cancel(); - } - if (cc=='+' || cc == '=') { - menuPerformed("key", "zoomin"); - e.cancel(); - } - if (cc=='0') { - menuPerformed("key", "zoom100"); - e.cancel(); + int cc = e.getNativeEvent().getCharCode(); + int t = e.getTypeInt(); + int code = e.getNativeEvent().getKeyCode(); + if (dialogIsShowing()) { + if (scrollValuePopup != null && scrollValuePopup.isShowing() && (t & Event.ONKEYDOWN) != 0) { + if (code == KEY_ESCAPE || code == KEY_SPACE) + scrollValuePopup.close(false); + if (code == KEY_ENTER) + scrollValuePopup.close(true); + } + + // process escape/enter for dialogs + // multiple edit dialogs could be displayed at once, pick the one in front + Dialog dlg = editDialog; + if (diodeModelEditDialog != null) + dlg = diodeModelEditDialog; + if (customLogicEditDialog != null) + dlg = customLogicEditDialog; + if (dialogShowing != null) + dlg = dialogShowing; + if (dlg != null && dlg.isShowing() && (t & Event.ONKEYDOWN) != 0) { + if (code == KEY_ESCAPE) + dlg.closeDialog(); + if (code == KEY_ENTER) + dlg.enterPressed(); + } + return; + } + + if ((t & Event.ONKEYPRESS) != 0) { + if (cc == '-') { + menuPerformed("key", "zoomout"); + e.cancel(); + } + if (cc == '+' || cc == '=') { + menuPerformed("key", "zoomin"); + e.cancel(); + } + if (cc == '0') { + menuPerformed("key", "zoom100"); + e.cancel(); + } + if (cc == '/' && shortcuts['/'] == null) { + menuPerformed("key", "search"); + e.cancel(); + } + } + + // all other shortcuts are ignored when editing disabled + if (noEditCheckItem.getState()) + return; + + if ((t & Event.ONKEYDOWN) != 0) { + if (code == KEY_BACKSPACE || code == KEY_DELETE) { + if (scopeSelected != -1) { + // Treat DELETE key with scope selected as "remove scope", not delete + scopes[scopeSelected].setElm(null); + scopeSelected = -1; + } else { + menuElm = null; + pushUndo(); + doDelete(true); + e.cancel(); + } + } + if (code == KEY_ESCAPE) { + setMouseMode(MODE_SELECT); + mouseModeStr = "Select"; + tempMouseMode = mouseMode; + e.cancel(); + } + + if (e.getNativeEvent().getCtrlKey() || e.getNativeEvent().getMetaKey()) { + if (code == KEY_C) { + menuPerformed("key", "copy"); + e.cancel(); } - if (cc=='/' && shortcuts['/'] == null) { - menuPerformed("key", "search"); + if (code == KEY_X) { + menuPerformed("key", "cut"); e.cancel(); } - } - - // all other shortcuts are ignored when editing disabled - if (noEditCheckItem.getState()) - return; - - if ((t & Event.ONKEYDOWN)!=0) { - if (code==KEY_BACKSPACE || code==KEY_DELETE) { - if (scopeSelected != -1) { - // Treat DELETE key with scope selected as "remove scope", not delete - scopes[scopeSelected].setElm(null); - scopeSelected = -1; - } else { - menuElm = null; - pushUndo(); - doDelete(true); - e.cancel(); - } - } - if (code==KEY_ESCAPE){ - setMouseMode(MODE_SELECT); - mouseModeStr = "Select"; - tempMouseMode = mouseMode; - e.cancel(); - } - - if (e.getNativeEvent().getCtrlKey() || e.getNativeEvent().getMetaKey()) { - if (code==KEY_C) { - menuPerformed("key", "copy"); - e.cancel(); - } - if (code==KEY_X) { - menuPerformed("key", "cut"); - e.cancel(); - } - if (code==KEY_V) { - menuPerformed("key", "paste"); - e.cancel(); - } - if (code==KEY_Z) { - menuPerformed("key", "undo"); - e.cancel(); - } - if (code==KEY_Y) { - menuPerformed("key", "redo"); - e.cancel(); - } - if (code==KEY_D) { - menuPerformed("key", "duplicate"); - e.cancel(); - } - if (code==KEY_A) { - menuPerformed("key", "selectAll"); - e.cancel(); - } - if (code==KEY_P) { - menuPerformed("key", "print"); - e.cancel(); - } - if (code==KEY_N && isElectron()) { - menuPerformed("key", "newwindow"); - e.cancel(); - } - if (code==KEY_S) { - String cmd = "exportaslocalfile"; - if (isElectron()) - cmd = saveFileItem.isEnabled() ? "save" : "saveas"; - menuPerformed("key", cmd); - e.cancel(); - } - if (code==KEY_O) { - menuPerformed("key", "importfromlocalfile"); - e.cancel(); - } - } - } - if ((t&Event.ONKEYPRESS)!=0) { - if (cc>32 && cc<127){ - String c=shortcuts[cc]; - e.cancel(); - if (c==null) - return; - setMouseMode(MODE_ADD_ELM); - mouseModeStr=c; - tempMouseMode = mouseMode; - } - if (cc==32) { - setMouseMode(MODE_SELECT); - mouseModeStr = "Select"; - tempMouseMode = mouseMode; - e.cancel(); - } - } + if (code == KEY_V) { + menuPerformed("key", "paste"); + e.cancel(); + } + if (code == KEY_Z) { + menuPerformed("key", "undo"); + e.cancel(); + } + if (code == KEY_Y) { + menuPerformed("key", "redo"); + e.cancel(); + } + if (code == KEY_D) { + menuPerformed("key", "duplicate"); + e.cancel(); + } + if (code == KEY_A) { + menuPerformed("key", "selectAll"); + e.cancel(); + } + if (code == KEY_P) { + menuPerformed("key", "print"); + e.cancel(); + } + if (code == KEY_N && isElectron()) { + menuPerformed("key", "newwindow"); + e.cancel(); + } + if (code == KEY_S) { + String cmd = "exportaslocalfile"; + if (isElectron()) + cmd = saveFileItem.isEnabled() ? "save" : "saveas"; + menuPerformed("key", cmd); + e.cancel(); + } + if (code == KEY_O) { + menuPerformed("key", "importfromlocalfile"); + e.cancel(); + } + } + } + if ((t & Event.ONKEYPRESS) != 0) { + if (cc > 32 && cc < 127) { + String c = shortcuts[cc]; + e.cancel(); + if (c == null) + return; + setMouseMode(MODE_ADD_ELM); + mouseModeStr = c; + tempMouseMode = mouseMode; + } + if (cc == 32) { + setMouseMode(MODE_SELECT); + mouseModeStr = "Select"; + tempMouseMode = mouseMode; + e.cancel(); + } + } } - + // factors a matrix into upper and lower triangular matrices by - // gaussian elimination. On entry, a[0..n-1][0..n-1] is the - // matrix to be factored. ipvt[] returns an integer vector of pivot + // gaussian elimination. On entry, a[0..n-1][0..n-1] is the + // matrix to be factored. ipvt[] returns an integer vector of pivot // indices, used in the lu_solve() routine. static boolean lu_factor(double a[][], int n, int ipvt[]) { - int i,j,k; - + int i, j, k; + // check for a possible singular matrix by scanning for rows that // are all zeroes - for (i = 0; i != n; i++) { + for (i = 0; i != n; i++) { boolean row_all_zeros = true; for (j = 0; j != n; j++) { if (a[i][j] != 0) { @@ -5438,15 +5517,15 @@ static boolean lu_factor(double a[][], int n, int ipvt[]) { if (row_all_zeros) return false; } - - // use Crout's method; loop through the columns + + // use Crout's method; loop through the columns for (j = 0; j != n; j++) { - + // calculate upper triangular elements for this column for (i = 0; i != j; i++) { double q = a[i][j]; for (k = 0; k != i; k++) - q -= a[i][k]*a[k][j]; + q -= a[i][k] * a[k][j]; a[i][j] = q; } @@ -5456,7 +5535,7 @@ static boolean lu_factor(double a[][], int n, int ipvt[]) { for (i = j; i != n; i++) { double q = a[i][j]; for (k = 0; k != j; k++) - q -= a[i][k]*a[k][j]; + q -= a[i][k] * a[k][j]; a[i][j] = q; double x = Math.abs(q); if (x >= largest) { @@ -5464,7 +5543,7 @@ static boolean lu_factor(double a[][], int n, int ipvt[]) { largestRow = i; } } - + // pivoting if (j != largestRow) { if (largestRow == -1) { @@ -5483,18 +5562,18 @@ static boolean lu_factor(double a[][], int n, int ipvt[]) { ipvt[j] = largestRow; // check for zeroes; if we find one, it's a singular matrix. - // we used to avoid them, but that caused weird bugs. For example, + // we used to avoid them, but that caused weird bugs. For example, // two inverters with outputs connected together should be flagged // as a singular matrix, but it was allowed (with weird currents) if (a[j][j] == 0.0) { console("didn't avoid zero"); -// a[j][j]=1e-18; + // a[j][j]=1e-18; return false; } - if (j != n-1) { - double mult = 1.0/a[j][j]; - for (i = j+1; i != n; i++) + if (j != n - 1) { + double mult = 1.0 / a[j][j]; + for (i = j + 1; i != n; i++) a[i][j] *= mult; } } @@ -5502,7 +5581,7 @@ static boolean lu_factor(double a[][], int n, int ipvt[]) { } // Solves the set of n linear equations using a LU factorization - // previously performed by lu_factor. On input, b[0..n-1] is the right + // previously performed by lu_factor. On input, b[0..n-1] is the right // hand side of the equations, and on output, contains the solution. static void lu_solve(double a[][], int n, int ipvt[], double b[]) { int i; @@ -5517,458 +5596,571 @@ static void lu_solve(double a[][], int n, int ipvt[], double b[]) { if (swap != 0) break; } - + int bi = i++; for (; i < n; i++) { int row = ipvt[i]; int j; double tot = b[row]; - + b[row] = b[i]; // forward substitution using the lower triangular matrix for (j = bi; j < i; j++) - tot -= a[i][j]*b[j]; + tot -= a[i][j] * b[j]; b[i] = tot; } - for (i = n-1; i >= 0; i--) { + for (i = n - 1; i >= 0; i--) { double tot = b[i]; - + // back-substitution using the upper triangular matrix int j; - for (j = i+1; j != n; j++) - tot -= a[i][j]*b[j]; - b[i] = tot/a[i][i]; + for (j = i + 1; j != n; j++) + tot -= a[i][j] * b[j]; + b[i] = tot / a[i][i]; } } - void createNewLoadFile() { - // This is a hack to fix what IMHO is a bug in the () { - public void onFailure(Exception reason) { - Window.alert("Can't load canvas2svg.js."); - } - public void onSuccess(Void result) { - loadedCanvas2SVG = true; - if (followupAction.equals("doExportAsSVG")) { - doExportAsSVG(); - } else if (followupAction.equals("doExportAsSVGFromAPI")) { - doExportAsSVGFromAPI(); - } - } - }).inject(); - return false; + void doDCAnalysis() { + dcAnalysisFlag = true; + resetAction(); + } + + void doPrint() { + Canvas cv = getCircuitAsCanvas(CAC_PRINT); + printCanvas(cv.getCanvasElement()); + } + + boolean loadedCanvas2SVG = false; + + boolean initializeSVGScriptIfNecessary(final String followupAction) { + // load canvas2svg if we haven't already + if (!loadedCanvas2SVG) { + ScriptInjector.fromUrl("canvas2svg.js").setCallback(new Callback() { + public void onFailure(Exception reason) { + Window.alert("Can't load canvas2svg.js."); } - return true; - } - void doExportAsSVG() { - if (!initializeSVGScriptIfNecessary("doExportAsSVG")) { - return; + public void onSuccess(Void result) { + loadedCanvas2SVG = true; + if (followupAction.equals("doExportAsSVG")) { + doExportAsSVG(); + } else if (followupAction.equals("doExportAsSVGFromAPI")) { + doExportAsSVGFromAPI(); + } } - dialogShowing = new ExportAsImageDialog(CAC_SVG); - dialogShowing.show(); + }).inject(); + return false; } + return true; + } - public void doExportAsSVGFromAPI() { - if (!initializeSVGScriptIfNecessary("doExportAsSVGFromAPI")) { - return; - } - String svg = getCircuitAsSVG(); - callSVGRenderedHook(svg); + void doExportAsSVG() { + if (!initializeSVGScriptIfNecessary("doExportAsSVG")) { + return; } + dialogShowing = new ExportAsImageDialog(CAC_SVG); + dialogShowing.show(); + } - static final int CAC_PRINT = 0; - static final int CAC_IMAGE = 1; - static final int CAC_SVG = 2; - - public Canvas getCircuitAsCanvas(int type) { - // create canvas to draw circuit into - Canvas cv = Canvas.createIfSupported(); - Rectangle bounds = getCircuitBounds(); - - // add some space on edges because bounds calculation is not perfect - int wmargin = 140; - int hmargin = 100; - int w = (bounds.width*2+wmargin) ; - int h = (bounds.height*2+hmargin) ; - cv.setCoordinateSpaceWidth(w); - cv.setCoordinateSpaceHeight(h); - - Context2d context = cv.getContext2d(); - drawCircuitInContext(context, type, bounds, w, h); - return cv; + public void doExportAsSVGFromAPI() { + if (!initializeSVGScriptIfNecessary("doExportAsSVGFromAPI")) { + return; } - - // create SVG context using canvas2svg - native static Context2d createSVGContext(int w, int h) /*-{ + String svg = getCircuitAsSVG(); + callSVGRenderedHook(svg); + } + + static final int CAC_PRINT = 0; + static final int CAC_IMAGE = 1; + static final int CAC_SVG = 2; + + public Canvas getCircuitAsCanvas(int type) { + // create canvas to draw circuit into + Canvas cv = Canvas.createIfSupported(); + Rectangle bounds = getCircuitBounds(); + + // add some space on edges because bounds calculation is not perfect + int wmargin = 140; + int hmargin = 100; + int w = (bounds.width * 2 + wmargin); + int h = (bounds.height * 2 + hmargin); + cv.setCoordinateSpaceWidth(w); + cv.setCoordinateSpaceHeight(h); + + Context2d context = cv.getContext2d(); + drawCircuitInContext(context, type, bounds, w, h); + return cv; + } + + // create SVG context using canvas2svg + native static Context2d createSVGContext(int w, int h) /*-{ return new C2S(w, h); }-*/; - - native static String getSerializedSVG(Context2d context) /*-{ + + native static String getSerializedSVG(Context2d context) /*-{ return context.getSerializedSvg(); }-*/; - - public String getCircuitAsSVG() { - Rectangle bounds = getCircuitBounds(); - // add some space on edges because bounds calculation is not perfect - int wmargin = 140; - int hmargin = 100; - int w = (bounds.width+wmargin) ; - int h = (bounds.height+hmargin) ; - Context2d context = createSVGContext(w, h); - drawCircuitInContext(context, CAC_SVG, bounds, w, h); - return getSerializedSVG(context); - } - - void drawCircuitInContext(Context2d context, int type, Rectangle bounds, int w, int h) { - Graphics g = new Graphics(context); - context.setTransform(1, 0, 0, 1, 0, 0); - double oldTransform[] = Arrays.copyOf(transform, 6); - - double scale = 1; - - // turn on white background, turn off current display - boolean p = printableCheckItem.getState(); - boolean c = dotsCheckItem.getState(); - boolean print = (type == CAC_PRINT); - if (print) - printableCheckItem.setState(true); - if (printableCheckItem.getState()) { - CircuitElm.whiteColor = Color.black; - CircuitElm.lightGrayColor = Color.black; - g.setColor(Color.white); - } else { - CircuitElm.whiteColor = Color.white; - CircuitElm.lightGrayColor = Color.lightGray; - g.setColor(Color.black); - g.fillRect(0, 0, w, h); - } - dotsCheckItem.setState(false); - - int wmargin = 140; - int hmargin = 100; - if (bounds != null) - scale = Math.min(w /(double)(bounds.width+wmargin), - h/(double)(bounds.height+hmargin)); - - // ScopeElms need the transform array to be updated - transform[0] = transform[3] = scale; - transform[4] = -(bounds.x-wmargin/2); - transform[5] = -(bounds.y-hmargin/2); - context.scale(scale, scale); - context.translate(transform[4], transform[5]); - context.setLineCap(Context2d.LineCap.ROUND); - - // draw elements - int i; - for (i = 0; i != elmList.size(); i++) { - getElm(i).draw(g); - } - for (i = 0; i != postDrawList.size(); i++) { - CircuitElm.drawPost(g, postDrawList.get(i)); - } + public String getCircuitAsSVG() { + Rectangle bounds = getCircuitBounds(); - // restore everything - printableCheckItem.setState(p); - dotsCheckItem.setState(c); - transform = oldTransform; + // add some space on edges because bounds calculation is not perfect + int wmargin = 140; + int hmargin = 100; + int w = (bounds.width + wmargin); + int h = (bounds.height + hmargin); + Context2d context = createSVGContext(w, h); + drawCircuitInContext(context, CAC_SVG, bounds, w, h); + return getSerializedSVG(context); + } + + void drawCircuitInContext(Context2d context, int type, Rectangle bounds, int w, int h) { + Graphics g = new Graphics(context); + context.setTransform(1, 0, 0, 1, 0, 0); + double oldTransform[] = Arrays.copyOf(transform, 6); + + double scale = 1; + + // turn on white background, turn off current display + boolean p = printableCheckItem.getState(); + boolean c = dotsCheckItem.getState(); + boolean print = (type == CAC_PRINT); + if (print) + printableCheckItem.setState(true); + if (printableCheckItem.getState()) { + CircuitElm.whiteColor = Color.black; + CircuitElm.lightGrayColor = Color.black; + g.setColor(Color.white); + } else { + CircuitElm.whiteColor = Color.white; + CircuitElm.lightGrayColor = Color.lightGray; + g.setColor(Color.black); + g.fillRect(0, 0, w, h); } - - boolean isSelection() { - for (int i = 0; i != elmList.size(); i++) - if (getElm(i).isSelected()) - return true; - return false; + dotsCheckItem.setState(false); + + int wmargin = 140; + int hmargin = 100; + if (bounds != null) + scale = Math.min(w / (double) (bounds.width + wmargin), h / (double) (bounds.height + hmargin)); + + // ScopeElms need the transform array to be updated + transform[0] = transform[3] = scale; + transform[4] = -(bounds.x - wmargin / 2); + transform[5] = -(bounds.y - hmargin / 2); + context.scale(scale, scale); + context.translate(transform[4], transform[5]); + context.setLineCap(Context2d.LineCap.ROUND); + + // draw elements + int i; + for (i = 0; i != elmList.size(); i++) { + getElm(i).draw(g); } - - public CustomCompositeModel getCircuitAsComposite() { - int i; - String nodeDump = ""; - String dump = ""; -// String models = ""; - CustomLogicModel.clearDumpedFlags(); - DiodeModel.clearDumpedFlags(); - TransistorModel.clearDumpedFlags(); - Vector sideLabels[] = new Vector[] { - new Vector(), new Vector(), - new Vector(), new Vector() - }; - Vector extList = new Vector(); - boolean sel = isSelection(); - - boolean used[] = new boolean[nodeList.size()]; - boolean extnodes[] = new boolean[nodeList.size()]; - - // find all the labeled nodes, get a list of them, and create a node number map - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (sel && !ce.isSelected()) - continue; - if (ce instanceof LabeledNodeElm) { - LabeledNodeElm lne = (LabeledNodeElm) ce; - String label = lne.text; - if (lne.isInternal()) - continue; - - // already added to list? - if (extnodes[ce.getNode(0)]) - continue; - - int side = ChipElm.SIDE_W; - if (Math.abs(ce.dx) >= Math.abs(ce.dy) && ce.dx > 0) side = ChipElm.SIDE_E; - if (Math.abs(ce.dx) <= Math.abs(ce.dy) && ce.dy < 0) side = ChipElm.SIDE_N; - if (Math.abs(ce.dx) <= Math.abs(ce.dy) && ce.dy > 0) side = ChipElm.SIDE_S; - - // create ext list entry for external nodes - sideLabels[side].add(lne); - extnodes[ce.getNode(0)] = true; - } - } - - Collections.sort(sideLabels[ChipElm.SIDE_W], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.y - b.y)); - Collections.sort(sideLabels[ChipElm.SIDE_E], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.y - b.y)); - Collections.sort(sideLabels[ChipElm.SIDE_N], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.x - b.x)); - Collections.sort(sideLabels[ChipElm.SIDE_S], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.x - b.x)); - - for (int side = 0; side < sideLabels.length; side++) { - for (int pos = 0; pos < sideLabels[side].size(); pos++) { - LabeledNodeElm lne = sideLabels[side].get(pos); - ExtListEntry ent = new ExtListEntry(lne.text, lne.getNode(0), pos, side); - extList.add(ent); - } - } - - // output all the elements - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (sel && !ce.isSelected()) - continue; - // don't need these elements dumped - if (ce instanceof WireElm || ce instanceof LabeledNodeElm || ce instanceof ScopeElm) + for (i = 0; i != postDrawList.size(); i++) { + CircuitElm.drawPost(g, postDrawList.get(i)); + } + + // restore everything + printableCheckItem.setState(p); + dotsCheckItem.setState(c); + transform = oldTransform; + } + + boolean isSelection() { + for (int i = 0; i != elmList.size(); i++) + if (getElm(i).isSelected()) + return true; + return false; + } + + public CustomCompositeModel getCircuitAsComposite() { + int i; + String nodeDump = ""; + String dump = ""; + // String models = ""; + CustomLogicModel.clearDumpedFlags(); + DiodeModel.clearDumpedFlags(); + TransistorModel.clearDumpedFlags(); + Vector sideLabels[] = new Vector[] { new Vector(), new Vector(), + new Vector(), new Vector() }; + Vector extList = new Vector(); + boolean sel = isSelection(); + + boolean used[] = new boolean[nodeList.size()]; + boolean extnodes[] = new boolean[nodeList.size()]; + + // find all the labeled nodes, get a list of them, and create a node number map + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (sel && !ce.isSelected()) + continue; + if (ce instanceof LabeledNodeElm) { + LabeledNodeElm lne = (LabeledNodeElm) ce; + String label = lne.text; + if (lne.isInternal()) continue; - if (ce instanceof GraphicElm || ce instanceof GroundElm) + + // already added to list? + if (extnodes[ce.getNode(0)]) continue; - int j; - if (nodeDump.length() > 0) - nodeDump += "\r"; - nodeDump += ce.getClass().getSimpleName(); - for (j = 0; j != ce.getPostCount(); j++) { - int n = ce.getNode(j); - used[n] = true; - nodeDump += " " + n; - } - - // save positions - int x1 = ce.x; int y1 = ce.y; - int x2 = ce.x2; int y2 = ce.y2; - - // set them to 0 so they're easy to remove - ce.x = ce.y = ce.x2 = ce.y2 = 0; - - String tstring = ce.dump(); - tstring = tstring.replaceFirst("[A-Za-z0-9]+ 0 0 0 0 ", ""); // remove unused tint_x1 y1 x2 y2 coords for internal components - - // restore positions - ce.x = x1; ce.y = y1; ce.x2 = x2; ce.y2 = y2; - if (dump.length() > 0) - dump += " "; - dump += CustomLogicModel.escape(tstring); - } - - for (i = 0; i != extList.size(); i++) { - ExtListEntry ent = extList.get(i); - if (!used[ent.node]) { - Window.alert("Node \"" + ent.name + "\" is not used!"); - return null; - } + + int side = ChipElm.SIDE_W; + if (Math.abs(ce.dx) >= Math.abs(ce.dy) && ce.dx > 0) + side = ChipElm.SIDE_E; + if (Math.abs(ce.dx) <= Math.abs(ce.dy) && ce.dy < 0) + side = ChipElm.SIDE_N; + if (Math.abs(ce.dx) <= Math.abs(ce.dy) && ce.dy > 0) + side = ChipElm.SIDE_S; + + // create ext list entry for external nodes + sideLabels[side].add(lne); + extnodes[ce.getNode(0)] = true; } - - boolean first = true; - for (i = 0; i != unconnectedNodes.size(); i++) { - int q = unconnectedNodes.get(i); - if (!extnodes[q] && used[q]) { - if (nodesWithGroundConnectionCount == 0 && first) { - first = false; - continue; - } - Window.alert("Some nodes are unconnected!"); - return null; - } - } + } - CustomCompositeModel ccm = new CustomCompositeModel(); - ccm.nodeList = nodeDump; - ccm.elmDump = dump; - ccm.extList = extList; - return ccm; + Collections.sort(sideLabels[ChipElm.SIDE_W], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.y - b.y)); + Collections.sort(sideLabels[ChipElm.SIDE_E], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.y - b.y)); + Collections.sort(sideLabels[ChipElm.SIDE_N], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.x - b.x)); + Collections.sort(sideLabels[ChipElm.SIDE_S], (LabeledNodeElm a, LabeledNodeElm b) -> Integer.signum(a.x - b.x)); + + for (int side = 0; side < sideLabels.length; side++) { + for (int pos = 0; pos < sideLabels[side].size(); pos++) { + LabeledNodeElm lne = sideLabels[side].get(pos); + ExtListEntry ent = new ExtListEntry(lne.text, lne.getNode(0), pos, side); + extList.add(ent); + } } - - static void invertMatrix(double a[][], int n) { - int ipvt[] = new int[n]; - lu_factor(a, n, ipvt); - int i, j; - double b[] = new double[n]; - double inva[][] = new double[n][n]; - - // solve for each column of identity matrix - for (i = 0; i != n; i++) { - for (j = 0; j != n; j++) - b[j] = 0; - b[i] = 1; - lu_solve(a, n, ipvt, b); - for (j = 0; j != n; j++) - inva[j][i] = b[j]; + + // output all the elements + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (sel && !ce.isSelected()) + continue; + // don't need these elements dumped + if (ce instanceof WireElm || ce instanceof LabeledNodeElm || ce instanceof ScopeElm) + continue; + if (ce instanceof GraphicElm || ce instanceof GroundElm) + continue; + int j; + if (nodeDump.length() > 0) + nodeDump += "\r"; + nodeDump += ce.getClass().getSimpleName(); + for (j = 0; j != ce.getPostCount(); j++) { + int n = ce.getNode(j); + used[n] = true; + nodeDump += " " + n; } - - // return in original matrix - for (i = 0; i != n; i++) - for (j = 0; j != n; j++) - a[i][j] = inva[i][j]; + + // save positions + int x1 = ce.x; + int y1 = ce.y; + int x2 = ce.x2; + int y2 = ce.y2; + + // set them to 0 so they're easy to remove + ce.x = ce.y = ce.x2 = ce.y2 = 0; + + String tstring = ce.dump(); + tstring = tstring.replaceFirst("[A-Za-z0-9]+ 0 0 0 0 ", ""); // remove unused tint_x1 y1 x2 y2 coords for + // internal components + + // restore positions + ce.x = x1; + ce.y = y1; + ce.x2 = x2; + ce.y2 = y2; + if (dump.length() > 0) + dump += " "; + dump += CustomLogicModel.escape(tstring); } - - double getLabeledNodeVoltage(String name) { - Integer node = LabeledNodeElm.getByName(name); - if (node == null || node == 0) - return 0; - // subtract one because ground is not included in nodeVoltages[] - return nodeVoltages[node.intValue()-1]; + + for (i = 0; i != extList.size(); i++) { + ExtListEntry ent = extList.get(i); + if (!used[ent.node]) { + Window.alert("Node \"" + ent.name + "\" is not used!"); + return null; + } } - - void setExtVoltage(String name, double v) { - int i; - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - if (ce instanceof ExtVoltageElm) { - ExtVoltageElm eve = (ExtVoltageElm) ce; - if (eve.getName().equals(name)) - eve.setVoltage(v); + + boolean first = true; + for (i = 0; i != unconnectedNodes.size(); i++) { + int q = unconnectedNodes.get(i); + if (!extnodes[q] && used[q]) { + if (nodesWithGroundConnectionCount == 0 && first) { + first = false; + continue; } + Window.alert("Some nodes are unconnected!"); + return null; } } - native JsArray getJSArray() /*-{ return []; }-*/; - - JsArray getJSElements() { - int i; - JsArray arr = getJSArray(); - for (i = 0; i != elmList.size(); i++) { - CircuitElm ce = getElm(i); - ce.addJSMethods(); - arr.push(ce.getJavaScriptObject()); + CustomCompositeModel ccm = new CustomCompositeModel(); + ccm.nodeList = nodeDump; + ccm.elmDump = dump; + ccm.extList = extList; + return ccm; + } + + static void invertMatrix(double a[][], int n) { + int ipvt[] = new int[n]; + lu_factor(a, n, ipvt); + int i, j; + double b[] = new double[n]; + double inva[][] = new double[n][n]; + + // solve for each column of identity matrix + for (i = 0; i != n; i++) { + for (j = 0; j != n; j++) + b[j] = 0; + b[i] = 1; + lu_solve(a, n, ipvt, b); + for (j = 0; j != n; j++) + inva[j][i] = b[j]; + } + + // return in original matrix + for (i = 0; i != n; i++) + for (j = 0; j != n; j++) + a[i][j] = inva[i][j]; + } + + double getLabeledNodeVoltage(String name) { + Integer node = LabeledNodeElm.getByName(name); + if (node == null || node == 0) + return 0; + // subtract one because ground is not included in nodeVoltages[] + return nodeVoltages[node.intValue() - 1]; + } + + void setExtVoltage(String name, double v) { + int i; + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + if (ce instanceof ExtVoltageElm) { + ExtVoltageElm eve = (ExtVoltageElm) ce; + if (eve.getName().equals(name)) + eve.setVoltage(v); } - return arr; } - - native void setupJSInterface() /*-{ + } + + native JsArray getJSArray() /*-{ return []; }-*/; + + JsArray getJSElements() { + int i; + JsArray arr = getJSArray(); + for (i = 0; i != elmList.size(); i++) { + CircuitElm ce = getElm(i); + ce.addJSMethods(); + arr.push(ce.getJavaScriptObject()); + } + return arr; + } + + native void setupJSInterface() /*-{ var that = this; $wnd.CircuitJS1 = { setSimRunning: $entry(function(run) { that.@com.lushprojects.circuitjs1.client.CirSim::setSimRunning(Z)(run); } ), @@ -6396,42 +6595,41 @@ native void setupJSInterface() /*-{ if (hook) hook($wnd.CircuitJS1); }-*/; - - native void callUpdateHook() /*-{ + + native void callUpdateHook() /*-{ var hook = $wnd.CircuitJS1.onupdate; if (hook) hook($wnd.CircuitJS1); }-*/; - - native void callAnalyzeHook() /*-{ + + native void callAnalyzeHook() /*-{ var hook = $wnd.CircuitJS1.onanalyze; if (hook) hook($wnd.CircuitJS1); }-*/; - - native void callTimeStepHook() /*-{ + native void callTimeStepHook() /*-{ var hook = $wnd.CircuitJS1.ontimestep; if (hook) hook($wnd.CircuitJS1); }-*/; - - native void callSVGRenderedHook(String svgData) /*-{ + + native void callSVGRenderedHook(String svgData) /*-{ var hook = $wnd.CircuitJS1.onsvgrendered; if (hook) hook($wnd.CircuitJS1, svgData); }-*/; - class UndoItem { - public String dump; - public double scale, transform4, transform5; - UndoItem(String d) { - dump = d; - scale = transform[0]; - transform4 = transform[4]; - transform5 = transform[5]; - } + class UndoItem { + public String dump; + public double scale, transform4, transform5; + + UndoItem(String d) { + dump = d; + scale = transform[0]; + transform4 = transform[4]; + transform5 = transform[5]; } + } } - diff --git a/src/com/lushprojects/circuitjs1/client/CircuitElm.java b/src/com/lushprojects/circuitjs1/client/CircuitElm.java index c6bb39ba..f4386d77 100644 --- a/src/com/lushprojects/circuitjs1/client/CircuitElm.java +++ b/src/com/lushprojects/circuitjs1/client/CircuitElm.java @@ -34,13 +34,13 @@ // circuit element class public abstract class CircuitElm implements Editable { static double voltageRange = 5; - static int colorScaleCount = 201; // odd so ground = gray + static int colorScaleCount = 201; // odd so ground = gray static Color colorScale[]; static double currentMult, powerMult; - + // scratch points for convenience static Point ps1, ps2; - + static CirSim sim; static public Color whiteColor, lightGrayColor, selectColor; static public Color positiveColor, negativeColor, neutralColor, currentColor; @@ -54,71 +54,80 @@ public abstract class CircuitElm implements Editable { static final int SCALE_1 = 1; static final int SCALE_M = 2; static final int SCALE_MU = 3; - + static int decimalDigits, shortDecimalDigits; - - // initial point where user created element. For simple two-terminal elements, this is the first node/post. + + // initial point where user created element. For simple two-terminal elements, + // this is the first node/post. int x, y; - - // point to which user dragged out element. For simple two-terminal elements, this is the second node/post + + // point to which user dragged out element. For simple two-terminal elements, + // this is the second node/post int x2, y2; - + int flags, nodes[], voltSource; - + // length along x and y axes, and sign of difference int dx, dy, dsign; - int lastHandleGrabbed=-1; - + int lastHandleGrabbed = -1; + // length of element double dn; - + double dpx1, dpy1; - + // (x,y) and (x2,y2) as Point objects Point point1, point2; - - // lead points (ends of wire stubs for simple two-terminal elements) + + // lead points (ends of wire stubs for simple two-terminal elements) Point lead1, lead2; - + // voltages at each node double volts[]; - + double current, curcount; Rectangle boundingBox; - - // if subclasses set this to true, element will be horizontal or vertical only + + // if subclasses set this to true, element will be horizontal or vertical only boolean noDiagonal; - + public boolean selected; - + boolean hasWireInfo; // used in calcWireInfo() - -// abstract int getDumpType(); + + // abstract int getDumpType(); int getDumpType() { - + throw new IllegalStateException(); // Seems necessary to work-around what appears to be a compiler - // bug affecting OTAElm to make sure this method (which should really be abstract) throws - // an exception. If you're getting this, try making small update to CompositeElm.java and try again - } - - // leftover from java, doesn't do anything anymore. - Class getDumpClass() { return getClass(); } - - int getDefaultFlags() { return 0; } + // bug affecting OTAElm to make sure this method (which should really be + // abstract) throws + // an exception. If you're getting this, try making small update to + // CompositeElm.java and try again + } + + // leftover from java, doesn't do anything anymore. + Class getDumpClass() { + return getClass(); + } + + int getDefaultFlags() { + return 0; + } + + boolean hasFlag(int f) { + return (flags & f) != 0; + } - boolean hasFlag(int f) { return (flags & f) != 0; } - static void initClass(CirSim s) { unitsFont = new Font("SansSerif", 0, 12); sim = s; - + colorScale = new Color[colorScaleCount]; - - + ps1 = new Point(); ps2 = new Point(); - + Storage stor = Storage.getLocalStorageIfSupported(); decimalDigits = 3; shortDecimalDigits = 1; @@ -139,7 +148,7 @@ static void setDecimalDigits(int num, boolean sf, boolean save) { shortDecimalDigits = num; else decimalDigits = num; - + String s = "####."; int ct = num; for (; ct > 0; ct--) @@ -149,13 +158,13 @@ static void setDecimalDigits(int num, boolean sf, boolean save) { shortFormat = nf; else showFormat = nf; - + if (save) { Storage stor = Storage.getLocalStorageIfSupported(); if (stor != null) stor.setItem(sf ? "decimalDigitsShort" : "decimalDigits", Integer.toString(num)); } - + if (!sf) { s = "####."; ct = num; @@ -164,7 +173,7 @@ static void setDecimalDigits(int num, boolean sf, boolean save) { fixedFormat = NumberFormat.getFormat(s); } } - + static void setColorScale() { int i; @@ -175,7 +184,7 @@ static void setColorScale() { negativeColor = Color.red; if (neutralColor == null) neutralColor = Color.gray; - + for (i = 0; i != colorScaleCount; i++) { double v = i * 2. / colorScaleCount - 1; if (v < 0) { @@ -186,7 +195,7 @@ static void setColorScale() { } } - + // create new element with one post at xx,yy, to be dragged out by user CircuitElm(int xx, int yy) { x = x2 = xx; @@ -195,20 +204,23 @@ static void setColorScale() { allocNodes(); initBoundingBox(); } - + // create element between xa,ya and xb,yb from undump CircuitElm(int xa, int ya, int xb, int yb, int f) { - x = xa; y = ya; x2 = xb; y2 = yb; flags = f; + x = xa; + y = ya; + x2 = xb; + y2 = yb; + flags = f; allocNodes(); initBoundingBox(); } - + void initBoundingBox() { boundingBox = new Rectangle(); - boundingBox.setBounds(min(x, x2), min(y, y2), - abs(x2-x)+1, abs(y2-y)+1); + boundingBox.setBounds(min(x, x2), min(y, y2), abs(x2 - x) + 1, abs(y2 - y) + 1); } - + // allocate nodes/volts arrays we need void allocNodes() { int n = getPostCount() + getInternalNodeCount(); @@ -218,78 +230,97 @@ void allocNodes() { volts = new double[n]; } } - + // dump component state for export/undo String dump() { int t = getDumpType(); - return (t < 127 ? ((char)t)+" " : t+" ") + x + " " + y + " " + - x2 + " " + y2 + " " + flags; + return (t < 127 ? ((char) t) + " " : t + " ") + x + " " + y + " " + x2 + " " + y2 + " " + flags; } - + // handle reset button void reset() { int i; - for (i = 0; i != getPostCount()+getInternalNodeCount(); i++) + for (i = 0; i != getPostCount() + getInternalNodeCount(); i++) volts[i] = 0; curcount = 0; } - void draw(Graphics g) {} - - // set current for voltage source vn to c. vn will be the same value as in a previous call to setVoltageSource(n, vn) - void setCurrent(int vn, double c) { current = c; } - + + void draw(Graphics g) { + } + + // set current for voltage source vn to c. vn will be the same value as in a + // previous call to setVoltageSource(n, vn) + void setCurrent(int vn, double c) { + current = c; + } + // get current for one- or two-terminal elements - double getCurrent() { return current; } + double getCurrent() { + return current; + } + + void setParentList(Vector elmList) { + } - void setParentList(Vector elmList) {} - // stamp matrix values for linear elements. - // for non-linear elements, use this to stamp values that don't change each iteration, and call stampRightSide() or stampNonLinear() as needed - void stamp() {} - + // for non-linear elements, use this to stamp values that don't change each + // iteration, and call stampRightSide() or stampNonLinear() as needed + void stamp() { + } + // stamp matrix values for non-linear elements - void doStep() {} - + void doStep() { + } + void delete() { - if (mouseElmRef==this) - mouseElmRef=null; + if (mouseElmRef == this) + mouseElmRef = null; sim.deleteSliders(this); } - void startIteration() {} - + + void startIteration() { + } + // get voltage of x'th node - double getPostVoltage(int x) { return volts[x]; } - + double getPostVoltage(int x) { + return volts[x]; + } + // set voltage of x'th node, called by simulator logic void setNodeVoltage(int n, double c) { volts[n] = c; calculateCurrent(); } - + // calculate current in response to node voltages changing - void calculateCurrent() {} - - // calculate post locations and other convenience values used for drawing. Called when element is moved + void calculateCurrent() { + } + + // calculate post locations and other convenience values used for drawing. + // Called when element is moved void setPoints() { - dx = x2-x; dy = y2-y; - dn = Math.sqrt(dx*dx+dy*dy); - dpx1 = dy/dn; - dpy1 = -dx/dn; - dsign = (dy == 0) ? sign(dx) : sign(dy); - point1 = new Point(x , y ); - point2 = new Point(x2, y2); + dx = x2 - x; + dy = y2 - y; + dn = Math.sqrt(dx * dx + dy * dy); + dpx1 = dy / dn; + dpy1 = -dx / dn; + dsign = (dy == 0) ? sign(dx) : sign(dy); + point1 = new Point(x, y); + point2 = new Point(x2, y2); } - - // calculate lead points for an element of length len. Handy for simple two-terminal elements. - // Posts are where the user connects wires; leads are ends of wire stubs drawn inside the element. + + // calculate lead points for an element of length len. Handy for simple + // two-terminal elements. + // Posts are where the user connects wires; leads are ends of wire stubs drawn + // inside the element. void calcLeads(int len) { if (dn < len || len == 0) { lead1 = point1; lead2 = point2; return; } - lead1 = interpPoint(point1, point2, (dn-len)/(2*dn)); - lead2 = interpPoint(point1, point2, (dn+len)/(2*dn)); + lead1 = interpPoint(point1, point2, (dn - len) / (2 * dn)); + lead2 = interpPoint(point1, point2, (dn + len) / (2 * dn)); } // calculate point fraction f between a and b, linearly interpolated @@ -298,35 +329,47 @@ Point interpPoint(Point a, Point b, double f) { interpPoint(a, b, p, f); return p; } - - // calculate point fraction f between a and b, linearly interpolated, return it in c + + // calculate point fraction f between a and b, linearly interpolated, return it + // in c void interpPoint(Point a, Point b, Point c, double f) { - c.x = (int) Math.floor(a.x*(1-f)+b.x*f+.48); - c.y = (int) Math.floor(a.y*(1-f)+b.y*f+.48); + c.x = (int) Math.floor(a.x * (1 - f) + b.x * f + .48); + c.y = (int) Math.floor(a.y * (1 - f) + b.y * f + .48); } - + /** - * Returns a point fraction f along the line between a and b and offset perpendicular by g - * @param a 1st Point - * @param b 2nd Point - * @param f Fraction along line - * @param g Fraction perpendicular to line - * Returns interpolated point in c + * Returns a point fraction f along the line between a and b and offset + * perpendicular by g + * + * @param a + * 1st Point + * @param b + * 2nd Point + * @param f + * Fraction along line + * @param g + * Fraction perpendicular to line Returns interpolated point in c */ void interpPoint(Point a, Point b, Point c, double f, double g) { - int gx = b.y-a.y; - int gy = a.x-b.x; - g /= Math.sqrt(gx*gx+gy*gy); - c.x = (int) Math.floor(a.x*(1-f)+b.x*f+g*gx+.48); - c.y = (int) Math.floor(a.y*(1-f)+b.y*f+g*gy+.48); + int gx = b.y - a.y; + int gy = a.x - b.x; + g /= Math.sqrt(gx * gx + gy * gy); + c.x = (int) Math.floor(a.x * (1 - f) + b.x * f + g * gx + .48); + c.y = (int) Math.floor(a.y * (1 - f) + b.y * f + g * gy + .48); } - + /** - * Returns a point fraction f along the line between a and b and offset perpendicular by g - * @param a 1st Point - * @param b 2nd Point - * @param f Fraction along line - * @param g Fraction perpendicular to line + * Returns a point fraction f along the line between a and b and offset + * perpendicular by g + * + * @param a + * 1st Point + * @param b + * 2nd Point + * @param f + * Fraction along line + * @param g + * Fraction perpendicular to line * @return Interpolated point */ Point interpPoint(Point a, Point b, double f, double g) { @@ -334,29 +377,36 @@ Point interpPoint(Point a, Point b, double f, double g) { interpPoint(a, b, p, f, g); return p; } - - + /** - * Calculates two points fraction f along the line between a and b and offest perpendicular by +/-g - * @param a 1st point (In) - * @param b 2nd point (In) - * @param c 1st point (Out) - * @param d 2nd point (Out) - * @param f Fraction along line - * @param g Fraction perpendicular to line + * Calculates two points fraction f along the line between a and b and offest + * perpendicular by +/-g + * + * @param a + * 1st point (In) + * @param b + * 2nd point (In) + * @param c + * 1st point (Out) + * @param d + * 2nd point (Out) + * @param f + * Fraction along line + * @param g + * Fraction perpendicular to line */ void interpPoint2(Point a, Point b, Point c, Point d, double f, double g) { -// int xpd = b.x-a.x; -// int ypd = b.y-a.y; - int gx = b.y-a.y; - int gy = a.x-b.x; - g /= Math.sqrt(gx*gx+gy*gy); - c.x = (int) Math.floor(a.x*(1-f)+b.x*f+g*gx+.48); - c.y = (int) Math.floor(a.y*(1-f)+b.y*f+g*gy+.48); - d.x = (int) Math.floor(a.x*(1-f)+b.x*f-g*gx+.48); - d.y = (int) Math.floor(a.y*(1-f)+b.y*f-g*gy+.48); + // int xpd = b.x-a.x; + // int ypd = b.y-a.y; + int gx = b.y - a.y; + int gy = a.x - b.x; + g /= Math.sqrt(gx * gx + gy * gy); + c.x = (int) Math.floor(a.x * (1 - f) + b.x * f + g * gx + .48); + c.y = (int) Math.floor(a.y * (1 - f) + b.y * f + g * gy + .48); + d.x = (int) Math.floor(a.x * (1 - f) + b.x * f - g * gx + .48); + d.y = (int) Math.floor(a.y * (1 - f) + b.y * f - g * gy + .48); } - + void draw2Leads(Graphics g) { // draw first lead setVoltageColor(g, volts[0]); @@ -366,7 +416,8 @@ void draw2Leads(Graphics g) { setVoltageColor(g, volts[1]); drawThickLine(g, lead2, point2); } - Point [] newPointArray(int n) { + + Point[] newPointArray(int n) { Point a[] = new Point[n]; while (n > 0) a[--n] = new Point(); @@ -377,11 +428,11 @@ void draw2Leads(Graphics g) { // draw current dots from point a to b void drawDots(Graphics g, Point pa, Point pb, double pos) { - if ((!sim.simIsRunning()) || pos == 0 || !sim.dotsCheckItem.getState()) + if ((!sim.simIsRunning()) || pos == 0 || !sim.dotsCheckItem.getState()) return; - int dx = pb.x-pa.x; - int dy = pb.y-pa.y; - double dn = Math.sqrt(dx*dx+dy*dy); + int dx = pb.x - pa.x; + int dy = pb.y - pa.y; + double dn = Math.sqrt(dx * dx + dy * dy); g.setColor(currentColor); int ds = 16; if (pos == CURRENT_TOO_FAST || pos == -CURRENT_TOO_FAST) { @@ -396,38 +447,39 @@ void drawDots(Graphics g, Point pa, Point pb, double pos) { ctx.lineTo(pb.x, pb.y); ctx.stroke(); g.restore(); - pos = Random.nextDouble()*ds; + pos = Random.nextDouble() * ds; } pos %= ds; if (pos < 0) pos += ds; double di = 0; for (di = pos; di < dn; di += ds) { - int x0 = (int) (pa.x+di*dx/dn); - int y0 = (int) (pa.y+di*dy/dn); - g.fillRect(x0-2, y0-2, 4, 4); + int x0 = (int) (pa.x + di * dx / dn); + int y0 = (int) (pa.y + di * dy / dn); + g.fillRect(x0 - 2, y0 - 2, 4, 4); } } double addCurCount(double c, double a) { if (c == CURRENT_TOO_FAST || c == -CURRENT_TOO_FAST) return c; - return c+a; + return c + a; } - + Polygon calcArrow(Point a, Point b, double al, double aw) { Polygon poly = new Polygon(); Point p1 = new Point(); Point p2 = new Point(); - int adx = b.x-a.x; - int ady = b.y-a.y; - double l = Math.sqrt(adx*adx+ady*ady); + int adx = b.x - a.x; + int ady = b.y - a.y; + double l = Math.sqrt(adx * adx + ady * ady); poly.addPoint(b.x, b.y); - interpPoint2(a, b, p1, p2, 1-al/l, aw); + interpPoint2(a, b, p1, p2, 1 - al / l, aw); poly.addPoint(p1.x, p1.y); poly.addPoint(p2.x, p2.y); return poly; } + Polygon createPolygon(Point a, Point b, Point c) { Polygon p = new Polygon(); p.addPoint(a.x, a.y); @@ -435,6 +487,7 @@ Polygon createPolygon(Point a, Point b, Point c) { p.addPoint(c.x, c.y); return p; } + Polygon createPolygon(Point a, Point b, Point c, Point d) { Polygon p = new Polygon(); p.addPoint(a.x, a.y); @@ -443,6 +496,7 @@ Polygon createPolygon(Point a, Point b, Point c, Point d) { p.addPoint(d.x, d.y); return p; } + Polygon createPolygon(Point a[]) { Polygon p = new Polygon(); int i; @@ -450,34 +504,40 @@ Polygon createPolygon(Point a[]) { p.addPoint(a[i].x, a[i].y); return p; } - + // draw second point to xx, yy void drag(int xx, int yy) { xx = sim.snapGrid(xx); yy = sim.snapGrid(yy); if (noDiagonal) { - if (Math.abs(x-xx) < Math.abs(y-yy)) { + if (Math.abs(x - xx) < Math.abs(y - yy)) { xx = x; } else { yy = y; } } - x2 = xx; y2 = yy; + x2 = xx; + y2 = yy; setPoints(); } - + void move(int dx, int dy) { - x += dx; y += dy; x2 += dx; y2 += dy; + x += dx; + y += dy; + x2 += dx; + y2 += dy; boundingBox.translate(dx, dy); setPoints(); } - // called when an element is done being dragged out; returns true if it's zero size and should be deleted + // called when an element is done being dragged out; returns true if it's zero + // size and should be deleted boolean creationFailed() { return (x == x2 && y == y2); } - // this is used to set the position of an internal element so we can draw it inside the parent + // this is used to set the position of an internal element so we can draw it + // inside the parent void setPosition(int x_, int y_, int x2_, int y2_) { x = x_; y = y_; @@ -485,13 +545,14 @@ void setPosition(int x_, int y_, int x2_, int y2_) { y2 = y2_; setPoints(); } - - // determine if moving this element by (dx,dy) will put it on top of another element + + // determine if moving this element by (dx,dy) will put it on top of another + // element boolean allowMove(int dx, int dy) { - int nx = x+dx; - int ny = y+dy; - int nx2 = x2+dx; - int ny2 = y2+dy; + int nx = x + dx; + int ny = y + dy; + int nx2 = x2 + dx; + int ny2 = y2 + dy; int i; for (i = 0; i != sim.elmList.size(); i++) { CircuitElm ce = sim.getElm(i); @@ -502,42 +563,46 @@ boolean allowMove(int dx, int dy) { } return true; } - + void movePoint(int n, int dx, int dy) { - // modified by IES to prevent the user dragging points to create zero sized nodes - // that then render improperly - int oldx=x; - int oldy=y; - int oldx2=x2; - int oldy2=y2; - if (noDiagonal) { - if (x == x2) - dx = 0; - else - dy = 0; - } - if (n == 0) { - x += dx; y += dy; - } else { - x2 += dx; y2 += dy; - } - if (x==x2 && y==y2) { - x=oldx; - y=oldy; - x2=oldx2; - y2=oldy2; - } - setPoints(); + // modified by IES to prevent the user dragging points to create zero sized + // nodes + // that then render improperly + int oldx = x; + int oldy = y; + int oldx2 = x2; + int oldy2 = y2; + if (noDiagonal) { + if (x == x2) + dx = 0; + else + dy = 0; + } + if (n == 0) { + x += dx; + y += dy; + } else { + x2 += dx; + y2 += dy; + } + if (x == x2 && y == y2) { + x = oldx; + y = oldy; + x2 = oldx2; + y2 = oldy2; + } + setPoints(); } - + void drawPosts(Graphics g) { - // we normally do this in updateCircuit() now because the logic is more complicated. - // we only handle the case where we have to draw all the posts. That happens when + // we normally do this in updateCircuit() now because the logic is more + // complicated. + // we only handle the case where we have to draw all the posts. That happens + // when // this element is selected or is being created if (sim.dragElm == null && !needsHighlight()) return; - if (sim.mouseMode == CirSim.MODE_DRAG_ROW || - sim.mouseMode == CirSim.MODE_DRAG_COLUMN) + if (sim.mouseMode == CirSim.MODE_DRAG_ROW || sim.mouseMode == CirSim.MODE_DRAG_COLUMN) return; int i; for (i = 0; i != getPostCount(); i++) { @@ -545,72 +610,93 @@ void drawPosts(Graphics g) { drawPost(g, p); } } - + int getNumHandles() { return getPostCount(); } - + void drawHandles(Graphics g, Color c) { - g.setColor(c); - if (lastHandleGrabbed==-1) - g.fillRect(x-3, y-3, 7, 7); - else if (lastHandleGrabbed==0) - g.fillRect(x-4, y-4, 9, 9); - if (getNumHandles() > 1) { - if (lastHandleGrabbed==-1) - g.fillRect(x2-3, y2-3, 7, 7); - else if (lastHandleGrabbed==1) - g.fillRect(x2-4, y2-4, 9, 9); - } + g.setColor(c); + if (lastHandleGrabbed == -1) + g.fillRect(x - 3, y - 3, 7, 7); + else if (lastHandleGrabbed == 0) + g.fillRect(x - 4, y - 4, 9, 9); + if (getNumHandles() > 1) { + if (lastHandleGrabbed == -1) + g.fillRect(x2 - 3, y2 - 3, 7, 7); + else if (lastHandleGrabbed == 1) + g.fillRect(x2 - 4, y2 - 4, 9, 9); + } } - + int getHandleGrabbedClose(int xtest, int ytest, int deltaSq, int minSize) { - lastHandleGrabbed=-1; - if ( Graphics.distanceSq(x , y , x2, y2)>=minSize) { - if (Graphics.distanceSq(x, y, xtest,ytest) <= deltaSq) - lastHandleGrabbed=0; - else if (getNumHandles() > 1 && Graphics.distanceSq(x2, y2, xtest,ytest) <= deltaSq) - lastHandleGrabbed=1; - } - return lastHandleGrabbed; + lastHandleGrabbed = -1; + if (Graphics.distanceSq(x, y, x2, y2) >= minSize) { + if (Graphics.distanceSq(x, y, xtest, ytest) <= deltaSq) + lastHandleGrabbed = 0; + else if (getNumHandles() > 1 && Graphics.distanceSq(x2, y2, xtest, ytest) <= deltaSq) + lastHandleGrabbed = 1; + } + return lastHandleGrabbed; } - - // number of voltage sources this element needs - int getVoltageSourceCount() { return 0; } - - // number of internal nodes (nodes not visible in UI that are needed for implementation) - int getInternalNodeCount() { return 0; } - - // notify this element that its pth node is n. This value n can be passed to stampMatrix() - void setNode(int p, int n) { nodes[p] = n; } - - // notify this element that its nth voltage source is v. This value v can be passed to stampVoltageSource(), etc and will be passed back in calls to setCurrent() + + // number of voltage sources this element needs + int getVoltageSourceCount() { + return 0; + } + + // number of internal nodes (nodes not visible in UI that are needed for + // implementation) + int getInternalNodeCount() { + return 0; + } + + // notify this element that its pth node is n. This value n can be passed to + // stampMatrix() + void setNode(int p, int n) { + nodes[p] = n; + } + + // notify this element that its nth voltage source is v. This value v can be + // passed to stampVoltageSource(), etc and will be passed back in calls to + // setCurrent() void setVoltageSource(int n, int v) { - // default implementation only makes sense for subclasses with one voltage source. If we have 0 this isn't used, if we have >1 this won't work + // default implementation only makes sense for subclasses with one voltage + // source. If we have 0 this isn't used, if we have >1 this won't work voltSource = v; } - -// int getVoltageSource() { return voltSource; } // Never used except for debug code which is commented out - + + // int getVoltageSource() { return voltSource; } // Never used except for debug + // code which is commented out + double getVoltageDiff() { return volts[0] - volts[1]; } - boolean nonLinear() { return false; } - int getPostCount() { return 2; } - + + boolean nonLinear() { + return false; + } + + int getPostCount() { + return 2; + } + // get (global) node number of nth node - int getNode(int n) { return nodes[n]; } - + int getNode(int n) { + return nodes[n]; + } + // get position of nth node Point getPost(int n) { return (n == 0) ? point1 : (n == 1) ? point2 : null; } - - // return post we're connected to (for wires, so we can optimize them out in calculateWireClosure()) + + // return post we're connected to (for wires, so we can optimize them out in + // calculateWireClosure()) Point getConnectedPost() { return point2; } - + int getNodeAtPoint(int xp, int yp) { int i; for (i = 0; i != getPostCount(); i++) { @@ -620,151 +706,166 @@ int getNodeAtPoint(int xp, int yp) { } return 0; } - + /* - void drawPost(Graphics g, int x0, int y0, int n) { - if (sim.dragElm == null && !needsHighlight() && - sim.getCircuitNode(n).links.size() == 2) - return; - if (sim.mouseMode == CirSim.MODE_DRAG_ROW || - sim.mouseMode == CirSim.MODE_DRAG_COLUMN) - return; - drawPost(g, x0, y0); - } - */ + * void drawPost(Graphics g, int x0, int y0, int n) { if (sim.dragElm == null && + * !needsHighlight() && sim.getCircuitNode(n).links.size() == 2) return; if + * (sim.mouseMode == CirSim.MODE_DRAG_ROW || sim.mouseMode == + * CirSim.MODE_DRAG_COLUMN) return; drawPost(g, x0, y0); } + */ static void drawPost(Graphics g, Point pt) { g.setColor(whiteColor); - g.fillOval(pt.x-3, pt.y-3, 7, 7); + g.fillOval(pt.x - 3, pt.y - 3, 7, 7); } - - // set/adjust bounding box used for selecting elements. getCircuitBounds() does not use this! + + // set/adjust bounding box used for selecting elements. getCircuitBounds() does + // not use this! void setBbox(int x1, int y1, int x2, int y2) { - if (x1 > x2) { int q = x1; x1 = x2; x2 = q; } - if (y1 > y2) { int q = y1; y1 = y2; y2 = q; } - boundingBox.setBounds(x1, y1, x2-x1+1, y2-y1+1); + if (x1 > x2) { + int q = x1; + x1 = x2; + x2 = q; + } + if (y1 > y2) { + int q = y1; + y1 = y2; + y2 = q; + } + boundingBox.setBounds(x1, y1, x2 - x1 + 1, y2 - y1 + 1); } - + // set bounding box for an element from p1 to p2 with width w void setBbox(Point p1, Point p2, double w) { setBbox(p1.x, p1.y, p2.x, p2.y); - int dpx = (int) (dpx1*w); - int dpy = (int) (dpy1*w); - adjustBbox(p1.x+dpx, p1.y+dpy, p1.x-dpx, p1.y-dpy); + int dpx = (int) (dpx1 * w); + int dpy = (int) (dpy1 * w); + adjustBbox(p1.x + dpx, p1.y + dpy, p1.x - dpx, p1.y - dpy); } // enlarge bbox to contain an additional rectangle void adjustBbox(int x1, int y1, int x2, int y2) { - if (x1 > x2) { int q = x1; x1 = x2; x2 = q; } - if (y1 > y2) { int q = y1; y1 = y2; y2 = q; } + if (x1 > x2) { + int q = x1; + x1 = x2; + x2 = q; + } + if (y1 > y2) { + int q = y1; + y1 = y2; + y2 = q; + } x1 = min(boundingBox.x, x1); y1 = min(boundingBox.y, y1); - x2 = max(boundingBox.x+boundingBox.width, x2); - y2 = max(boundingBox.y+boundingBox.height, y2); - boundingBox.setBounds(x1, y1, x2-x1, y2-y1); + x2 = max(boundingBox.x + boundingBox.width, x2); + y2 = max(boundingBox.y + boundingBox.height, y2); + boundingBox.setBounds(x1, y1, x2 - x1, y2 - y1); } + void adjustBbox(Point p1, Point p2) { adjustBbox(p1.x, p1.y, p2.x, p2.y); } - - // needed for calculating circuit bounds (need to special-case centered text elements) - boolean isCenteredText() { return false; } - + + // needed for calculating circuit bounds (need to special-case centered text + // elements) + boolean isCenteredText() { + return false; + } + void drawCenteredText(Graphics g, String s, int x, int y, boolean cx) { // FontMetrics fm = g.getFontMetrics(); - //int w = fm.stringWidth(s); -// int w=0; -// if (cx) -// x -= w/2; -// g.drawString(s, x, y+fm.getAscent()/2); -// adjustBbox(x, y-fm.getAscent()/2, -// x+w, y+fm.getAscent()/2+fm.getDescent()); - int w=(int)g.context.measureText(s).getWidth(); - int h2=(int)g.currentFontSize/2; - g.save(); - g.context.setTextBaseline("middle"); - if (cx) { - g.context.setTextAlign("center"); - adjustBbox(x-w/2,y-h2,x+w/2,y+h2); - } else { - adjustBbox(x,y-h2,x+w,y+h2); - } - - if (cx) - g.context.setTextAlign("center"); - g.drawString(s, x, y); - g.restore(); + // int w = fm.stringWidth(s); + // int w=0; + // if (cx) + // x -= w/2; + // g.drawString(s, x, y+fm.getAscent()/2); + // adjustBbox(x, y-fm.getAscent()/2, + // x+w, y+fm.getAscent()/2+fm.getDescent()); + int w = (int) g.context.measureText(s).getWidth(); + int h2 = (int) g.currentFontSize / 2; + g.save(); + g.context.setTextBaseline("middle"); + if (cx) { + g.context.setTextAlign("center"); + adjustBbox(x - w / 2, y - h2, x + w / 2, y + h2); + } else { + adjustBbox(x, y - h2, x + w, y + h2); + } + + if (cx) + g.context.setTextAlign("center"); + g.drawString(s, x, y); + g.restore(); } - - // draw component values (number of resistor ohms, etc). hs = offset + + // draw component values (number of resistor ohms, etc). hs = offset void drawValues(Graphics g, String s, double hs) { if (s == null) return; g.setFont(unitsFont); - //FontMetrics fm = g.getFontMetrics(); - int w = (int)g.context.measureText(s).getWidth(); + // FontMetrics fm = g.getFontMetrics(); + int w = (int) g.context.measureText(s).getWidth(); g.setColor(whiteColor); - int ya = (int)g.currentFontSize/2; + int ya = (int) g.currentFontSize / 2; int xc, yc; if (this instanceof RailElm || this instanceof SweepElm) { xc = x2; yc = y2; } else { - xc = (x2+x)/2; - yc = (y2+y)/2; + xc = (x2 + x) / 2; + yc = (y2 + y) / 2; } - int dpx = (int) (dpx1*hs); - int dpy = (int) (dpy1*hs); + int dpx = (int) (dpx1 * hs); + int dpy = (int) (dpy1 * hs); if (dpx == 0) - g.drawString(s, xc-w/2, yc-abs(dpy)-2); + g.drawString(s, xc - w / 2, yc - abs(dpy) - 2); else { - int xx = xc+abs(dpx)+2; - if (this instanceof VoltageElm || (x < x2 && y > y2)) - xx = xc-(w+abs(dpx)+2); - g.drawString(s, xx, yc+dpy+ya); + int xx = xc + abs(dpx) + 2; + if (this instanceof VoltageElm || (x < x2 && y > y2)) + xx = xc - (w + abs(dpx) + 2); + g.drawString(s, xx, yc + dpy + ya); } } - + void drawLabeledNode(Graphics g, String str, Point pt1, Point pt2) { boolean lineOver = false; if (str.startsWith("/")) { lineOver = true; str = str.substring(1); } - int w=(int)g.context.measureText(str).getWidth(); - int h=(int)g.currentFontSize; - g.save(); - g.context.setTextBaseline("middle"); - int x = pt2.x, y = pt2.y; - if (pt1.y != pt2.y) { - x -= w/2; - y += sign(pt2.y-pt1.y)*h; - } else { - if (pt2.x > pt1.x) - x += 4; - else - x -= 4+w; - } - g.drawString(str, x, y); - adjustBbox(x, y-h/2, x+w, y+h/2); - g.restore(); + int w = (int) g.context.measureText(str).getWidth(); + int h = (int) g.currentFontSize; + g.save(); + g.context.setTextBaseline("middle"); + int x = pt2.x, y = pt2.y; + if (pt1.y != pt2.y) { + x -= w / 2; + y += sign(pt2.y - pt1.y) * h; + } else { + if (pt2.x > pt1.x) + x += 4; + else + x -= 4 + w; + } + g.drawString(str, x, y); + adjustBbox(x, y - h / 2, x + w, y + h / 2); + g.restore(); if (lineOver) { - int ya = y-h/2-1; - g.drawLine(x, ya, x+w, ya); - } - } - - void drawCoil(Graphics g, int hs, Point p1, Point p2, - double v1, double v2) { + int ya = y - h / 2 - 1; + g.drawLine(x, ya, x + w, ya); + } + } + + void drawCoil(Graphics g, int hs, Point p1, Point p2, double v1, double v2) { double len = distance(p1, p2); g.save(); g.context.setLineWidth(3.0); - g.context.transform(((double)(p2.x-p1.x))/len, ((double)(p2.y-p1.y))/len, - -((double)(p2.y-p1.y))/len,((double)(p2.x-p1.x))/len,p1.x,p1.y); - if (sim.voltsCheckItem.getState() ) { - CanvasGradient grad = g.context.createLinearGradient(0,0,len,0); - grad.addColorStop(0, getVoltageColor(g,v1).getHexValue()); - grad.addColorStop(1.0, getVoltageColor(g,v2).getHexValue()); + g.context.transform(((double) (p2.x - p1.x)) / len, ((double) (p2.y - p1.y)) / len, + -((double) (p2.y - p1.y)) / len, ((double) (p2.x - p1.x)) / len, p1.x, p1.y); + if (sim.voltsCheckItem.getState()) { + CanvasGradient grad = g.context.createLinearGradient(0, 0, len, 0); + grad.addColorStop(0, getVoltageColor(g, v1).getHexValue()); + grad.addColorStop(1.0, getVoltageColor(g, v2).getHexValue()); g.context.setStrokeStyle(grad); } g.context.setLineCap(LineCap.ROUND); @@ -772,113 +873,112 @@ void drawCoil(Graphics g, int hs, Point p1, Point p2, int loop; // draw more loops for a longer coil - int loopCt = (int)Math.ceil(len/11); + int loopCt = (int) Math.ceil(len / 11); for (loop = 0; loop != loopCt; loop++) { g.context.beginPath(); - double start = len*loop/loopCt; - g.context.moveTo(start,0); - g.context.arc(len*(loop+.5)/loopCt, 0, len/(2*loopCt), Math.PI, Math.PI*2); - g.context.lineTo(len*(loop+1)/loopCt, 0); + double start = len * loop / loopCt; + g.context.moveTo(start, 0); + g.context.arc(len * (loop + .5) / loopCt, 0, len / (2 * loopCt), Math.PI, Math.PI * 2); + g.context.lineTo(len * (loop + 1) / loopCt, 0); g.context.stroke(); } g.restore(); } - + static void drawThickLine(Graphics g, int x, int y, int x2, int y2) { - g.setLineWidth(3.0); - g.drawLine(x,y,x2,y2); - g.setLineWidth(1.0); + g.setLineWidth(3.0); + g.drawLine(x, y, x2, y2); + g.setLineWidth(1.0); } static void drawThickLine(Graphics g, Point pa, Point pb) { - g.setLineWidth(3.0); - g.drawLine(pa.x, pa.y, pb.x, pb.y); - g.setLineWidth(1.0); + g.setLineWidth(3.0); + g.drawLine(pa.x, pa.y, pb.x, pb.y); + g.setLineWidth(1.0); } static void drawThickPolygon(Graphics g, int xs[], int ys[], int c) { -// int i; -// for (i = 0; i != c-1; i++) -// drawThickLine(g, xs[i], ys[i], xs[i+1], ys[i+1]); -// drawThickLine(g, xs[i], ys[i], xs[0], ys[0]); - g.setLineWidth(3.0); - g.drawPolyline(xs, ys, c); - g.setLineWidth(1.0); + // int i; + // for (i = 0; i != c-1; i++) + // drawThickLine(g, xs[i], ys[i], xs[i+1], ys[i+1]); + // drawThickLine(g, xs[i], ys[i], xs[0], ys[0]); + g.setLineWidth(3.0); + g.drawPolyline(xs, ys, c); + g.setLineWidth(1.0); } - + static void drawThickPolygon(Graphics g, Polygon p) { drawThickPolygon(g, p.xpoints, p.ypoints, p.npoints); } - + static void drawPolygon(Graphics g, Polygon p) { - g.drawPolyline(p.xpoints, p.ypoints, p.npoints); -/* int i; - int xs[] = p.xpoints; - int ys[] = p.ypoints; - int np = p.npoints; - np -= 3; - for (i = 0; i != np-1; i++) - g.drawLine(xs[i], ys[i], xs[i+1], ys[i+1]); - g.drawLine(xs[i], ys[i], xs[0], ys[0]);*/ + g.drawPolyline(p.xpoints, p.ypoints, p.npoints); + /* + * int i; int xs[] = p.xpoints; int ys[] = p.ypoints; int np = p.npoints; np -= + * 3; for (i = 0; i != np-1; i++) g.drawLine(xs[i], ys[i], xs[i+1], ys[i+1]); + * g.drawLine(xs[i], ys[i], xs[0], ys[0]); + */ } - + static void drawThickCircle(Graphics g, int cx, int cy, int ri) { - g.setLineWidth(3.0); - g.context.beginPath(); - g.context.arc(cx, cy, ri*.98, 0, 2*Math.PI); - g.context.stroke(); - g.setLineWidth(1.0); + g.setLineWidth(3.0); + g.context.beginPath(); + g.context.arc(cx, cy, ri * .98, 0, 2 * Math.PI); + g.context.stroke(); + g.setLineWidth(1.0); } - + Polygon getSchmittPolygon(float gsize, float ctr) { Point pts[] = newPointArray(6); - float hs = 3*gsize; - float h1 = 3*gsize; - float h2 = h1*2; + float hs = 3 * gsize; + float h1 = 3 * gsize; + float h2 = h1 * 2; double len = distance(lead1, lead2); - pts[0] = interpPoint(lead1, lead2, ctr-h2/len, hs); - pts[1] = interpPoint(lead1, lead2, ctr+h1/len, hs); - pts[2] = interpPoint(lead1, lead2, ctr+h1/len, -hs); - pts[3] = interpPoint(lead1, lead2, ctr+h2/len, -hs); - pts[4] = interpPoint(lead1, lead2, ctr-h1/len, -hs); - pts[5] = interpPoint(lead1, lead2, ctr-h1/len, hs); - return createPolygon(pts); + pts[0] = interpPoint(lead1, lead2, ctr - h2 / len, hs); + pts[1] = interpPoint(lead1, lead2, ctr + h1 / len, hs); + pts[2] = interpPoint(lead1, lead2, ctr + h1 / len, -hs); + pts[3] = interpPoint(lead1, lead2, ctr + h2 / len, -hs); + pts[4] = interpPoint(lead1, lead2, ctr - h1 / len, -hs); + pts[5] = interpPoint(lead1, lead2, ctr - h1 / len, hs); + return createPolygon(pts); } static String getVoltageDText(double v) { return getUnitText(Math.abs(v), "V"); } + static String getVoltageText(double v) { return getUnitText(v, "V"); } + static String getTimeText(double v) { if (v >= 60) { - double h = Math.floor(v/3600); - v -= 3600*h; - double m = Math.floor(v/60); - v -= 60*m; + double h = Math.floor(v / 3600); + v -= 3600 * h; + double m = Math.floor(v / 60); + v -= 60 * m; if (h == 0) return m + ":" + ((v >= 10) ? "" : "0") + showFormat.format(v); - return h + ":" + ((m >= 10) ? "" : "0") + m + ":" + ((v >= 10) ? "" : "0") + showFormat.format(v); + return h + ":" + ((m >= 10) ? "" : "0") + m + ":" + ((v >= 10) ? "" : "0") + showFormat.format(v); } return getUnitText(v, "s"); } - + static String format(double v, boolean sf) { -// if (sf && Math.abs(v) > 10) -// return shortFormat.format(Math.round(v)); + // if (sf && Math.abs(v) > 10) + // return shortFormat.format(Math.round(v)); return (sf ? shortFormat : showFormat).format(v); } - + static String getUnitText(double v, String u) { - return getUnitText(v,u, false); + return getUnitText(v, u, false); } static String getShortUnitText(double v, String u) { - return getUnitText(v,u, true); + return getUnitText(v, u, true); } - + private static String getUnitText(double v, String u, boolean sf) { String sp = sf ? "" : " "; double va = Math.abs(v); @@ -886,32 +986,35 @@ private static String getUnitText(double v, String u, boolean sf) { // this used to return null, but then wires would display "null" with 0V return "0" + sp + u; if (va < 1e-9) - return format(v*1e12, sf) + sp + "p" + u; + return format(v * 1e12, sf) + sp + "p" + u; if (va < 1e-6) - return format(v*1e9, sf) + sp + "n" + u; + return format(v * 1e9, sf) + sp + "n" + u; if (va < 1e-3) - return format(v*1e6, sf) + sp + Locale.muString + u; + return format(v * 1e6, sf) + sp + Locale.muString + u; if (va < 1) - return format(v*1e3, sf) + sp + "m" + u; + return format(v * 1e3, sf) + sp + "m" + u; if (va < 1e3) return format(v, sf) + sp + u; if (va < 1e6) - return format(v*1e-3, sf) + sp + "k" + u; + return format(v * 1e-3, sf) + sp + "k" + u; if (va < 1e9) - return format(v*1e-6, sf) + sp + "M" + u; + return format(v * 1e-6, sf) + sp + "M" + u; if (va < 1e12) - return format(v*1e-9, sf) + sp + "G" + u; + return format(v * 1e-9, sf) + sp + "G" + u; return NumberFormat.getFormat("#.##E000").format(v) + sp + u; } - + static String getCurrentText(double i) { return getUnitText(i, "A"); } + static String getCurrentDText(double i) { return getUnitText(Math.abs(i), "A"); } - static String getUnitTextWithScale(double val, String utext, int scale) { return getUnitTextWithScale(val, utext, scale, false); } + static String getUnitTextWithScale(double val, String utext, int scale) { + return getUnitTextWithScale(val, utext, scale, false); + } static String getUnitTextWithScale(double val, String utext, int scale, boolean fixed) { if (Math.abs(val) > 1e12) @@ -920,23 +1023,25 @@ static String getUnitTextWithScale(double val, String utext, int scale, boolean if (scale == SCALE_1) return nf.format(val) + " " + utext; if (scale == SCALE_M) - return nf.format(1e3*val) + " m" + utext; + return nf.format(1e3 * val) + " m" + utext; if (scale == SCALE_MU) - return nf.format(1e6*val) + " " + Locale.muString + utext; + return nf.format(1e6 * val) + " " + Locale.muString + utext; return getUnitText(val, utext); } - // update dot positions (curcount) for drawing current (simple case for single current) + // update dot positions (curcount) for drawing current (simple case for single + // current) void updateDotCount() { curcount = updateDotCount(current, curcount); } - // update dot positions (curcount) for drawing current (general case for multiple currents) + // update dot positions (curcount) for drawing current (general case for + // multiple currents) double updateDotCount(double cur, double cc) { - - if (!sim.simIsRunning()) + + if (!sim.simIsRunning()) return cc; - double cadd = cur*currentMult; + double cadd = cur * currentMult; if (cadd > 6 || cadd < -6) return CURRENT_TOO_FAST; if (cc == CURRENT_TOO_FAST) @@ -944,180 +1049,251 @@ void updateDotCount() { cadd %= 8; return cc + cadd; } - + // update and draw current for simple two-terminal element void doDots(Graphics g) { updateDotCount(); if (sim.dragElm != this) drawDots(g, point1, point2, curcount); } - - void doAdjust() {} - void setupAdjust() {} - + + void doAdjust() { + } + + void setupAdjust() { + } + // get component info for display in lower right void getInfo(String arr[]) { } - + int getBasicInfo(String arr[]) { arr[1] = "I = " + getCurrentDText(getCurrent()); arr[2] = "Vd = " + getVoltageDText(getVoltageDiff()); return 3; } + String getScopeText(int v) { - String info[] = new String[10]; - getInfo(info); - return info[0]; + String info[] = new String[10]; + getInfo(info); + return info[0]; } - + Color getVoltageColor(Graphics g, double volts) { - if (needsHighlight()) { - return (selectColor); - } - if (!sim.voltsCheckItem.getState()) { - return(whiteColor); - } - int c = (int) ((volts+voltageRange)*(colorScaleCount-1)/ - (voltageRange*2)); - if (c < 0) - c = 0; - if (c >= colorScaleCount) - c = colorScaleCount-1; - return (colorScale[c]); + if (needsHighlight()) { + return (selectColor); + } + if (!sim.voltsCheckItem.getState()) { + return (whiteColor); + } + int c = (int) ((volts + voltageRange) * (colorScaleCount - 1) / (voltageRange * 2)); + if (c < 0) + c = 0; + if (c >= colorScaleCount) + c = colorScaleCount - 1; + return (colorScale[c]); } - + void setVoltageColor(Graphics g, double volts) { - g.setColor(getVoltageColor(g, volts)); + g.setColor(getVoltageColor(g, volts)); } - + // yellow argument is unused, can't remember why it was there void setPowerColor(Graphics g, boolean yellow) { - /*if (conductanceCheckItem.getState()) { - setConductanceColor(g, current/getVoltageDiff()); - return; - }*/ - if (!sim.powerCheckItem.getState() ) + /* + * if (conductanceCheckItem.getState()) { setConductanceColor(g, + * current/getVoltageDiff()); return; } + */ + if (!sim.powerCheckItem.getState()) return; setPowerColor(g, getPower()); } - + void setPowerColor(Graphics g, double w0) { - if (!sim.powerCheckItem.getState() ) + if (!sim.powerCheckItem.getState()) return; - if (needsHighlight()) { - g.setColor(selectColor); - return; - } + if (needsHighlight()) { + g.setColor(selectColor); + return; + } w0 *= powerMult; - //System.out.println(w); - int i = (int) ((colorScaleCount/2)+(colorScaleCount/2)*-w0); - if (i<0) - i=0; - if (i>=colorScaleCount) - i=colorScaleCount-1; - g.setColor(colorScale[i]); + // System.out.println(w); + int i = (int) ((colorScaleCount / 2) + (colorScaleCount / 2) * -w0); + if (i < 0) + i = 0; + if (i >= colorScaleCount) + i = colorScaleCount - 1; + g.setColor(colorScale[i]); } + void setConductanceColor(Graphics g, double w0) { w0 *= powerMult; - //System.out.println(w); + // System.out.println(w); double w = (w0 < 0) ? -w0 : w0; if (w > 1) w = 1; - int rg = (int) (w*255); + int rg = (int) (w * 255); g.setColor(new Color(rg, rg, rg)); } - double getPower() { return getVoltageDiff()*current; } + + double getPower() { + return getVoltageDiff() * current; + } + double getScopeValue(int x) { - return (x == Scope.VAL_CURRENT) ? getCurrent() : - (x == Scope.VAL_POWER) ? getPower() : getVoltageDiff(); + return (x == Scope.VAL_CURRENT) ? getCurrent() : (x == Scope.VAL_POWER) ? getPower() : getVoltageDiff(); } + int getScopeUnits(int x) { - return (x == Scope.VAL_CURRENT) ? Scope.UNITS_A : - (x == Scope.VAL_POWER) ? Scope.UNITS_W : Scope.UNITS_V; + return (x == Scope.VAL_CURRENT) ? Scope.UNITS_A : (x == Scope.VAL_POWER) ? Scope.UNITS_W : Scope.UNITS_V; } - public EditInfo getEditInfo(int n) { return null; } - public void setEditValue(int n, EditInfo ei) {} - + + public EditInfo getEditInfo(int n) { + return null; + } + + public void setEditValue(int n, EditInfo ei) { + } + // get number of nodes that can be retrieved by getConnectionNode() - int getConnectionNodeCount() { return getPostCount(); } - - // get nodes that can be passed to getConnection(), to test if this element connects + int getConnectionNodeCount() { + return getPostCount(); + } + + // get nodes that can be passed to getConnection(), to test if this element + // connects // those two nodes; this is the same as getNode() for all but labeled nodes. - int getConnectionNode(int n) { return getNode(n); } - - // are n1 and n2 connected by this element? this is used to determine + int getConnectionNode(int n) { + return getNode(n); + } + + // are n1 and n2 connected by this element? this is used to determine // unconnected nodes, and look for loops - boolean getConnection(int n1, int n2) { return true; } - + boolean getConnection(int n1, int n2) { + return true; + } + // is n1 connected to ground somehow? - boolean hasGroundConnection(int n1) { return false; } - - // is this a wire or equivalent to a wire? (used for circuit validation) - boolean isWireEquivalent() { return false; } - + boolean hasGroundConnection(int n1) { + return false; + } + + // is this a wire or equivalent to a wire? (used for circuit validation) + boolean isWireEquivalent() { + return false; + } + // is this a wire we can remove? - boolean isRemovableWire() { return false; } - - boolean canViewInScope() { return getPostCount() <= 2; } + boolean isRemovableWire() { + return false; + } + + boolean canViewInScope() { + return getPostCount() <= 2; + } + boolean comparePair(int x1, int x2, int y1, int y2) { return ((x1 == y1 && x2 == y2) || (x1 == y2 && x2 == y1)); } - boolean needsHighlight() { - return mouseElmRef==this || selected || sim.plotYElm == this || - // Test if the current mouseElm is a ScopeElm and, if so, does it belong to this elm - (mouseElmRef instanceof ScopeElm && ((ScopeElm) mouseElmRef).elmScope.getElm()==this); + + boolean needsHighlight() { + return mouseElmRef == this || selected || sim.plotYElm == this || + // Test if the current mouseElm is a ScopeElm and, if so, does it belong to this + // elm + (mouseElmRef instanceof ScopeElm && ((ScopeElm) mouseElmRef).elmScope.getElm() == this); + } + + boolean isSelected() { + return selected; + } + + boolean canShowValueInScope(int v) { + return false; } - boolean isSelected() { return selected; } - boolean canShowValueInScope(int v) { return false; } - void setSelected(boolean x) { selected = x; } + + void setSelected(boolean x) { + selected = x; + } + void selectRect(Rectangle r, boolean add) { if (r.intersects(boundingBox)) selected = true; else if (!add) selected = false; } - static int abs(int x) { return x < 0 ? -x : x; } - static int sign(int x) { return (x < 0) ? -1 : (x == 0) ? 0 : 1; } - static int min(int a, int b) { return (a < b) ? a : b; } - static int max(int a, int b) { return (a > b) ? a : b; } + + static int abs(int x) { + return x < 0 ? -x : x; + } + + static int sign(int x) { + return (x < 0) ? -1 : (x == 0) ? 0 : 1; + } + + static int min(int a, int b) { + return (a < b) ? a : b; + } + + static int max(int a, int b) { + return (a > b) ? a : b; + } + static double distance(Point p1, Point p2) { - double x = p1.x-p2.x; - double y = p1.y-p2.y; - return Math.sqrt(x*x+y*y); + double x = p1.x - p2.x; + double y = p1.y - p2.y; + return Math.sqrt(x * x + y * y); + } + + Rectangle getBoundingBox() { + return boundingBox; + } + + boolean needsShortcut() { + return getShortcut() > 0; + } + + int getShortcut() { + return 0; + } + + boolean isGraphicElmt() { + return false; } - Rectangle getBoundingBox() { return boundingBox; } - boolean needsShortcut() { return getShortcut() > 0; } - int getShortcut() { return 0; } - boolean isGraphicElmt() { return false; } - void setMouseElm(boolean v) { if (v) - mouseElmRef=this; - else if (mouseElmRef==this) - mouseElmRef=null; + mouseElmRef = this; + else if (mouseElmRef == this) + mouseElmRef = null; } - void draggingDone() {} - - String dumpModel() { return null; } - + + void draggingDone() { + } + + String dumpModel() { + return null; + } + boolean isMouseElm() { - return mouseElmRef==this; + return mouseElmRef == this; } - - void updateModels() {} - void stepFinished() {} - + + void updateModels() { + } + + void stepFinished() { + } + // get current flowing into node n out of this element double getCurrentIntoNode(int n) { // if we take out the getPostCount() == 2 it gives the wrong value for rails - if (n==0 && getPostCount() == 2) + if (n == 0 && getPostCount() == 2) return -current; else return current; } - + void flipPosts() { int oldx = x; int oldy = y; @@ -1127,11 +1303,13 @@ void flipPosts() { y2 = oldy; setPoints(); } - - String getClassName() { return getClass().getName().replace("com.lushprojects.circuitjs1.client.", ""); } - + + String getClassName() { + return getClass().getName().replace("com.lushprojects.circuitjs1.client.", ""); + } + native JsArrayString getJsArrayString() /*-{ return []; }-*/; - + JsArrayString getInfoJS() { JsArrayString jsarr = getJsArrayString(); String arr[] = new String[20]; @@ -1141,13 +1319,13 @@ JsArrayString getInfoJS() { jsarr.push(arr[i]); return jsarr; } - + double getVoltageJS(int n) { if (n >= volts.length) return 0; return volts[n]; } - + native void addJSMethods() /*-{ var that = this; this.getType = $entry(function() { return that.@com.lushprojects.circuitjs1.client.CircuitElm::getClassName()(); }); @@ -1158,7 +1336,7 @@ native void addJSMethods() /*-{ this.getLabelName = $entry(function() { return that.@com.lushprojects.circuitjs1.client.LabeledNodeElm::getName()(); }); this.getPostCount = $entry(function() { return that.@com.lushprojects.circuitjs1.client.CircuitElm::getPostCount()(); }); }-*/; - + native JavaScriptObject getJavaScriptObject() /*-{ return this; }-*/; - + } diff --git a/src/com/lushprojects/circuitjs1/client/CircuitNode.java b/src/com/lushprojects/circuitjs1/client/CircuitNode.java index f89dd84d..3871d7b3 100644 --- a/src/com/lushprojects/circuitjs1/client/CircuitNode.java +++ b/src/com/lushprojects/circuitjs1/client/CircuitNode.java @@ -24,5 +24,8 @@ class CircuitNode { Vector links; boolean internal; - CircuitNode() { links = new Vector(); } + + CircuitNode() { + links = new Vector(); + } } diff --git a/src/com/lushprojects/circuitjs1/client/CircuitNodeLink.java b/src/com/lushprojects/circuitjs1/client/CircuitNodeLink.java index 3049acf0..e37cd694 100644 --- a/src/com/lushprojects/circuitjs1/client/CircuitNodeLink.java +++ b/src/com/lushprojects/circuitjs1/client/CircuitNodeLink.java @@ -20,6 +20,6 @@ package com.lushprojects.circuitjs1.client; class CircuitNodeLink { - int num; - CircuitElm elm; - } + int num; + CircuitElm elm; +} diff --git a/src/com/lushprojects/circuitjs1/client/ClockElm.java b/src/com/lushprojects/circuitjs1/client/ClockElm.java index 527413d6..8d46b236 100644 --- a/src/com/lushprojects/circuitjs1/client/ClockElm.java +++ b/src/com/lushprojects/circuitjs1/client/ClockElm.java @@ -20,13 +20,19 @@ package com.lushprojects.circuitjs1.client; class ClockElm extends RailElm { - public ClockElm(int xx, int yy) { - super(xx, yy, WF_SQUARE); - maxVoltage = 2.5; - bias = 2.5; - frequency = 100; - flags |= FLAG_CLOCK; - } - Class getDumpClass() { return RailElm.class; } - int getShortcut() { return 0; } + public ClockElm(int xx, int yy) { + super(xx, yy, WF_SQUARE); + maxVoltage = 2.5; + bias = 2.5; + frequency = 100; + flags |= FLAG_CLOCK; } + + Class getDumpClass() { + return RailElm.class; + } + + int getShortcut() { + return 0; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/Color.java b/src/com/lushprojects/circuitjs1/client/Color.java index 61bf86a3..3b6a3478 100644 --- a/src/com/lushprojects/circuitjs1/client/Color.java +++ b/src/com/lushprojects/circuitjs1/client/Color.java @@ -19,8 +19,7 @@ package com.lushprojects.circuitjs1.client; -public class Color -{ +public class Color { public final static Color white = new Color(255, 255, 255); public final static Color lightGray = new Color(192, 192, 192); public final static Color gray = new Color(128, 128, 128); @@ -37,82 +36,72 @@ public class Color public final static Color cyan = new Color(0, 255, 255); public final static Color blue = new Color(0, 0, 255); public static final Color NONE = new Color(""); - + private int r, g, b; - + // only for special cases, like no color, or maybe named colors private String colorText = null; - public Color (String colorText) { - this.colorText = colorText; - if (colorText.startsWith("#") && colorText.length() == 7) { - String rs = colorText.substring(1, 3); - String gs = colorText.substring(3, 5); - String bs = colorText.substring(5, 7); - r = Integer.parseInt(rs, 16); - g = Integer.parseInt(gs, 16); - b = Integer.parseInt(bs, 16); - } + public Color(String colorText) { + this.colorText = colorText; + if (colorText.startsWith("#") && colorText.length() == 7) { + String rs = colorText.substring(1, 3); + String gs = colorText.substring(3, 5); + String bs = colorText.substring(5, 7); + r = Integer.parseInt(rs, 16); + g = Integer.parseInt(gs, 16); + b = Integer.parseInt(bs, 16); + } } // create mixture of c1 and c2 - public Color (Color c1, Color c2, double mix) { - double m0 = 1-mix; - this.r = (int) (c1.r*m0 + c2.r*mix); - this.g = (int) (c1.g*m0 + c2.g*mix); - this.b = (int) (c1.b*m0 + c2.b*mix); + public Color(Color c1, Color c2, double mix) { + double m0 = 1 - mix; + this.r = (int) (c1.r * m0 + c2.r * mix); + this.g = (int) (c1.g * m0 + c2.g * mix); + this.b = (int) (c1.b * m0 + c2.b * mix); } - - public Color (int r, int g, int b) - { - this.r = r; - this.g = g; - this.b = b; + + public Color(int r, int g, int b) { + this.r = r; + this.g = g; + this.b = b; } - public int getRed () - { - return r; + public int getRed() { + return r; } - public int getGreen () - { - return g; + public int getGreen() { + return g; } - public int getBlue () - { - return b; + public int getBlue() { + return b; } - public String getHexValue () - { - if (colorText != null) { - return colorText; - } + public String getHexValue() { + if (colorText != null) { + return colorText; + } - return "#" - + pad(Integer.toHexString(r)) - + pad(Integer.toHexString(g)) - + pad(Integer.toHexString(b)); + return "#" + pad(Integer.toHexString(r)) + pad(Integer.toHexString(g)) + pad(Integer.toHexString(b)); } - private String pad (String in) - { - if (in.length() == 0) { - return "00"; - } - if (in.length() == 1) { - return "0" + in; - } - return in; + private String pad(String in) { + if (in.length() == 0) { + return "00"; + } + if (in.length() == 1) { + return "0" + in; + } + return in; } - public String toString () - { - if (colorText != null) { - return colorText; - } - return "red=" + r + ", green=" + g + ", blue=" + b; + public String toString() { + if (colorText != null) { + return colorText; + } + return "red=" + r + ", green=" + g + ", blue=" + b; } } \ No newline at end of file diff --git a/src/com/lushprojects/circuitjs1/client/ComparatorElm.java b/src/com/lushprojects/circuitjs1/client/ComparatorElm.java index 083024da..ee3ab5c9 100644 --- a/src/com/lushprojects/circuitjs1/client/ComparatorElm.java +++ b/src/com/lushprojects/circuitjs1/client/ComparatorElm.java @@ -1,96 +1,92 @@ package com.lushprojects.circuitjs1.client; - - - public class ComparatorElm extends CompositeElm { - + private static String modelString = "OpAmpElm 1 2 3\rAnalogSwitchElm 4 5 3\rGroundElm 5"; - private static int[] modelExternalNodes = {2, 1, 4}; + private static int[] modelExternalNodes = { 2, 1, 4 }; final int FLAG_SMALL = 2; int opsize, opheight, opwidth; - Point in1p[], in2p[], textp[]; - Polygon triangle; - Font plusFont; - + Point in1p[], in2p[], textp[]; + Polygon triangle; + Font plusFont; + public ComparatorElm(int xx, int yy) { super(xx, yy, modelString, modelExternalNodes); noDiagonal = true; setSize(sim.smallGridCheckItem.getState() ? 1 : 2); } - public ComparatorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st, modelString, modelExternalNodes); noDiagonal = true; setSize((f & FLAG_SMALL) != 0 ? 1 : 2); } - + public int getDumpType() { return 401; } - - void setSize(int s) { - opsize = s; - opheight = 8*s; - opwidth = 13*s; - flags = (flags & ~FLAG_SMALL) | ((s == 1) ? FLAG_SMALL : 0); - } - - public boolean getConnection(int n1, int n2) { return false; } - - void draw(Graphics g) { - setBbox(point1, point2, opheight*2); - setVoltageColor(g, volts[0]); - drawThickLine(g, in1p[0], in1p[1]); - setVoltageColor(g, volts[1]); - drawThickLine(g, in2p[0], in2p[1]); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - setPowerColor(g, true); - drawThickPolygon(g, triangle); - g.setFont(plusFont); - drawCenteredText(g, "-", textp[0].x, textp[0].y-2, true); - drawCenteredText(g, "+", textp[1].x, textp[1].y , true); - drawCenteredText(g, "\u2265?", textp[2].x, textp[2].y , true); - setVoltageColor(g, volts[2]); - drawThickLine(g, lead2, point2); - curcount = updateDotCount(-getCurrentIntoNode(2), curcount); - drawDots(g, point2, lead2, curcount); - drawPosts(g); - } - void setPoints() { - super.setPoints(); - if (dn > 150 && this == sim.dragElm) - setSize(2); - int ww = opwidth; - if (ww > dn/2) - ww = (int) (dn/2); - calcLeads(ww*2); - int hs = opheight*dsign; -// if ((flags & FLAG_SWAP) != 0) -// hs = -hs; - in1p = newPointArray(2); - in2p = newPointArray(2); - textp = newPointArray(3); - interpPoint2(point1, point2, in1p[0], in2p[0], 0, hs); - interpPoint2(lead1 , lead2, in1p[1], in2p[1], 0, hs); - interpPoint2(lead1 , lead2, textp[0], textp[1], .2, hs); - interpPoint(lead1, lead2, textp[2], 0.5, 0); - Point tris[] = newPointArray(2); - interpPoint2(lead1, lead2, tris[0], tris[1], 0, hs*2); - triangle = createPolygon(tris[0], tris[1], lead2); - plusFont = new Font("SansSerif", 0, opsize == 2 ? 14 : 10); - setPost(0, in1p[0]); - setPost(1,in2p[0]); - setPost(2,point2); - } - - - + void setSize(int s) { + opsize = s; + opheight = 8 * s; + opwidth = 13 * s; + flags = (flags & ~FLAG_SMALL) | ((s == 1) ? FLAG_SMALL : 0); + } + + public boolean getConnection(int n1, int n2) { + return false; + } + + void draw(Graphics g) { + setBbox(point1, point2, opheight * 2); + setVoltageColor(g, volts[0]); + drawThickLine(g, in1p[0], in1p[1]); + setVoltageColor(g, volts[1]); + drawThickLine(g, in2p[0], in2p[1]); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + setPowerColor(g, true); + drawThickPolygon(g, triangle); + g.setFont(plusFont); + drawCenteredText(g, "-", textp[0].x, textp[0].y - 2, true); + drawCenteredText(g, "+", textp[1].x, textp[1].y, true); + drawCenteredText(g, "\u2265?", textp[2].x, textp[2].y, true); + setVoltageColor(g, volts[2]); + drawThickLine(g, lead2, point2); + curcount = updateDotCount(-getCurrentIntoNode(2), curcount); + drawDots(g, point2, lead2, curcount); + drawPosts(g); + } + + void setPoints() { + super.setPoints(); + if (dn > 150 && this == sim.dragElm) + setSize(2); + int ww = opwidth; + if (ww > dn / 2) + ww = (int) (dn / 2); + calcLeads(ww * 2); + int hs = opheight * dsign; + // if ((flags & FLAG_SWAP) != 0) + // hs = -hs; + in1p = newPointArray(2); + in2p = newPointArray(2); + textp = newPointArray(3); + interpPoint2(point1, point2, in1p[0], in2p[0], 0, hs); + interpPoint2(lead1, lead2, in1p[1], in2p[1], 0, hs); + interpPoint2(lead1, lead2, textp[0], textp[1], .2, hs); + interpPoint(lead1, lead2, textp[2], 0.5, 0); + Point tris[] = newPointArray(2); + interpPoint2(lead1, lead2, tris[0], tris[1], 0, hs * 2); + triangle = createPolygon(tris[0], tris[1], lead2); + plusFont = new Font("SansSerif", 0, opsize == 2 ? 14 : 10); + setPost(0, in1p[0]); + setPost(1, in2p[0]); + setPost(2, point2); + } + void getInfo(String arr[]) { - arr[0] = "Comparator"; - arr[1] = "V+ = " + getVoltageText(volts[1]); - arr[2] = "V- = " + getVoltageText(volts[0]); + arr[0] = "Comparator"; + arr[1] = "V+ = " + getVoltageText(volts[1]); + arr[2] = "V- = " + getVoltageText(volts[0]); } } diff --git a/src/com/lushprojects/circuitjs1/client/CompositeElm.java b/src/com/lushprojects/circuitjs1/client/CompositeElm.java index 9bc1bc72..7cda02b0 100644 --- a/src/com/lushprojects/circuitjs1/client/CompositeElm.java +++ b/src/com/lushprojects/circuitjs1/client/CompositeElm.java @@ -20,15 +20,17 @@ public abstract class CompositeElm extends CircuitElm { - // need to use escape() instead of converting spaces to _'s so composite elements can be nested + // need to use escape() instead of converting spaces to _'s so composite + // elements can be nested final int FLAG_ESCAPE = 1; - + // list of elements contained in this subcircuit Vector compElmList; - - // list of nodes, mapping each one to a list of elements that reference that node + + // list of nodes, mapping each one to a list of elements that reference that + // node protected Vector compNodeList; - + protected int numPosts = 0; protected int numNodes = 0; protected Point posts[]; @@ -37,11 +39,11 @@ public abstract class CompositeElm extends CircuitElm { CompositeElm(int xx, int yy) { super(xx, yy); } - + public CompositeElm(int xa, int ya, int xb, int yb, int f) { super(xa, ya, xb, yb, f); } - + CompositeElm(int xx, int yy, String s, int externalNodes[]) { super(xx, yy); loadComposite(null, s, externalNodes); @@ -54,8 +56,10 @@ public CompositeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st, S allocNodes(); } - boolean useEscape() { return (flags & FLAG_ESCAPE) != 0; } - + boolean useEscape() { + return (flags & FLAG_ESCAPE) != 0; + } + public void loadComposite(StringTokenizer stIn, String model, int externalNodes[]) { HashMap compNodeHash = new HashMap(); StringTokenizer modelLinet = new StringTokenizer(model, "\r"); @@ -74,13 +78,13 @@ public void loadComposite(StringTokenizer stIn, String model, int externalNodes[ StringTokenizer stModel = new StringTokenizer(line, " +\t\n\r\f"); String ceType = stModel.nextToken(); CircuitElm newce = CirSim.constructElement(ceType, 0, 0); - if (stIn!=null) { + if (stIn != null) { int tint = newce.getDumpType(); - String dumpedCe= stIn.nextToken(); + String dumpedCe = stIn.nextToken(); if (useEscape()) dumpedCe = CustomLogicModel.unescape(dumpedCe); StringTokenizer stCe = new StringTokenizer(dumpedCe, useEscape() ? " " : "_"); - int flags = new Integer(stCe.nextToken()).intValue(); + int flags = Integer.valueOf(stCe.nextToken()).intValue(); newce = CirSim.createCe(tint, 0, 0, 0, 0, flags, stCe); } if (newce instanceof GroundElm) @@ -89,7 +93,7 @@ public void loadComposite(StringTokenizer stIn, String model, int externalNodes[ int thisPost = 0; while (stModel.hasMoreTokens()) { - int nodeOfThisPost = new Integer(stModel.nextToken()).intValue(); + int nodeOfThisPost = Integer.valueOf(stModel.nextToken()).intValue(); // node = 0 means ground if (nodeOfThisPost == 0) { @@ -143,24 +147,25 @@ public void loadComposite(StringTokenizer stIn, String model, int externalNodes[ numNodes = compNodeList.size(); -// CirSim.console("Dumping compNodeList"); -// for (int i = 0; i < numNodes; i++) { -// CirSim.console("New node" + i + " Size of links:" + compNodeList.get(i).links.size()); -// } + // CirSim.console("Dumping compNodeList"); + // for (int i = 0; i < numNodes; i++) { + // CirSim.console("New node" + i + " Size of links:" + + // compNodeList.get(i).links.size()); + // } posts = new Point[numPosts]; - + // Enumerate voltage sources for (int i = 0; i < compElmList.size(); i++) { int cnt = compElmList.get(i).getVoltageSourceCount(); - for (int j=0;j < cnt ; j++) { + for (int j = 0; j < cnt; j++) { vsRecord = new VoltageSourceRecord(); vsRecord.elm = compElmList.get(i); vsRecord.vsNumForElement = j; voltageSources.add(vsRecord); } } - + // dump new circuits with escape() flags |= FLAG_ESCAPE; } @@ -173,7 +178,7 @@ public boolean nonLinear() { } public String dump() { - String dumpStr=super.dump(); + String dumpStr = super.dump(); dumpStr += dumpElements(); return dumpStr; } @@ -182,26 +187,29 @@ public String dumpElements() { String dumpStr = ""; for (int i = 0; i < compElmList.size(); i++) { String tstring = compElmList.get(i).dump(); - tstring = tstring.replaceFirst("[A-Za-z0-9]+ 0 0 0 0 ", ""); // remove unused tint x1 y1 x2 y2 coords for internal components - dumpStr += " "+ CustomLogicModel.escape(tstring); + tstring = tstring.replaceFirst("[A-Za-z0-9]+ 0 0 0 0 ", ""); // remove unused tint x1 y1 x2 y2 coords for + // internal components + dumpStr += " " + CustomLogicModel.escape(tstring); } return dumpStr; } - // dump subset of elements (some of them may not have any state, and/or may be very long, so we avoid dumping them for brevity) + // dump subset of elements (some of them may not have any state, and/or may be + // very long, so we avoid dumping them for brevity) public String dumpWithMask(int mask) { - String dumpStr=super.dump(); + String dumpStr = super.dump(); return dumpStr + dumpElements(mask); } public String dumpElements(int mask) { String dumpStr = ""; for (int i = 0; i < compElmList.size(); i++) { - if ((mask & (1< cnLinks = compNodeList.get(n).links; for (int j = 0; j < cnLinks.size(); j++) { @@ -241,7 +249,7 @@ public boolean getConnection(int n1, int n2) { } return false; } - + // is n1 connected to ground somehow? public boolean hasGroundConnection(int n1) { Vector connectedNodes = new Vector(); @@ -251,7 +259,7 @@ public boolean hasGroundConnection(int n1) { int i; for (i = 0; i < connectedNodes.size(); i++) { // next node in list - int n = connectedNodes.get(i); + int n = connectedNodes.get(i); // find all elements connected to n Vector cnLinks = compNodeList.get(n).links; for (int j = 0; j < cnLinks.size(); j++) { @@ -278,7 +286,7 @@ public boolean hasGroundConnection(int n1) { public void reset() { for (int i = 0; i < compElmList.size(); i++) compElmList.get(i).reset(); - } + } int getPostCount() { return numPosts; @@ -321,7 +329,7 @@ public void startIteration() { for (int i = 0; i < compElmList.size(); i++) compElmList.get(i).startIteration(); } - + public void doStep() { for (int i = 0; i < compElmList.size(); i++) compElmList.get(i).doStep(); @@ -339,7 +347,7 @@ public void setNode(int p, int n) { super.setNode(p, n); cnLinks = compNodeList.get(p).links; - // call setNode() for all elements that use that node + // call setNode() for all elements that use that node for (int i = 0; i < cnLinks.size(); i++) { cnLinks.get(i).elm.setNode(cnLinks.get(i).num, n); } @@ -354,7 +362,7 @@ public void setNodeVoltage(int n, double c) { for (int i = 0; i < cnLinks.size(); i++) { cnLinks.get(i).elm.setNodeVoltage(cnLinks.get(i).num, c); } - volts[n]=c; + volts[n] = c; } public boolean canViewInScope() { @@ -364,7 +372,7 @@ public boolean canViewInScope() { public void delete() { for (int i = 0; i < compElmList.size(); i++) compElmList.get(i).delete(); - super.delete(); + super.delete(); } public int getVoltageSourceCount() { @@ -377,35 +385,34 @@ public int getVoltageSourceCount() { void setVoltageSource(int n, int v) { // voltSource(n) = v; VoltageSourceRecord vsr; - vsr=voltageSources.get(n); + vsr = voltageSources.get(n); vsr.elm.setVoltageSource(vsr.vsNumForElement, v); - vsr.vsNode=v; + vsr.vsNode = v; } - + @Override - public void setCurrent(int vsn, double c) { - for (int i=0;i cnLinks; cnLinks = compNodeList.get(n).links; for (int i = 0; i < cnLinks.size(); i++) { - c+=cnLinks.get(i).elm.getCurrentIntoNode(cnLinks.get(i).num); + c += cnLinks.get(i).elm.getCurrentIntoNode(cnLinks.get(i).num); } return c; } } - class VoltageSourceRecord { - int vsNumForElement; - int vsNode; - CircuitElm elm; + int vsNumForElement; + int vsNode; + CircuitElm elm; } diff --git a/src/com/lushprojects/circuitjs1/client/Counter2Elm.java b/src/com/lushprojects/circuitjs1/client/Counter2Elm.java index 412879a1..1e90d7cf 100644 --- a/src/com/lushprojects/circuitjs1/client/Counter2Elm.java +++ b/src/com/lushprojects/circuitjs1/client/Counter2Elm.java @@ -22,127 +22,139 @@ import com.lushprojects.circuitjs1.client.util.Locale; class Counter2Elm extends ChipElm { - int modulus; + int modulus; - public Counter2Elm(int xx, int yy) { - super(xx, yy); - } + public Counter2Elm(int xx, int yy) { + super(xx, yy); + } - public Counter2Elm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - try { - modulus = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + public Counter2Elm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + try { + modulus = Integer.parseInt(st.nextToken()); + } catch (Exception e) { } + } - String dump() { - return super.dump() + " " + modulus; - } + String dump() { + return super.dump() + " " + modulus; + } - boolean needsBits() { return true; } - String getChipName() { - if (modulus == 0) - return "Counter"; - return Locale.LS("Counter") + Locale.LS(" (mod ") + modulus + ")"; - } - - int clk, clr, enp, ent, rco, load; - - void setupPins() { - sizeX = 2; - sizeY = bits+3; - pins = new Pin[getPostCount()]; - int i; - for (i = 0; i != bits; i++) { - pins[i] = new Pin(i+1, SIDE_E, "Q" + (bits-i-1)); - pins[i].output = pins[i].state = true; - } - for (i = 0; i != bits; i++) { - int ii = i+bits; - pins[ii] = new Pin(i+1, SIDE_W, "I" + (bits-i-1)); - } - int p = bits*2; - clk = p; - clr = p+1; - enp = p+2; - rco = p+3; - load = p+4; - ent = p+5; - pins[clk] = new Pin(0, SIDE_W, ""); - pins[clk].clock = true; - pins[clr] = new Pin(bits+1, SIDE_W, "CLR"); - pins[clr].bubble = true; - pins[enp] = new Pin(bits+2, SIDE_W, "EnP"); - pins[rco] = new Pin(0, SIDE_E, "RCO"); - pins[rco].output = true; - pins[load] = new Pin(bits+1, SIDE_E, "LOAD"); - pins[load].bubble = true; - pins[ent] = new Pin(bits+2, SIDE_E, "EnT"); - } - int getPostCount() { - return bits*2+6; + boolean needsBits() { + return true; + } + + String getChipName() { + if (modulus == 0) + return "Counter"; + return Locale.LS("Counter") + Locale.LS(" (mod ") + modulus + ")"; + } + + int clk, clr, enp, ent, rco, load; + + void setupPins() { + sizeX = 2; + sizeY = bits + 3; + pins = new Pin[getPostCount()]; + int i; + for (i = 0; i != bits; i++) { + pins[i] = new Pin(i + 1, SIDE_E, "Q" + (bits - i - 1)); + pins[i].output = pins[i].state = true; } - public EditInfo getChipEditInfo(int n) { - if (n == 0) - return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); - if (n == 1) - return new EditInfo("Modulus", modulus, 1, 1).setDimensionless(); - return null; + for (i = 0; i != bits; i++) { + int ii = i + bits; + pins[ii] = new Pin(i + 1, SIDE_W, "I" + (bits - i - 1)); } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value >= 2) { - bits = (int)ei.value; - setupPins(); - setPoints(); - allocNodes(); - } - if (n == 1) - modulus = (int)ei.value; + int p = bits * 2; + clk = p; + clr = p + 1; + enp = p + 2; + rco = p + 3; + load = p + 4; + ent = p + 5; + pins[clk] = new Pin(0, SIDE_W, ""); + pins[clk].clock = true; + pins[clr] = new Pin(bits + 1, SIDE_W, "CLR"); + pins[clr].bubble = true; + pins[enp] = new Pin(bits + 2, SIDE_W, "EnP"); + pins[rco] = new Pin(0, SIDE_E, "RCO"); + pins[rco].output = true; + pins[load] = new Pin(bits + 1, SIDE_E, "LOAD"); + pins[load].bubble = true; + pins[ent] = new Pin(bits + 2, SIDE_E, "EnT"); + } + + int getPostCount() { + return bits * 2 + 6; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) + return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); + if (n == 1) + return new EditInfo("Modulus", modulus, 1, 1).setDimensionless(); + return null; + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value >= 2) { + bits = (int) ei.value; + setupPins(); + setPoints(); + allocNodes(); } - int getVoltageSourceCount() { return bits+1; } - - boolean carry; - - void execute() { - if (pins[clk].value && !lastClock) { - if (pins[enp].value && pins[ent].value) { - int i; - int value = 0; - - // get current value - int lastBit = bits-1; - for (i = 0; i != bits; i++) - if (pins[lastBit-i].value) - value |= 1< 2 ? bits : 2; + pins = new Pin[getPostCount()]; + pins[0] = new Pin(0, SIDE_W, ""); + pins[0].clock = true; + pins[0].bubble = negativeEdgeTriggered(); + pins[1] = new Pin(sizeY - 1, SIDE_W, "R"); + pins[1].bubble = invertreset; + int i; + for (i = 0; i != bits; i++) { + int ii = i + 2; + pins[ii] = new Pin(i, SIDE_E, "Q" + (bits - i - 1)); + pins[ii].output = pins[ii].state = true; } + if (hasUpDown()) + pins[bits + 2] = new Pin(sizeY - 2, SIDE_W, "U/D"); + allocNodes(); + } + + int getPostCount() { + return (hasUpDown()) ? bits + 3 : bits + 2; + } - String dump() { - return super.dump() + " " + invertreset + " " + modulus; + public EditInfo getChipEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Invert reset pin", invertreset); + return ei; } + if (n == 1) + return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); + if (n == 2) + return new EditInfo("Modulus", modulus, 1, 1).setDimensionless(); + if (n == 3) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Up/Down Pin", hasUpDown()); + return ei; + } + if (n == 4) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Negative Edge Triggered", negativeEdgeTriggered()); + return ei; + } + return null; + } - boolean needsBits() { return true; } - String getChipName() { - if (modulus == 0) - return "Counter"; - return Locale.LS("Counter") + Locale.LS(" (mod ") + modulus + ")"; + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0) { + invertreset = ei.checkbox.getState(); + setupPins(); + setPoints(); } - void setupPins() { - sizeX = 2; - sizeY = bits > 2 ? bits : 2; - pins = new Pin[getPostCount()]; - pins[0] = new Pin(0, SIDE_W, ""); - pins[0].clock = true; - pins[0].bubble = negativeEdgeTriggered(); - pins[1] = new Pin(sizeY-1, SIDE_W, "R"); - pins[1].bubble = invertreset; - int i; - for (i = 0; i != bits; i++) { - int ii = i+2; - pins[ii] = new Pin(i, SIDE_E, "Q" + (bits-i-1)); - pins[ii].output = pins[ii].state = true; - } - if (hasUpDown()) - pins[bits+2] = new Pin(sizeY-2, SIDE_W, "U/D"); - allocNodes(); + if (n == 1 && ei.value >= 3) { + bits = (int) ei.value; + setupPins(); + setPoints(); } - int getPostCount() { - return (hasUpDown()) ? bits+3 : bits+2; + if (n == 2) + modulus = (int) ei.value; + if (n == 3) { + flags = ei.changeFlag(flags, FLAG_UP_DOWN); + setupPins(); + setPoints(); } - public EditInfo getChipEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Invert reset pin",invertreset); - return ei; - } - if (n == 1) - return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); - if (n == 2) - return new EditInfo("Modulus", modulus, 1, 1).setDimensionless(); - if (n == 3) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Up/Down Pin", hasUpDown()); - return ei; - } - if (n == 4) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Negative Edge Triggered", negativeEdgeTriggered()); - return ei; - } - return null; + if (n == 4) { + flags = ei.changeFlag(flags, FLAG_NEGATIVE_EDGE); + setupPins(); + setPoints(); } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0) { - invertreset = ei.checkbox.getState(); - setupPins(); - setPoints(); - } - if (n == 1 && ei.value >= 3) { - bits = (int)ei.value; - setupPins(); - setPoints(); - } - if (n == 2) - modulus = (int)ei.value; - if (n == 3) { - flags = ei.changeFlag(flags, FLAG_UP_DOWN); - setupPins(); - setPoints(); - } - if (n == 4) { - flags = ei.changeFlag(flags, FLAG_NEGATIVE_EDGE); - setupPins(); - setPoints(); - } + } + + boolean hasUpDown() { + return (flags & FLAG_UP_DOWN) != 0; + } + + boolean negativeEdgeTriggered() { + return (flags & FLAG_NEGATIVE_EDGE) != 0; + } + + int getVoltageSourceCount() { + return bits; + } + + void execute() { + boolean neg = negativeEdgeTriggered(); + if (pins[0].value != neg && lastClock == neg) { + int i; + int value = 0; + + // get direction + int dir = 1; + if (hasUpDown() && pins[bits + 2].value) + dir = -1; + + // get current value + int lastBit = 2 + bits - 1; + for (i = 0; i != bits; i++) + if (pins[lastBit - i].value) + value |= 1 << i; + + // update value + value += dir; + if (modulus != 0) + value = (value + modulus) % modulus; + + // convert value to binary + for (i = 0; i != bits; i++) + pins[lastBit - i].value = (value & (1 << i)) != 0; } - boolean hasUpDown() { return (flags & FLAG_UP_DOWN) != 0; } - boolean negativeEdgeTriggered() { return (flags & FLAG_NEGATIVE_EDGE) != 0; } - int getVoltageSourceCount() { return bits; } - void execute() { - boolean neg = negativeEdgeTriggered(); - if (pins[0].value != neg && lastClock == neg) { - int i; - int value = 0; - - // get direction - int dir = 1; - if (hasUpDown() && pins[bits+2].value) - dir = -1; - - // get current value - int lastBit = 2+bits-1; - for (i = 0; i != bits; i++) - if (pins[lastBit-i].value) - value |= 1< 0) - parallelCapacitance = ei.value; - if (n == 1 && ei.value > 0) - seriesCapacitance = ei.value; - if (n == 2 && ei.value > 0) - inductance = ei.value; - if (n == 3 && ei.value > 0) - resistance = ei.value; - initCrystal(); + public CrystalElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st, modelString, modelExternalNodes); + CapacitorElm c1 = (CapacitorElm) compElmList.get(0); + parallelCapacitance = c1.getCapacitance(); + CapacitorElm c2 = (CapacitorElm) compElmList.get(1); + seriesCapacitance = c2.getCapacitance(); + InductorElm i1 = (InductorElm) compElmList.get(2); + inductance = i1.getInductance(); + ResistorElm r1 = (ResistorElm) compElmList.get(3); + resistance = r1.getResistance(); + initCrystal(); + } + + private void initCrystal() { + CapacitorElm c1 = (CapacitorElm) compElmList.get(0); + c1.setCapacitance(parallelCapacitance); + CapacitorElm c2 = (CapacitorElm) compElmList.get(1); + c2.setCapacitance(seriesCapacitance); + InductorElm i1 = (InductorElm) compElmList.get(2); + i1.setInductance(inductance); + ResistorElm r1 = (ResistorElm) compElmList.get(3); + r1.setResistance(resistance); + } + + int getDumpType() { + return 412; + } + + Point sandwichPoints[]; + + void setPoints() { + super.setPoints(); + double f = (dn / 2 - 10) / dn; + // calc leads + lead1 = interpPoint(point1, point2, f); + lead2 = interpPoint(point1, point2, 1 - f); + // calc plates + plate1 = newPointArray(2); + plate2 = newPointArray(2); + interpPoint2(point1, point2, plate1[0], plate1[1], f, 8); + interpPoint2(point1, point2, plate2[0], plate2[1], 1 - f, 8); + + sandwichPoints = newPointArray(4); + double f2 = (dn / 2 - 5) / dn; + interpPoint2(point1, point2, sandwichPoints[0], sandwichPoints[1], f2, 10); + interpPoint2(point1, point2, sandwichPoints[3], sandwichPoints[2], 1 - f2, 10); + + // need to do this explicitly for CompositeElms + setPost(0, point1); + setPost(1, point2); + } + + void draw(Graphics g) { + int hs = 12; + setBbox(point1, point2, hs); + + // draw first lead and plate + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, lead1); + setPowerColor(g, false); + drawThickLine(g, plate1[0], plate1[1]); + if (sim.powerCheckItem.getState()) + g.setColor(Color.gray); + + // draw second lead and plate + setVoltageColor(g, volts[1]); + drawThickLine(g, point2, lead2); + setPowerColor(g, false); + drawThickLine(g, plate2[0], plate2[1]); + + int i; + setVoltageColor(g, .5 * (volts[0] + volts[1])); + for (i = 0; i != 4; i++) + drawThickLine(g, sandwichPoints[i], sandwichPoints[(i + 1) % 4]); + + updateDotCount(); + if (sim.dragElm != this) { + drawDots(g, point1, lead1, curcount); + drawDots(g, point2, lead2, -curcount); } + drawPosts(g); + } + + void calculateCurrent() { + current = getCurrentIntoNode(1); + } + + void getInfo(String arr[]) { + arr[0] = "crystal"; + getBasicInfo(arr); + arr[3] = "fs = " + getUnitText(1 / (Math.sqrt(inductance * seriesCapacitance) * Math.PI * 2), "Hz"); + // arr[3] = "C = " + getUnitText(capacitance, "F"); + // arr[4] = "P = " + getUnitText(getPower(), "W"); + // double v = getVoltageDiff(); + // arr[4] = "U = " + getUnitText(.5*capacitance*v*v, "J"); + } + + public boolean canViewInScope() { + return true; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo(EditInfo.makeLink("crystal.html", "Parallel Capacitance"), parallelCapacitance); + if (n == 1) + return new EditInfo("Series Capacitance (F)", seriesCapacitance); + if (n == 2) + return new EditInfo("Inductance (H)", inductance, 0, 0); + if (n == 3) + return new EditInfo("Resistance (" + Locale.ohmString + ")", resistance, 0, 0); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) + parallelCapacitance = ei.value; + if (n == 1 && ei.value > 0) + seriesCapacitance = ei.value; + if (n == 2 && ei.value > 0) + inductance = ei.value; + if (n == 3 && ei.value > 0) + resistance = ei.value; + initCrystal(); } +} diff --git a/src/com/lushprojects/circuitjs1/client/CurrentElm.java b/src/com/lushprojects/circuitjs1/client/CurrentElm.java index 822a542c..d198f048 100644 --- a/src/com/lushprojects/circuitjs1/client/CurrentElm.java +++ b/src/com/lushprojects/circuitjs1/client/CurrentElm.java @@ -19,90 +19,104 @@ package com.lushprojects.circuitjs1.client; - class CurrentElm extends CircuitElm { - double currentValue; - boolean broken; - public CurrentElm(int xx, int yy) { - super(xx, yy); +class CurrentElm extends CircuitElm { + double currentValue; + boolean broken; + + public CurrentElm(int xx, int yy) { + super(xx, yy); + currentValue = .01; + } + + public CurrentElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + try { + currentValue = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { currentValue = .01; } - public CurrentElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - try { - currentValue = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { - currentValue = .01; - } - } - String dump() { - return super.dump() + " " + currentValue; - } - int getDumpType() { return 'i'; } - - Polygon arrow; - Point ashaft1, ashaft2, center; - void setPoints() { - super.setPoints(); - calcLeads(26); - ashaft1 = interpPoint(lead1, lead2, .25); - ashaft2 = interpPoint(lead1, lead2, .6); - center = interpPoint(lead1, lead2, .5); - Point p2 = interpPoint(lead1, lead2, .75); - arrow = calcArrow(center, p2, 4, 4); - } - void draw(Graphics g) { - int cr = 12; - draw2Leads(g); - setVoltageColor(g, (volts[0]+volts[1])/2); - setPowerColor(g, false); - - drawThickCircle(g, center.x, center.y, cr); - drawThickLine(g, ashaft1, ashaft2); - - g.fillPolygon(arrow); - setBbox(point1, point2, cr); - doDots(g); - if (sim.showValuesCheckItem.getState() && current != 0) { - String s = getShortUnitText(current, "A"); - if (dx == 0 || dy == 0) - drawValues(g, s, cr); - } - drawPosts(g); - } - - // analyzeCircuit determines if current source has a path or if it's broken - void setBroken(boolean b) { - broken = b; - } - - // we defer stamping current sources until we can tell if they have a current path or not - void stamp() { - if (broken) { - // no current path; stamping a current source would cause a matrix error. - sim.stampResistor(nodes[0], nodes[1], 1e8); - current = 0; - } else { - // ok to stamp a current source - sim.stampCurrentSource(nodes[0], nodes[1], currentValue); - current = currentValue; - } - } - - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Current (A)", currentValue, 0, .1); - return null; - } - public void setEditValue(int n, EditInfo ei) { - currentValue = ei.value; - } - void getInfo(String arr[]) { - arr[0] = "current source"; - getBasicInfo(arr); + } + + String dump() { + return super.dump() + " " + currentValue; + } + + int getDumpType() { + return 'i'; + } + + Polygon arrow; + Point ashaft1, ashaft2, center; + + void setPoints() { + super.setPoints(); + calcLeads(26); + ashaft1 = interpPoint(lead1, lead2, .25); + ashaft2 = interpPoint(lead1, lead2, .6); + center = interpPoint(lead1, lead2, .5); + Point p2 = interpPoint(lead1, lead2, .75); + arrow = calcArrow(center, p2, 4, 4); + } + + void draw(Graphics g) { + int cr = 12; + draw2Leads(g); + setVoltageColor(g, (volts[0] + volts[1]) / 2); + setPowerColor(g, false); + + drawThickCircle(g, center.x, center.y, cr); + drawThickLine(g, ashaft1, ashaft2); + + g.fillPolygon(arrow); + setBbox(point1, point2, cr); + doDots(g); + if (sim.showValuesCheckItem.getState() && current != 0) { + String s = getShortUnitText(current, "A"); + if (dx == 0 || dy == 0) + drawValues(g, s, cr); } - double getVoltageDiff() { - return volts[1] - volts[0]; + drawPosts(g); + } + + // analyzeCircuit determines if current source has a path or if it's broken + void setBroken(boolean b) { + broken = b; + } + + // we defer stamping current sources until we can tell if they have a current + // path or not + void stamp() { + if (broken) { + // no current path; stamping a current source would cause a matrix error. + sim.stampResistor(nodes[0], nodes[1], 1e8); + current = 0; + } else { + // ok to stamp a current source + sim.stampCurrentSource(nodes[0], nodes[1], currentValue); + current = currentValue; } - double getPower() { return -getVoltageDiff()*current; } } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Current (A)", currentValue, 0, .1); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + currentValue = ei.value; + } + + void getInfo(String arr[]) { + arr[0] = "current source"; + getBasicInfo(arr); + } + + double getVoltageDiff() { + return volts[1] - volts[0]; + } + + double getPower() { + return -getVoltageDiff() * current; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/CustomCompositeChipElm.java b/src/com/lushprojects/circuitjs1/client/CustomCompositeChipElm.java index 816829bf..352ca68e 100644 --- a/src/com/lushprojects/circuitjs1/client/CustomCompositeChipElm.java +++ b/src/com/lushprojects/circuitjs1/client/CustomCompositeChipElm.java @@ -19,43 +19,55 @@ package com.lushprojects.circuitjs1.client; - // concrete subclass of ChipElm that can be used by other elements (like CustomCompositeElm) to draw chips. - // CustomCompositeElm can't be a subclass of both ChipElm and CompositeElm. - class CustomCompositeChipElm extends ChipElm { - String label; - - public CustomCompositeChipElm(int xx, int yy) { - super(xx, yy); - setSize(2); - } - boolean needsBits() { return false; } - void setupPins() { } - int getVoltageSourceCount() { return 0; } - void setPins(Pin p[]) { - pins = p; - } - void allocPins(int n) { - pins = new Pin[n]; - } - void setPin(int n, int p, int s, String t) { - pins[n] = new Pin(p, s, t); - pins[n].fixName(); - } - - void setLabel(String text) { - label = text; - } - - void drawLabel(Graphics g, int x, int y) { - if (label == null) - return; - g.save(); - g.context.setTextBaseline("middle"); - g.context.setTextAlign("center"); - g.drawString(label, x, y); - g.restore(); - } - - int getPostCount() { return pins == null ? 1 : pins.length; } +// concrete subclass of ChipElm that can be used by other elements (like CustomCompositeElm) to draw chips. +// CustomCompositeElm can't be a subclass of both ChipElm and CompositeElm. +class CustomCompositeChipElm extends ChipElm { + String label; + + public CustomCompositeChipElm(int xx, int yy) { + super(xx, yy); + setSize(2); + } + + boolean needsBits() { + return false; + } + + void setupPins() { + } + + int getVoltageSourceCount() { + return 0; + } + + void setPins(Pin p[]) { + pins = p; } + void allocPins(int n) { + pins = new Pin[n]; + } + + void setPin(int n, int p, int s, String t) { + pins[n] = new Pin(p, s, t); + pins[n].fixName(); + } + + void setLabel(String text) { + label = text; + } + + void drawLabel(Graphics g, int x, int y) { + if (label == null) + return; + g.save(); + g.context.setTextBaseline("middle"); + g.context.setTextAlign("center"); + g.drawString(label, x, y); + g.restore(); + } + + int getPostCount() { + return pins == null ? 1 : pins.length; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/CustomCompositeElm.java b/src/com/lushprojects/circuitjs1/client/CustomCompositeElm.java index eb798de4..5cca575d 100644 --- a/src/com/lushprojects/circuitjs1/client/CustomCompositeElm.java +++ b/src/com/lushprojects/circuitjs1/client/CustomCompositeElm.java @@ -16,14 +16,15 @@ public class CustomCompositeElm extends CompositeElm { CustomCompositeModel model; static String lastModelName = "default"; static final int FLAG_SMALL = 2; - + public CustomCompositeElm(int xx, int yy) { super(xx, yy); - + // use last model as default when creating new element in UI. - // use default otherwise, to avoid infinite recursion when creating nested subcircuits. + // use default otherwise, to avoid infinite recursion when creating nested + // subcircuits. modelName = (xx == 0 && yy == 0) ? "default" : lastModelName; - + flags |= FLAG_ESCAPE; if (sim.smallGridCheckItem.getState()) flags |= FLAG_SMALL; @@ -38,14 +39,13 @@ public CustomCompositeElm(int xx, int yy, String name) { flags |= FLAG_SMALL; updateModels(); } - - public CustomCompositeElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public CustomCompositeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); modelName = CustomLogicModel.unescape(st.nextToken()); updateModels(st); } - + public String dump() { // insert model name before the elements String s = super.dumpWithMask(0); @@ -53,10 +53,10 @@ public String dump() { s += dumpElements(); return s; } - + String dumpModel() { String modelStr = ""; - + // dump models of all children for (int i = 0; i < compElmList.size(); i++) { CircuitElm ce = compElmList.get(i); @@ -69,20 +69,20 @@ String dumpModel() { } if (model.dumped) return modelStr; - + // dump our model if (!modelStr.isEmpty()) modelStr += "\n"; modelStr += model.dump(); - + return modelStr; } - + void draw(Graphics g) { int i; for (i = 0; i != postCount; i++) { chip.volts[i] = volts[i]; - chip.pins[i].current = getCurrentIntoNode(i); + chip.pins[i].current = getCurrentIntoNode(i); } chip.setSelected(needsHighlight()); chip.draw(g); @@ -94,11 +94,11 @@ void setPoints() { chip.x2 = x2; chip.y2 = y2; chip.flags = (flags & (ChipElm.FLAG_FLIP_X | ChipElm.FLAG_FLIP_Y | ChipElm.FLAG_FLIP_XY)); - if (x2-x > model.sizeX*16 && this == sim.dragElm) + if (x2 - x > model.sizeX * 16 && this == sim.dragElm) flags &= ~FLAG_SMALL; chip.setSize((flags & FLAG_SMALL) != 0 ? 1 : 2); chip.setLabel((model.flags & CustomCompositeModel.FLAG_SHOW_LABEL) != 0 ? model.name : null); - + chip.sizeX = model.sizeX; chip.sizeY = model.sizeY; chip.allocPins(postCount); @@ -107,7 +107,7 @@ void setPoints() { ExtListEntry pin = model.extList.get(i); chip.setPin(i, pin.pos, pin.side, pin.name); } - + chip.setPoints(); for (i = 0; i != getPostCount(); i++) setPost(i, chip.getPost(i)); @@ -116,7 +116,7 @@ void setPoints() { public void updateModels() { updateModels(null); } - + public void updateModels(StringTokenizer st) { model = CustomCompositeModel.getModelWithName(modelName); if (model == null) @@ -132,54 +132,56 @@ public void updateModels(StringTokenizer st) { allocNodes(); setPoints(); } - - int getPostCount() { return postCount; } - + + int getPostCount() { + return postCount; + } + Vector models; - + public EditInfo getEditInfo(int n) { // if model is built in, don't allow it to be changed if (model.builtin) n += 2; - + if (n == 0) { EditInfo ei = new EditInfo(EditInfo.makeLink("subcircuits.html", "Model Name"), 0, -1, -1); - models = CustomCompositeModel.getModelList(); - ei.choice = new Choice(); - int i; - for (i = 0; i != models.size(); i++) { - CustomCompositeModel ccm = models.get(i); - ei.choice.add(ccm.name); - if (ccm == model) - ei.choice.select(i); - } + models = CustomCompositeModel.getModelList(); + ei.choice = new Choice(); + int i; + for (i = 0; i != models.size(); i++) { + CustomCompositeModel ccm = models.get(i); + ei.choice.add(ccm.name); + if (ccm == model) + ei.choice.select(i); + } + return ei; + } + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Edit Pin Layout")); + return ei; + } + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip X", (flags & ChipElm.FLAG_FLIP_X) != 0); + return ei; + } + if (n == 3) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip Y", (flags & ChipElm.FLAG_FLIP_Y) != 0); + return ei; + } + if (n == 4) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip X/Y", (flags & ChipElm.FLAG_FLIP_XY) != 0); + return ei; + } + if (n == 5 && model.canLoadModelCircuit()) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Load Model Circuit")); return ei; } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Edit Pin Layout")); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip X", (flags & ChipElm.FLAG_FLIP_X) != 0); - return ei; - } - if (n == 3) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip Y", (flags & ChipElm.FLAG_FLIP_Y) != 0); - return ei; - } - if (n == 4) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip X/Y", (flags & ChipElm.FLAG_FLIP_XY) != 0); - return ei; - } - if (n == 5 && model.canLoadModelCircuit()) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Load Model Circuit")); - return ei; - } return null; } @@ -187,43 +189,45 @@ public void setEditValue(int n, EditInfo ei) { if (model.builtin) n += 2; if (n == 0) { - model = models.get(ei.choice.getSelectedIndex()); + model = models.get(ei.choice.getSelectedIndex()); lastModelName = modelName = model.name; updateModels(); setPoints(); return; } - if (n == 1) { - if (model.name.equals("default")) { - Window.alert(Locale.LS("Can't edit this model.")); - return; - } - EditCompositeModelDialog dlg = new EditCompositeModelDialog(); - dlg.setModel(model); - dlg.createDialog(); - CirSim.dialogShowing = dlg; - dlg.show(); - return; - } - if (n == 2) { - flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_X); - setPoints(); - } - if (n == 3) { - flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_Y); - setPoints(); - } - if (n == 4) { - flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_XY); - setPoints(); - } - if (n == 5) { - sim.readCircuit(model.modelCircuit); - CirSim.editDialog.closeDialog(); - } + if (n == 1) { + if (model.name.equals("default")) { + Window.alert(Locale.LS("Can't edit this model.")); + return; + } + EditCompositeModelDialog dlg = new EditCompositeModelDialog(); + dlg.setModel(model); + dlg.createDialog(); + CirSim.dialogShowing = dlg; + dlg.show(); + return; + } + if (n == 2) { + flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_X); + setPoints(); + } + if (n == 3) { + flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_Y); + setPoints(); + } + if (n == 4) { + flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_XY); + setPoints(); + } + if (n == 5) { + sim.readCircuit(model.modelCircuit); + CirSim.editDialog.closeDialog(); + } + } + + int getDumpType() { + return 410; } - - int getDumpType() { return 410; } void getInfo(String arr[]) { super.getInfo(arr); @@ -233,9 +237,9 @@ void getInfo(String arr[]) { arr[0] = "subcircuit (" + model.name + ")"; int i; for (i = 0; i != postCount; i++) { - if (i+1 >= arr.length) + if (i + 1 >= arr.length) break; - arr[i+1] = model.extList.get(i).name + " = " + getVoltageText(volts[i]); + arr[i + 1] = model.extList.get(i).name + " = " + getVoltageText(volts[i]); } } } diff --git a/src/com/lushprojects/circuitjs1/client/CustomCompositeModel.java b/src/com/lushprojects/circuitjs1/client/CustomCompositeModel.java index 16fde51b..6e2ba4d5 100644 --- a/src/com/lushprojects/circuitjs1/client/CustomCompositeModel.java +++ b/src/com/lushprojects/circuitjs1/client/CustomCompositeModel.java @@ -11,8 +11,19 @@ // model for subcircuits class ExtListEntry { - ExtListEntry(String s, int n) { name = s; node = n; side = ChipElm.SIDE_W; } - ExtListEntry(String s, int n, int p, int sd) { name = s; node = n; pos = p; side = sd; } + ExtListEntry(String s, int n) { + name = s; + node = n; + side = ChipElm.SIDE_W; + } + + ExtListEntry(String s, int n, int p, int sd) { + name = s; + node = n; + pos = p; + side = sd; + } + String name; int node, pos, side; }; @@ -20,7 +31,7 @@ class ExtListEntry { public class CustomCompositeModel implements Comparable { static HashMap modelMap; - + int flags, sizeX, sizeY; String name; String nodeList; @@ -31,7 +42,7 @@ public class CustomCompositeModel implements Comparable { boolean builtin; static int sequenceNumber; static final int FLAG_SHOW_LABEL = 1; - + void setName(String n) { modelMap.remove(name); name = n; @@ -40,7 +51,7 @@ void setName(String n) { } static void initModelMap() { - modelMap = new HashMap(); + modelMap = new HashMap(); // create default stub model Vector extList = new Vector(); @@ -49,33 +60,33 @@ static void initModelMap() { d.sizeX = d.sizeY = 1; modelMap.put(d.name, d); sequenceNumber = 1; - + // get models from local storage - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor != null) { - int len = stor.getLength(); - int i; - for (i = 0; i != len; i++) { - String key = stor.key(i); - if (!key.startsWith("subcircuit:")) - continue; - String data = stor.getItem(key); - String firstLine = data; - int lineLen = data.indexOf('\n'); - if (lineLen != -1) - firstLine = data.substring(0, lineLen); - StringTokenizer st = new StringTokenizer(firstLine, " "); - if (st.nextToken() == ".") { - CustomCompositeModel model = undumpModel(st); - if (lineLen != -1) - model.modelCircuit = data.substring(lineLen+1); - } - } - } - - loadBuiltinModels(); - } - + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor != null) { + int len = stor.getLength(); + int i; + for (i = 0; i != len; i++) { + String key = stor.key(i); + if (!key.startsWith("subcircuit:")) + continue; + String data = stor.getItem(key); + String firstLine = data; + int lineLen = data.indexOf('\n'); + if (lineLen != -1) + firstLine = data.substring(0, lineLen); + StringTokenizer st = new StringTokenizer(firstLine, " "); + if (st.nextToken() == ".") { + CustomCompositeModel model = undumpModel(st); + if (lineLen != -1) + model.modelCircuit = data.substring(lineLen + 1); + } + } + } + + loadBuiltinModels(); + } + static CustomCompositeModel getModelWithName(String name) { if (modelMap == null) initModelMap(); @@ -83,15 +94,16 @@ static CustomCompositeModel getModelWithName(String name) { return lm; } - static CustomCompositeModel createModel(String name, String elmDump, String nodeList, Vector extList) { + static CustomCompositeModel createModel(String name, String elmDump, String nodeList, + Vector extList) { CustomCompositeModel lm = new CustomCompositeModel(); lm.name = name; lm.elmDump = elmDump; lm.nodeList = nodeList; lm.extList = extList; - modelMap.put(name, lm); - sequenceNumber++; - return lm; + modelMap.put(name, lm); + sequenceNumber++; + return lm; } static void clearDumpedFlags() { @@ -99,35 +111,35 @@ static void clearDumpedFlags() { return; Iterator it = modelMap.entrySet().iterator(); while (it.hasNext()) { - Map.Entry pair = (Map.Entry)it.next(); + Map.Entry pair = (Map.Entry) it.next(); pair.getValue().dumped = false; } } static Vector getModelList() { - Vector vector = new Vector(); - Iterator it = modelMap.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry)it.next(); - CustomCompositeModel dm = pair.getValue(); - if (dm.builtin) - continue; - vector.add(dm); - } - Collections.sort(vector); - return vector; + Vector vector = new Vector(); + Iterator it = modelMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + CustomCompositeModel dm = pair.getValue(); + if (dm.builtin) + continue; + vector.add(dm); + } + Collections.sort(vector); + return vector; } public int compareTo(CustomCompositeModel dm) { - return name.compareTo(dm.name); + return name.compareTo(dm.name); } - + CustomCompositeModel() { } - + static CustomCompositeModel undumpModel(StringTokenizer st) { String name = CustomLogicModel.unescape(st.nextToken()); -// CustomCompositeElm.lastModelName = name; + // CustomCompositeElm.lastModelName = name; CustomCompositeModel model = getModelWithName(name); if (model == null) { model = new CustomCompositeModel(); @@ -135,14 +147,15 @@ static CustomCompositeModel undumpModel(StringTokenizer st) { modelMap.put(name, model); sequenceNumber++; } else if (model.modelCircuit != null) { - // if model has an associated model circuit, don't overwrite it. keep the old one. + // if model has an associated model circuit, don't overwrite it. keep the old + // one. CirSim.console("ignoring model " + name + ", using stored version instead"); return model; } model.undump(st); return model; } - + void undump(StringTokenizer st) { flags = Integer.parseInt(st.nextToken()); sizeX = Integer.parseInt(st.nextToken()); @@ -160,27 +173,27 @@ void undump(StringTokenizer st) { nodeList = CustomLogicModel.unescape(st.nextToken()); elmDump = CustomLogicModel.unescape(st.nextToken()); } - + boolean isSaved() { if (name == null) return false; - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return false; - return stor.getItem("subcircuit:" + name) != null; + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return false; + return stor.getItem("subcircuit:" + name) != null; } - + void setSaved(boolean sv) { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; - if (sv) { - String cir = (modelCircuit == null) ? "" : modelCircuit; - stor.setItem("subcircuit:" + name, dump() + "\n" + cir); - } else - stor.removeItem("subcircuit:" + name); - } - + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; + if (sv) { + String cir = (modelCircuit == null) ? "" : modelCircuit; + stor.setItem("subcircuit:" + name, dump() + "\n" + cir); + } else + stor.removeItem("subcircuit:" + name); + } + String arrayToList(String arr[]) { if (arr == null) return ""; @@ -192,42 +205,43 @@ String arrayToList(String arr[]) { x += "," + arr[i]; return x; } - - boolean showLabel() { return (flags & FLAG_SHOW_LABEL) != 0; } - + + boolean showLabel() { + return (flags & FLAG_SHOW_LABEL) != 0; + } + void setShowLabel(boolean sl) { flags = (sl) ? (flags | FLAG_SHOW_LABEL) : (flags & ~FLAG_SHOW_LABEL); } - String [] listToArray(String arr) { + String[] listToArray(String arr) { return arr.split(","); } - + String dump() { if (builtin) return ""; dumped = true; String str = ". " + CustomLogicModel.escape(name) + " 0 " + sizeX + " " + sizeY + " " + extList.size() + " "; - int i; - for (i = 0; i != extList.size(); i++) { - ExtListEntry ent = extList.get(i); - if (i > 0) - str += " "; - str += CustomLogicModel.escape(ent.name) + " " + ent.node + " " + ent.pos + " " + ent.side; - } - str += " " + CustomLogicModel.escape(nodeList) + " " + CustomLogicModel.escape(elmDump); - return str; - } - + int i; + for (i = 0; i != extList.size(); i++) { + ExtListEntry ent = extList.get(i); + if (i > 0) + str += " "; + str += CustomLogicModel.escape(ent.name) + " " + ent.node + " " + ent.pos + " " + ent.side; + } + str += " " + CustomLogicModel.escape(nodeList) + " " + CustomLogicModel.escape(elmDump); + return str; + } + boolean canLoadModelCircuit() { return modelCircuit != null && modelCircuit.length() > 0; } - + static void loadBuiltinModels() { String lm317 = ". ~LM317-v2 0 2 2 3 adj 2 1 1 in 1 0 2 out 3 0 3 JfetElm\\s3\\s4\\s1\\s\\rResistorElm\\s5\\s39\\rCapacitorElm\\s39\\s6\\rCapacitorElm\\s39\\s5\\rTransistorElm\\s39\\s5\\s6\\s\\rResistorElm\\s7\\s40\\rCapacitorElm\\s40\\s8\\rCapacitorElm\\s40\\s5\\rTransistorElm\\s40\\s5\\s8\\s\\rResistorElm\\s5\\s41\\rCapacitorElm\\s41\\s9\\rCapacitorElm\\s41\\s7\\rTransistorElm\\s41\\s7\\s9\\s\\rResistorElm\\s7\\s42\\rCapacitorElm\\s42\\s3\\rCapacitorElm\\s42\\s10\\rTransistorElm\\s42\\s10\\s3\\s\\rResistorElm\\s10\\s43\\rCapacitorElm\\s43\\s11\\rCapacitorElm\\s43\\s3\\rTransistorElm\\s43\\s3\\s11\\s\\rResistorElm\\s10\\s44\\rCapacitorElm\\s44\\s13\\rCapacitorElm\\s44\\s12\\rTransistorElm\\s44\\s12\\s13\\s\\rResistorElm\\s5\\s45\\rCapacitorElm\\s45\\s14\\rCapacitorElm\\s45\\s11\\rTransistorElm\\s45\\s11\\s14\\s\\rResistorElm\\s12\\s46\\rCapacitorElm\\s46\\s11\\rCapacitorElm\\s46\\s15\\rTransistorElm\\s46\\s15\\s11\\s\\rResistorElm\\s5\\s47\\rCapacitorElm\\s47\\s17\\rCapacitorElm\\s47\\s16\\rTransistorElm\\s47\\s16\\s17\\s\\rResistorElm\\s15\\s48\\rCapacitorElm\\s48\\s18\\rCapacitorElm\\s48\\s16\\rTransistorElm\\s48\\s16\\s18\\s\\rResistorElm\\s19\\s49\\rCapacitorElm\\s49\\s16\\rCapacitorElm\\s49\\s3\\rTransistorElm\\s49\\s3\\s16\\s\\rResistorElm\\s20\\s50\\rCapacitorElm\\s50\\s19\\rCapacitorElm\\s50\\s1\\rTransistorElm\\s50\\s1\\s19\\s\\rResistorElm\\s5\\s51\\rCapacitorElm\\s51\\s21\\rCapacitorElm\\s51\\s20\\rTransistorElm\\s51\\s20\\s21\\s\\rResistorElm\\s22\\s52\\rCapacitorElm\\s52\\s20\\rCapacitorElm\\s52\\s3\\rTransistorElm\\s52\\s3\\s20\\s\\rResistorElm\\s23\\s53\\rCapacitorElm\\s53\\s16\\rCapacitorElm\\s53\\s22\\rTransistorElm\\s53\\s22\\s16\\s\\rResistorElm\\s3\\s54\\rCapacitorElm\\s54\\s24\\rCapacitorElm\\s54\\s22\\rTransistorElm\\s54\\s22\\s24\\s\\rResistorElm\\s23\\s55\\rCapacitorElm\\s55\\s16\\rCapacitorElm\\s55\\s23\\rTransistorElm\\s55\\s23\\s16\\s\\rResistorElm\\s3\\s56\\rCapacitorElm\\s56\\s25\\rCapacitorElm\\s56\\s23\\rTransistorElm\\s56\\s23\\s25\\s\\rResistorElm\\s26\\s57\\rCapacitorElm\\s57\\s16\\rCapacitorElm\\s57\\s3\\rTransistorElm\\s57\\s3\\s16\\s\\rResistorElm\\s27\\s58\\rCapacitorElm\\s58\\s3\\rCapacitorElm\\s58\\s26\\rTransistorElm\\s58\\s26\\s3\\s\\rResistorElm\\s28\\s59\\rCapacitorElm\\s59\\s1\\rCapacitorElm\\s59\\s28\\rTransistorElm\\s59\\s28\\s1\\s\\rResistorElm\\s28\\s60\\rCapacitorElm\\s60\\s1\\rCapacitorElm\\s60\\s16\\rTransistorElm\\s60\\s16\\s1\\s\\rResistorElm\\s16\\s61\\rCapacitorElm\\s61\\s29\\rCapacitorElm\\s61\\s28\\rTransistorElm\\s61\\s28\\s29\\s\\rResistorElm\\s31\\s62\\rCapacitorElm\\s62\\s32\\rCapacitorElm\\s62\\s30\\rTransistorElm\\s62\\s30\\s32\\s\\rResistorElm\\s31\\s63\\rCapacitorElm\\s63\\s33\\rCapacitorElm\\s63\\s30\\rTransistorElm\\s63\\s30\\s33\\s\\rResistorElm\\s34\\s64\\rCapacitorElm\\s64\\s35\\rCapacitorElm\\s64\\s1\\rTransistorElm\\s64\\s1\\s35\\s\\rResistorElm\\s35\\s65\\rCapacitorElm\\s65\\s36\\rCapacitorElm\\s65\\s1\\rTransistorElm\\s65\\s1\\s36\\s\\rDiodeElm\\s3\\s4\\rDiodeElm\\s37\\s1\\rDiodeElm\\s32\\s38\\rResistorElm\\s1\\s6\\rResistorElm\\s1\\s9\\rResistorElm\\s1\\s14\\rResistorElm\\s1\\s17\\rResistorElm\\s1\\s21\\rResistorElm\\s4\\s7\\rResistorElm\\s7\\s10\\rResistorElm\\s11\\s12\\rResistorElm\\s8\\s3\\rResistorElm\\s13\\s3\\rResistorElm\\s15\\s3\\rResistorElm\\s18\\s3\\rResistorElm\\s19\\s3\\rResistorElm\\s2\\s24\\rResistorElm\\s24\\s25\\rResistorElm\\s16\\s26\\rResistorElm\\s16\\s31\\rResistorElm\\s29\\s35\\rResistorElm\\s16\\s34\\rResistorElm\\s27\\s30\\rResistorElm\\s30\\s31\\rResistorElm\\s3\\s35\\rResistorElm\\s37\\s38\\rResistorElm\\s33\\s32\\rResistorElm\\s33\\s36\\rResistorElm\\s36\\s3\\rCapacitorElm\\s22\\s3\\rCapacitorElm\\s22\\s2\\rCapacitorElm\\s26\\s27\\rCapacitorElm\\s5\\s3\\rCapacitorElm\\s28\\s3\\rCapacitorElm\\s23\\s3\\r 0\\\\s-7\\\\s0.0001\\s0\\\\s200\\s2\\\\s1.5000000000000002e-13\\\\s0\\\\s0\\s2\\\\s1e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.1\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s200\\s2\\\\s1.5000000000000002e-13\\\\s0\\\\s0\\s2\\\\s1e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.1\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s50\\s2\\\\s4e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A2\\s0\\\\s100\\s2\\\\s3.0000000000000003e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A0.2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s10\\s2\\\\s3e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A2\\s0\\\\s10\\s2\\\\s3e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s40\\\\s~lm317-qpl-A2\\s0\\\\s50\\s2\\\\s4e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s500\\s2\\\\s4e-13\\\\s0\\\\s0\\s2\\\\s2e-13\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A0.2\\s0\\\\s20\\s2\\\\s1e-11\\\\s0\\\\s0\\s2\\\\s5e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A5\\s0\\\\s2\\s2\\\\s1e-10\\\\s0\\\\s0\\s2\\\\s5e-11\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s80\\\\s~lm317-qnl-A50\\s2\\\\s~lm317-dz\\s2\\\\s~lm317-dz\\s2\\\\s~lm317-dz\\s0\\\\s310\\s0\\\\s310\\s0\\\\s190\\s0\\\\s82\\s0\\\\s5600\\s0\\\\s100000\\s0\\\\s130\\s0\\\\s12400\\s0\\\\s180\\s0\\\\s4100\\s0\\\\s5800\\s0\\\\s72\\s0\\\\s5100\\s0\\\\s12000\\s0\\\\s2400\\s0\\\\s6700\\s0\\\\s12000\\s0\\\\s130\\s0\\\\s370\\s0\\\\s13000\\s0\\\\s400\\s0\\\\s160\\s0\\\\s18000\\s0\\\\s160\\s0\\\\s3\\s0\\\\s0.1\\s2\\\\s3e-11\\\\s0\\\\s0\\s2\\\\s3e-11\\\\s0\\\\s0\\s2\\\\s5e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s1e-12\\\\s0\\\\s0"; String tl431 = ". ~TL431 0 1 3 3 A 2 0 1 C 1 0 0 ref 3 1 2 ResistorElm\\s3\\s18\\rCapacitorElm\\s18\\s4\\rCapacitorElm\\s18\\s1\\rTransistorElm\\s18\\s1\\s4\\s\\rResistorElm\\s4\\s5\\rResistorElm\\s5\\s6\\rResistorElm\\s5\\s7\\rResistorElm\\s6\\s19\\rCapacitorElm\\s19\\s2\\rCapacitorElm\\s19\\s6\\rTransistorElm\\s19\\s6\\s2\\s\\rResistorElm\\s6\\s20\\rCapacitorElm\\s20\\s8\\rCapacitorElm\\s20\\s7\\rTransistorElm\\s20\\s7\\s8\\s\\rResistorElm\\s8\\s2\\rResistorElm\\s4\\s21\\rCapacitorElm\\s21\\s10\\rCapacitorElm\\s21\\s9\\rTransistorElm\\s21\\s9\\s10\\s\\rResistorElm\\s10\\s11\\rResistorElm\\s7\\s22\\rCapacitorElm\\s22\\s2\\rCapacitorElm\\s22\\s11\\rTransistorElm\\s22\\s11\\s2\\s\\rResistorElm\\s13\\s23\\rCapacitorElm\\s23\\s2\\rCapacitorElm\\s23\\s12\\rTransistorElm\\s23\\s12\\s2\\s\\rResistorElm\\s9\\s24\\rCapacitorElm\\s24\\s14\\rCapacitorElm\\s24\\s9\\rTransistorElm\\s24\\s9\\s14\\s\\rResistorElm\\s9\\s25\\rCapacitorElm\\s25\\s15\\rCapacitorElm\\s25\\s12\\rTransistorElm\\s25\\s12\\s15\\s\\rResistorElm\\s1\\s14\\rResistorElm\\s1\\s15\\rResistorElm\\s12\\s26\\rCapacitorElm\\s26\\s16\\rCapacitorElm\\s26\\s1\\rTransistorElm\\s26\\s1\\s16\\s\\rResistorElm\\s17\\s16\\rResistorElm\\s17\\s27\\rCapacitorElm\\s27\\s2\\rCapacitorElm\\s27\\s1\\rTransistorElm\\s27\\s1\\s2\\s\\rResistorElm\\s17\\s2\\rResistorElm\\s12\\s28\\rCapacitorElm\\s28\\s3\\rCapacitorElm\\s28\\s12\\rTransistorElm\\s28\\s12\\s3\\s\\rDiodeElm\\s2\\s12\\rResistorElm\\s13\\s6\\rDiodeElm\\s2\\s1\\rCapacitorElm\\s1\\s12\\rCapacitorElm\\s7\\s11\\r 0\\\\s40\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed\\s0\\\\s3280\\s0\\\\s2400\\s0\\\\s7200\\s0\\\\s33.333333333333336\\s2\\\\s1.2e-12\\\\s0\\\\s0\\s2\\\\s2.4e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed-A1.2\\s0\\\\s18.18181818181818\\s2\\\\s2.2000000000000003e-12\\\\s0\\\\s0\\s2\\\\s4.400000000000001e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed-A2.2\\s0\\\\s800\\s0\\\\s40\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed\\s0\\\\s4000\\s0\\\\s40\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed\\s0\\\\s80\\s2\\\\s5e-13\\\\s0\\\\s0\\s2\\\\s1e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed-A0.5\\s0\\\\s80\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s3e-12\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s60\\\\s~tl431ed-qp_ed\\s0\\\\s80\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s3e-12\\\\s0\\\\s0\\s0\\\\s-1\\\\s0\\\\s0\\\\s60\\\\s~tl431ed-qp_ed\\s0\\\\s800\\s0\\\\s800\\s0\\\\s40\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed\\s0\\\\s150\\s0\\\\s8\\s2\\\\s5e-12\\\\s0\\\\s0\\s2\\\\s1e-11\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed-A5\\s0\\\\s10000\\s0\\\\s40\\s2\\\\s1e-12\\\\s0\\\\s0\\s2\\\\s2e-12\\\\s0\\\\s0\\s0\\\\s1\\\\s0\\\\s0\\\\s140\\\\s~tl431ed-qn_ed\\s2\\\\s~tl431ed-d_ed\\s0\\\\s1000\\s2\\\\s~tl431ed-d_ed\\s2\\\\s1e-11\\\\s0\\\\s0\\s2\\\\s2e-11\\\\s0\\\\s0"; - String models[] = { lm317, tl431 }; int i; for (i = 0; i != models.length; i++) { diff --git a/src/com/lushprojects/circuitjs1/client/CustomLogicElm.java b/src/com/lushprojects/circuitjs1/client/CustomLogicElm.java index ef0d9c18..cf2ceaa9 100644 --- a/src/com/lushprojects/circuitjs1/client/CustomLogicElm.java +++ b/src/com/lushprojects/circuitjs1/client/CustomLogicElm.java @@ -12,55 +12,54 @@ public class CustomLogicElm extends ChipElm { boolean patternValues[]; boolean highImpedance[]; static String lastModelName = "default"; - + public CustomLogicElm(int xx, int yy) { super(xx, yy); modelName = lastModelName; setupPins(); } - public CustomLogicElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + public CustomLogicElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); modelName = CustomLogicModel.unescape(st.nextToken()); updateModels(); int i; for (i = 0; i != getPostCount(); i++) { if (pins[i].output) { - volts[i] = new Double(st.nextToken()).doubleValue(); + volts[i] = Double.valueOf(st.nextToken()).doubleValue(); pins[i].value = volts[i] > getThreshold(); } } } - + String dump() { String s = super.dump(); s += " " + CustomLogicModel.escape(modelName); // the code to do this in ChipElm doesn't work here because we don't know - // how many pins to read until we read the model name! So we have to + // how many pins to read until we read the model name! So we have to // duplicate it here. - int i; - for (i = 0; i != getPostCount(); i++) { - if (pins[i].output) - s += " " + volts[i]; - } + int i; + for (i = 0; i != getPostCount(); i++) { + if (pins[i].output) + s += " " + volts[i]; + } return s; } - + String dumpModel() { if (model.dumped) return ""; return model.dump(); } - + public void updateModels() { model = CustomLogicModel.getModelWithNameOrCopy(modelName, model); setupPins(); allocNodes(); setPoints(); } - + @Override void setupPins() { if (modelName == null) { @@ -68,7 +67,7 @@ void setupPins() { allocNodes(); return; } - + model = CustomLogicModel.getModelWithName(modelName); inputCount = model.inputs.length; outputCount = model.outputs.length; @@ -76,7 +75,7 @@ void setupPins() { if (sizeY == 0) sizeY = 1; sizeX = 2; - postCount = inputCount+outputCount; + postCount = inputCount + outputCount; pins = new Pin[postCount]; int i; for (i = 0; i != inputCount; i++) { @@ -84,48 +83,56 @@ void setupPins() { pins[i].fixName(); } for (i = 0; i != outputCount; i++) { - pins[i+inputCount] = new Pin(i, SIDE_E, model.outputs[i]); - pins[i+inputCount].output = true; - pins[i+inputCount].fixName(); + pins[i + inputCount] = new Pin(i, SIDE_E, model.outputs[i]); + pins[i + inputCount].output = true; + pins[i + inputCount].fixName(); } lastValues = new boolean[postCount]; patternValues = new boolean[26]; highImpedance = new boolean[postCount]; } - int getPostCount() { return postCount; } - + int getPostCount() { + return postCount; + } + @Override int getVoltageSourceCount() { return outputCount; } - // keep track of whether we have any tri-state outputs. if not, then we can simplify things quite a bit, making the simulation faster - boolean hasTriState() { return model == null ? false : model.triState; } - - boolean nonLinear() { return hasTriState(); } - + // keep track of whether we have any tri-state outputs. if not, then we can + // simplify things quite a bit, making the simulation faster + boolean hasTriState() { + return model == null ? false : model.triState; + } + + boolean nonLinear() { + return hasTriState(); + } + int getInternalNodeCount() { - // for tri-state outputs, we need an internal node to connect a voltage source to, and then connect a resistor from there to the output. + // for tri-state outputs, we need an internal node to connect a voltage source + // to, and then connect a resistor from there to the output. // we do this for all outputs if any of them are tri-state - return (hasTriState()) ? outputCount : 0; + return (hasTriState()) ? outputCount : 0; } - + void stamp() { int i; int add = (hasTriState()) ? outputCount : 0; for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (p.output) { - sim.stampVoltageSource(0, nodes[i+add], p.voltSource); + sim.stampVoltageSource(0, nodes[i + add], p.voltSource); if (hasTriState()) { - sim.stampNonLinear(nodes[i+add]); + sim.stampNonLinear(nodes[i + add]); sim.stampNonLinear(nodes[i]); } } } } - + void doStep() { int i; for (i = 0; i != getPostCount(); i++) { @@ -138,12 +145,13 @@ void doStep() { for (i = 0; i != getPostCount(); i++) { Pin p = pins[i]; if (p.output) { - // connect output voltage source (to internal node if tri-state, otherwise connect directly to output) - sim.updateVoltageSource(0, nodes[i+add], p.voltSource, p.value ? highVoltage : 0); - + // connect output voltage source (to internal node if tri-state, otherwise + // connect directly to output) + sim.updateVoltageSource(0, nodes[i + add], p.voltSource, p.value ? highVoltage : 0); + // add resistor for tri-state if necessary if (hasTriState()) - sim.stampResistor(nodes[i+add], nodes[i], highImpedance[i] ? 1e8 : 1e-3); + sim.stampResistor(nodes[i + add], nodes[i], highImpedance[i] ? 1e8 : 1e-3); } } } @@ -161,62 +169,62 @@ void execute() { continue; break; } - + // don't care if (x == '?') continue; - + // up transition if (x == '+') { if (pins[j].value && !lastValues[j]) continue; break; } - + // down transition if (x == '-') { if (!pins[j].value && lastValues[j]) continue; break; } - + // save pattern values if (x >= 'a' && x <= 'z') { - patternValues[x-'a'] = pins[j].value; + patternValues[x - 'a'] = pins[j].value; continue; } - + // compare pattern values if (x >= 'A' && x <= 'z') { - if (patternValues[x-'A'] != pins[j].value) + if (patternValues[x - 'A'] != pins[j].value) break; continue; } } if (j != rl.length()) continue; - + // success String rr = model.rulesRight.get(i); for (j = 0; j != rr.length(); j++) { char x = rr.charAt(j); - highImpedance[j+inputCount] = false; + highImpedance[j + inputCount] = false; if (x >= 'a' && x <= 'z') - pins[j+inputCount].value = patternValues[x-'a']; + pins[j + inputCount].value = patternValues[x - 'a']; else if (x == '_') - highImpedance[j+inputCount] = true; + highImpedance[j + inputCount] = true; else - pins[j+inputCount].value = (x == '1'); + pins[j + inputCount].value = (x == '1'); } break; } - + // save values for transition checking int j; for (j = 0; j != postCount; j++) lastValues[j] = pins[j].value; } - + public EditInfo getChipEditInfo(int n) { if (n == 0) { EditInfo ei = new EditInfo("Model Name", 0, -1, -1); @@ -225,13 +233,13 @@ public EditInfo getChipEditInfo(int n) { return ei; } if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Edit Model")); - return ei; + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Edit Model")); + return ei; } return null; } - + public void setChipEditValue(int n, EditInfo ei) { if (n == 0) { String newModelName = ei.textf.getText(); @@ -251,8 +259,10 @@ public void setChipEditValue(int n, EditInfo ei) { return; } } - - int getDumpType() { return 208; } + + int getDumpType() { + return 208; + } void getInfo(String arr[]) { super.getInfo(arr); diff --git a/src/com/lushprojects/circuitjs1/client/CustomLogicModel.java b/src/com/lushprojects/circuitjs1/client/CustomLogicModel.java index 775c5cf0..97c1cf32 100644 --- a/src/com/lushprojects/circuitjs1/client/CustomLogicModel.java +++ b/src/com/lushprojects/circuitjs1/client/CustomLogicModel.java @@ -12,7 +12,7 @@ public class CustomLogicModel implements Editable { static int FLAG_SCHMITT = 1; static HashMap modelMap; - + int flags; String name; String[] inputs; @@ -22,10 +22,10 @@ public class CustomLogicModel implements Editable { Vector rulesLeft, rulesRight; boolean dumped; boolean triState; - + static CustomLogicModel getModelWithName(String name) { if (modelMap == null) - modelMap = new HashMap(); + modelMap = new HashMap(); CustomLogicModel lm = modelMap.get(name); if (lm != null) return lm; @@ -35,10 +35,10 @@ static CustomLogicModel getModelWithName(String name) { modelMap.put(name, lm); return lm; } - + static CustomLogicModel getModelWithNameOrCopy(String name, CustomLogicModel oldmodel) { if (modelMap == null) - modelMap = new HashMap(); + modelMap = new HashMap(); CustomLogicModel lm = modelMap.get(name); if (lm != null) return lm; @@ -48,17 +48,17 @@ static CustomLogicModel getModelWithNameOrCopy(String name, CustomLogicModel old modelMap.put(name, lm); return lm; } - + static void clearDumpedFlags() { if (modelMap == null) return; Iterator it = modelMap.entrySet().iterator(); while (it.hasNext()) { - Map.Entry pair = (Map.Entry)it.next(); + Map.Entry pair = (Map.Entry) it.next(); pair.getValue().dumped = false; } } - + CustomLogicModel() { inputs = listToArray("A,B"); outputs = listToArray("C,D"); @@ -66,7 +66,7 @@ static void clearDumpedFlags() { rulesRight = new Vector(); rules = ""; } - + CustomLogicModel(CustomLogicModel copy) { flags = copy.flags; inputs = copy.inputs; @@ -76,22 +76,22 @@ static void clearDumpedFlags() { rulesLeft = copy.rulesLeft; rulesRight = copy.rulesRight; } - + static void undumpModel(StringTokenizer st) { String name = unescape(st.nextToken()); CustomLogicModel model = getModelWithName(name); model.undump(st); } - + void undump(StringTokenizer st) { - flags = new Integer(st.nextToken()).intValue(); + flags = Integer.valueOf(st.nextToken()).intValue(); inputs = listToArray(unescape(st.nextToken())); outputs = listToArray(unescape(st.nextToken())); infoText = unescape(st.nextToken()); rules = unescape(st.nextToken()); parseRules(); } - + String arrayToList(String arr[]) { if (arr == null) return ""; @@ -103,42 +103,39 @@ String arrayToList(String arr[]) { x += "," + arr[i]; return x; } - - String [] listToArray(String arr) { + + String[] listToArray(String arr) { return arr.split(","); } - + public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("Inputs", 0, -1, -1); - ei.text = arrayToList(inputs); - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("Outputs", 0, -1, -1); - ei.text = arrayToList(outputs); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("Info Text", 0, -1, -1); - ei.text = infoText; - return ei; - } - if (n == 3) { - EditInfo ei = new EditInfo(EditInfo.makeLink("customlogic.html", "Definition"), 0, -1, -1); - ei.textArea = new TextArea(); - ei.textArea.setVisibleLines(5); - ei.textArea.setText(rules); - return ei; - } - /* - * not implemented - if (n == 4) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Schmitt", (flags & FLAG_SCHMITT) != 0); - return ei; - } - */ + if (n == 0) { + EditInfo ei = new EditInfo("Inputs", 0, -1, -1); + ei.text = arrayToList(inputs); + return ei; + } + if (n == 1) { + EditInfo ei = new EditInfo("Outputs", 0, -1, -1); + ei.text = arrayToList(outputs); + return ei; + } + if (n == 2) { + EditInfo ei = new EditInfo("Info Text", 0, -1, -1); + ei.text = infoText; + return ei; + } + if (n == 3) { + EditInfo ei = new EditInfo(EditInfo.makeLink("customlogic.html", "Definition"), 0, -1, -1); + ei.textArea = new TextArea(); + ei.textArea.setVisibleLines(5); + ei.textArea.setText(rules); + return ei; + } + /* + * not implemented if (n == 4) { EditInfo ei = new EditInfo("", 0, -1, -1); + * ei.checkbox = new Checkbox("Schmitt", (flags & FLAG_SCHMITT) != 0); return + * ei; } + */ return null; } @@ -174,7 +171,7 @@ void parseRules() { continue; String s0[] = s.replaceAll(" ", "").split("="); if (s0.length != 2) { - Window.alert("Error on line " + (i+1) + " of model description"); + Window.alert("Error on line " + (i + 1) + " of model description"); return; } if (s0[0].length() < inputs.length) { @@ -182,7 +179,7 @@ void parseRules() { return; } if (s0[0].length() > inputs.length + outputs.length) { - Window.alert("Model must have <= " + (inputs.length+outputs.length) + " digits on left side"); + Window.alert("Model must have <= " + (inputs.length + outputs.length) + " digits on left side"); return; } if (s0[1].length() != outputs.length) { @@ -200,15 +197,15 @@ void parseRules() { continue; } if (x < 'a' || x > 'z') { - Window.alert("Error on line " + (i+1) + " of model description"); + Window.alert("Error on line " + (i + 1) + " of model description"); return; } // if a letter appears twice, capitalize it the 2nd time so we can compare - if (used[x-'a']) { - newRl += (char)(x + 'A' - 'a'); + if (used[x - 'a']) { + newRl += (char) (x + 'A' - 'a'); continue; } - used[x-'a'] = true; + used[x - 'a'] = true; newRl += x; } String rr = s0[1]; @@ -218,45 +215,45 @@ void parseRules() { rulesRight.add(s0[1]); } } - + String dump() { dumped = true; if (rules.length() > 0 && !rules.endsWith("\n")) rules += "\n"; - return "! " + escape(name) + " " + flags + " " + escape(arrayToList(inputs)) + " " + - escape(arrayToList(outputs)) + " " + escape(infoText) + " " + escape(rules); + return "! " + escape(name) + " " + flags + " " + escape(arrayToList(inputs)) + " " + + escape(arrayToList(outputs)) + " " + escape(infoText) + " " + escape(rules); } - + static String escape(String s) { if (s.length() == 0) return "\\0"; - return s.replace("\\", "\\\\").replace("\n", "\\n").replace(" ", "\\s").replace("+", "\\p"). - replace("=", "\\q").replace("#", "\\h").replace("&", "\\a").replace("\r", "\\r"); + return s.replace("\\", "\\\\").replace("\n", "\\n").replace(" ", "\\s").replace("+", "\\p").replace("=", "\\q") + .replace("#", "\\h").replace("&", "\\a").replace("\r", "\\r"); } - + static String unescape(String s) { if (s.equals("\\0")) return ""; int i; for (i = 0; i < s.length(); i++) { if (s.charAt(i) == '\\') { - char c = s.charAt(i+1); + char c = s.charAt(i + 1); if (c == 'n') - s = s.substring(0, i) + "\n" + s.substring(i+2); + s = s.substring(0, i) + "\n" + s.substring(i + 2); else if (c == 'r') - s = s.substring(0, i) + "\r" + s.substring(i+2); + s = s.substring(0, i) + "\r" + s.substring(i + 2); else if (c == 's') - s = s.substring(0, i) + " " + s.substring(i+2); + s = s.substring(0, i) + " " + s.substring(i + 2); else if (c == 'p') - s = s.substring(0, i) + "+" + s.substring(i+2); + s = s.substring(0, i) + "+" + s.substring(i + 2); else if (c == 'q') - s = s.substring(0, i) + "=" + s.substring(i+2); + s = s.substring(0, i) + "=" + s.substring(i + 2); else if (c == 'h') - s = s.substring(0, i) + "#" + s.substring(i+2); + s = s.substring(0, i) + "#" + s.substring(i + 2); else if (c == 'a') - s = s.substring(0, i) + "&" + s.substring(i+2); + s = s.substring(0, i) + "&" + s.substring(i + 2); else - s = s.substring(0, i) + s.substring(i+1); + s = s.substring(0, i) + s.substring(i + 1); } } return s; diff --git a/src/com/lushprojects/circuitjs1/client/CustomTransformerElm.java b/src/com/lushprojects/circuitjs1/client/CustomTransformerElm.java index e8ada3e7..3c881ba5 100644 --- a/src/com/lushprojects/circuitjs1/client/CustomTransformerElm.java +++ b/src/com/lushprojects/circuitjs1/client/CustomTransformerElm.java @@ -22,434 +22,454 @@ import com.google.gwt.user.client.Window; class CustomTransformerElm extends CircuitElm { - double coilCurrents[], coilInductances[], coilCurCounts[], coilCurSourceValues[], coilPolarities[]; - double nodeCurrents[], nodeCurCounts[]; - - // node number n of first node of each coil (second node = n+1) - int coilNodes[]; - - int coilCount, nodeCount; - - // number of primary coils - int primaryCoils; - - Point nodePoints[], nodeTaps[], ptCore[]; - String description; - double inductance, couplingCoef; - boolean needDots; - - Point dots[]; - int width; - - public CustomTransformerElm(int xx, int yy) { - super(xx, yy); - inductance = 4; - width = 32; - noDiagonal = true; - couplingCoef = .999; - description = "1,1:1"; - parseDescription(description); + double coilCurrents[], coilInductances[], coilCurCounts[], coilCurSourceValues[], coilPolarities[]; + double nodeCurrents[], nodeCurCounts[]; + + // node number n of first node of each coil (second node = n+1) + int coilNodes[]; + + int coilCount, nodeCount; + + // number of primary coils + int primaryCoils; + + Point nodePoints[], nodeTaps[], ptCore[]; + String description; + double inductance, couplingCoef; + boolean needDots; + + Point dots[]; + int width; + + public CustomTransformerElm(int xx, int yy) { + super(xx, yy); + inductance = 4; + width = 32; + noDiagonal = true; + couplingCoef = .999; + description = "1,1:1"; + parseDescription(description); + } + + public CustomTransformerElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + width = 32; // max(32, abs(yb-ya)); + inductance = Double.valueOf(st.nextToken()).doubleValue(); + couplingCoef = Double.valueOf(st.nextToken()).doubleValue(); + String str = st.nextToken(); + description = CustomLogicModel.unescape(str); + coilCount = Integer.valueOf(st.nextToken()).intValue(); + int i; + coilCurrents = new double[coilCount]; + for (i = 0; i != coilCount; i++) + coilCurrents[i] = Double.valueOf(st.nextToken()).doubleValue(); + noDiagonal = true; + parseDescription(description); + } + + void drag(int xx, int yy) { + xx = sim.snapGrid(xx); + yy = sim.snapGrid(yy); + // width = max(32, abs(yy-y)); + if (xx == x) + yy = y; + x2 = xx; + y2 = yy; + setPoints(); + } + + int getDumpType() { + return 406; + } + + String dump() { + String s = super.dump() + " " + inductance + " " + couplingCoef + " " + CustomLogicModel.escape(description) + + " " + coilCount + " "; + int i; + for (i = 0; i != coilCount; i++) { + s += coilCurrents[i] + " "; } - public CustomTransformerElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - width = 32; // max(32, abs(yb-ya)); - inductance = new Double(st.nextToken()).doubleValue(); - couplingCoef = new Double(st.nextToken()).doubleValue(); - String str = st.nextToken(); - description = CustomLogicModel.unescape(str); - coilCount = new Integer(st.nextToken()).intValue(); - int i; + return s; + } + + void parseDescription() { + parseDescription(description); + } + + boolean parseDescription(String desc) { + // a number indicates a coil (number = turns ratio to base inductance coil) + // (negative number = reverse polarity) + // : separates primary and secondary + // , separates two coils + // + separates two connected coils (tapped) + StringTokenizer st = new StringTokenizer(desc, ",:+", true); + + // count coils/nodes + coilCount = nodeCount = 0; + while (st.hasMoreTokens()) { + String s = st.nextToken(); + if (s == "+") + nodeCount--; + if (s == "," || s == "+" || s == ":") + continue; + nodeCount += 2; + coilCount++; + } + + coilNodes = new int[coilCount]; + coilInductances = new double[coilCount]; + // save coil currents if possible (needed for undumping) + if (coilCurrents == null || coilCurrents.length != coilCount) coilCurrents = new double[coilCount]; - for (i = 0; i != coilCount; i++) - coilCurrents[i] = new Double(st.nextToken()).doubleValue(); - noDiagonal = true; - parseDescription(description); + coilCurCounts = new double[coilCount]; + coilCurSourceValues = new double[coilCount]; + coilPolarities = new double[coilCount]; + nodePoints = newPointArray(nodeCount); + nodeTaps = newPointArray(nodeCount); + nodeCurrents = new double[nodeCount]; + nodeCurCounts = new double[nodeCount]; + + // start over + st = new StringTokenizer(desc, ",:+", true); + int nodeNum = 0; + int coilNum = 0; + primaryCoils = 0; + boolean secondary = false; + needDots = false; + while (true) { + String tok = st.nextToken(); + double n = 0; + try { + n = Double.parseDouble(tok); + } catch (Exception e) { + return false; + } + if (n == 0) + return false; + // create new coil + coilNodes[coilNum] = nodeNum; + coilInductances[coilNum] = n * n * inductance; + coilPolarities[coilNum] = 1; + if (n < 0) { + coilPolarities[coilNum] = -1; + needDots = true; + } + nodeNum += 2; + coilNum++; + if (!secondary) + primaryCoils = coilNum; + if (!st.hasMoreTokens()) + break; + tok = st.nextToken(); + if (tok == ",") + continue; + if (tok == "+") { + nodeNum--; + continue; + } + if (tok == ":") { + // switch to secondary + if (secondary) + return false; + secondary = true; + continue; + } + return false; } - void drag(int xx, int yy) { - xx = sim.snapGrid(xx); - yy = sim.snapGrid(yy); -// width = max(32, abs(yy-y)); - if (xx == x) - yy = y; - x2 = xx; y2 = yy; - setPoints(); + allocNodes(); + setPoints(); + return true; + } + + boolean isTrapezoidal() { + return (flags & Inductor.FLAG_BACK_EULER) == 0; + } + + void draw(Graphics g) { + int i; + + // draw taps + for (i = 0; i != getPostCount(); i++) { + setVoltageColor(g, volts[i]); + drawThickLine(g, nodePoints[i], nodeTaps[i]); } - int getDumpType() { return 406; } - String dump() { - String s = super.dump() + " " + inductance + " " + couplingCoef + " " + CustomLogicModel.escape(description) + " " + coilCount + " "; - int i; - for (i = 0; i != coilCount; i++) { - s += coilCurrents[i] + " "; + + // draw coils + for (i = 0; i != coilCount; i++) { + int n = coilNodes[i]; + setVoltageColor(g, volts[n]); + setPowerColor(g, coilCurrents[i] * (volts[n] - volts[n + 1])); + drawCoil(g, (i >= primaryCoils ? -6 : 6), nodeTaps[n], nodeTaps[n + 1], volts[n], volts[n + 1]); + if (dots != null) { + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + g.fillOval(dots[i].x - 2, dots[i].y - 2, 5, 5); } - return s; } - - void parseDescription() { - parseDescription(description); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + + // draw core + for (i = 0; i != 2; i++) { + drawThickLine(g, ptCore[i], ptCore[i + 2]); } - - boolean parseDescription(String desc) { - // a number indicates a coil (number = turns ratio to base inductance coil) - // (negative number = reverse polarity) - // : separates primary and secondary - // , separates two coils - // + separates two connected coils (tapped) - StringTokenizer st = new StringTokenizer(desc, ",:+", true); - - // count coils/nodes - coilCount = nodeCount = 0; - while (st.hasMoreTokens()) { - String s = st.nextToken(); - if (s == "+") - nodeCount--; - if (s == "," || s == "+" || s == ":") - continue; - nodeCount += 2; - coilCount++; - } - - coilNodes = new int[coilCount]; - coilInductances = new double[coilCount]; - // save coil currents if possible (needed for undumping) - if (coilCurrents == null || coilCurrents.length != coilCount) - coilCurrents = new double[coilCount]; - coilCurCounts = new double[coilCount]; - coilCurSourceValues = new double[coilCount]; - coilPolarities = new double[coilCount]; - nodePoints = newPointArray(nodeCount); - nodeTaps = newPointArray(nodeCount); - nodeCurrents = new double[nodeCount]; - nodeCurCounts = new double[nodeCount]; - - // start over - st = new StringTokenizer(desc, ",:+", true); - int nodeNum = 0; - int coilNum = 0; - primaryCoils = 0; - boolean secondary = false; - needDots = false; - while (true) { - String tok = st.nextToken(); - double n = 0; - try { - n = Double.parseDouble(tok); - } catch (Exception e) { return false; } - if (n == 0) - return false; - // create new coil - coilNodes[coilNum] = nodeNum; - coilInductances[coilNum] = n*n*inductance; - coilPolarities[coilNum] = 1; - if (n < 0) { - coilPolarities[coilNum] = -1; - needDots = true; - } - nodeNum += 2; - coilNum++; - if (!secondary) - primaryCoils = coilNum; - if (!st.hasMoreTokens()) - break; - tok = st.nextToken(); - if (tok == ",") - continue; - if (tok == "+") { - nodeNum--; - continue; + + // draw coil currents + for (i = 0; i != coilCount; i++) { + coilCurCounts[i] = updateDotCount(coilCurrents[i], coilCurCounts[i]); + int ni = coilNodes[i]; + drawDots(g, nodeTaps[ni], nodeTaps[ni + 1], coilCurCounts[i]); + } + + // draw tap currents + for (i = 0; i != nodeCount; i++) { + nodeCurCounts[i] = updateDotCount(nodeCurrents[i], nodeCurCounts[i]); + drawDots(g, nodePoints[i], nodeTaps[i], nodeCurCounts[i]); + } + + drawPosts(g); + setBbox(nodePoints[0], nodePoints[nodeCount - 1], 0); + adjustBbox(ptCore[0], ptCore[3]); + } + + void setPoints() { + super.setPoints(); + point2.y = point1.y; + int i; + int primaryNodes = (primaryCoils == coilCount) ? nodeCount : coilNodes[primaryCoils]; + dn = Math.abs(point1.x - point2.x); + double ce = .5 - 12 / dn; + double cd = .5 - 2 / dn; + double maxWidth = 0; + int step; + for (step = 0; step != 2; step++) { + int c = 0; + double offset = 0; + for (i = 0; i != nodeCount; i++) { + if (i == primaryNodes) + offset = 0; + if (step == 1) { + if (i == primaryNodes - 1 || i == nodeCount - 1) + offset = maxWidth; + interpPoint(point1, point2, nodePoints[i], i < primaryNodes ? 0 : 1, -offset); + interpPoint(point1, point2, nodeTaps[i], i < primaryNodes ? ce : 1 - ce, -offset); } - if (tok == ":") { - // switch to secondary - if (secondary) - return false; - secondary = true; - continue; + maxWidth = Math.max(maxWidth, offset); + int nn = c < coilCount ? coilNodes[c] : -1; + if (nn == i) { + // this is first node of a coil, make room + c++; + offset += width; + } else { + // this is last node of a coil, make small gap + offset += 16; } - return false; } - allocNodes(); - setPoints(); - return true; } - - boolean isTrapezoidal() { return (flags & Inductor.FLAG_BACK_EULER) == 0; } - void draw(Graphics g) { - int i; - - // draw taps - for (i = 0; i != getPostCount(); i++) { - setVoltageColor(g, volts[i]); - drawThickLine(g, nodePoints[i], nodeTaps[i]); - } - - // draw coils + ptCore = newPointArray(4); + for (i = 0; i != 4; i += 2) { + double h = (i == 2) ? -maxWidth : 0; + interpPoint(point1, point2, ptCore[i], cd, h); + interpPoint(point1, point2, ptCore[i + 1], 1 - cd, h); + } + + if (needDots) { + dots = new Point[coilCount]; + double dotp = Math.abs(7. / width); for (i = 0; i != coilCount; i++) { int n = coilNodes[i]; - setVoltageColor(g, volts[n]); - setPowerColor(g, coilCurrents[i]*(volts[n]-volts[n+1])); - drawCoil(g, (i >= primaryCoils ? -6 : 6), nodeTaps[n], nodeTaps[n+1], volts[n], volts[n+1]); - if (dots != null) { - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - g.fillOval(dots[i].x-2, dots[i].y-2, 5, 5); - } - } - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - - // draw core - for (i = 0; i != 2; i++) { - drawThickLine(g, ptCore[i], ptCore[i+2]); + dots[i] = interpPoint(nodeTaps[n], nodeTaps[n + 1], coilPolarities[i] > 0 ? dotp : 1 - dotp, + i < primaryCoils ? -7 : 7); } - - // draw coil currents - for (i = 0; i != coilCount; i++) { - coilCurCounts[i] = updateDotCount(coilCurrents[i], coilCurCounts[i]); + } else + dots = null; + } + + Point getPost(int n) { + return nodePoints[n]; + } + + int getPostCount() { + return nodeCount; + } + + void reset() { + int i; + for (i = 0; i != coilCount; i++) + coilCurrents[i] = coilCurSourceValues[i] = coilCurCounts[i] = 0; + for (i = 0; i != nodeCount; i++) + volts[i] = nodeCurrents[i] = nodeCurCounts[i] = 0; + } + + double xformMatrix[][]; + + void stamp() { + // equations for transformer: + // v1 = L1 di1/dt + M12 di2/dt + M13 di3/dt + ... + // v2 = M21 di1/dt + L2 di2/dt + M23 di3/dt + ... + // v3 = ... (one row for each coil) + // we invert that to get: + // di1/dt = a1 v1 + a2 v2 + ... + // di2/dt = a3 v1 + a4 v2 + ... + // integrate di1/dt using trapezoidal approx and we get: + // i1(t2) = i1(t1) + dt/2 (i1(t1) + i1(t2)) + // = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1) + ... + + // a1 dt/2 v1(t2) + a2 dt/2 v2(t2) + ... + // the norton equivalent of this for i1 is: + // a. current source, I = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1) + ... + // b. resistor, G = a1 dt/2 + // c. current source controlled by voltage v2, G = a2 dt/2 + // and for i2: + // a. current source, I = i2(t1) + a3 dt/2 v1(t1) + a4 dt/2 v2(t1) + ... + // b. resistor, G = a3 dt/2 + // c. current source controlled by voltage v2, G = a4 dt/2 + // + // For backward euler, the current source value is just i1(t1) and we use + // dt instead of dt/2 for the resistor and VCCS. + xformMatrix = new double[coilCount][coilCount]; + int i; + // fill diagonal + for (i = 0; i != coilCount; i++) + xformMatrix[i][i] = coilInductances[i]; + int j; + // fill off-diagonal + for (i = 0; i != coilCount; i++) + for (j = 0; j != i; j++) + xformMatrix[i][j] = xformMatrix[j][i] = couplingCoef + * Math.sqrt(coilInductances[i] * coilInductances[j]) * coilPolarities[i] * coilPolarities[j]; + + CirSim.invertMatrix(xformMatrix, coilCount); + + double ts = isTrapezoidal() ? sim.timeStep / 2 : sim.timeStep; + for (i = 0; i != coilCount; i++) + for (j = 0; j != coilCount; j++) { + // multiply in dt/2 (or dt for backward euler) + xformMatrix[i][j] *= ts; int ni = coilNodes[i]; - drawDots(g, nodeTaps[ni], nodeTaps[ni+1], coilCurCounts[i]); - } - - // draw tap currents - for (i = 0; i != nodeCount; i++) { - nodeCurCounts[i] = updateDotCount(nodeCurrents[i], nodeCurCounts[i]); - drawDots(g, nodePoints[i], nodeTaps[i], nodeCurCounts[i]); + int nj = coilNodes[j]; + if (i == j) + sim.stampConductance(nodes[ni], nodes[ni + 1], xformMatrix[i][i]); + else + sim.stampVCCurrentSource(nodes[ni], nodes[ni + 1], nodes[nj], nodes[nj + 1], xformMatrix[i][j]); } - - drawPosts(g); - setBbox(nodePoints[0], nodePoints[nodeCount-1], 0); - adjustBbox(ptCore[0], ptCore[3]); - } - - void setPoints() { - super.setPoints(); - point2.y = point1.y; - int i; - int primaryNodes = (primaryCoils == coilCount) ? nodeCount : coilNodes[primaryCoils]; - dn = Math.abs(point1.x-point2.x); - double ce = .5-12/dn; - double cd = .5-2/dn; - double maxWidth = 0; - int step; - for (step = 0; step != 2; step++) { - int c = 0; - double offset = 0; - for (i = 0; i != nodeCount; i++) { - if (i == primaryNodes) - offset = 0; - if (step == 1) { - if (i == primaryNodes-1 || i == nodeCount-1) - offset = maxWidth; - interpPoint(point1, point2, nodePoints[i], i < primaryNodes ? 0 : 1, -offset); - interpPoint(point1, point2, nodeTaps[i] , i < primaryNodes ? ce : 1-ce, -offset); - } - maxWidth = Math.max(maxWidth, offset); - int nn = c < coilCount ? coilNodes[c] : -1; - if (nn == i) { - // this is first node of a coil, make room - c++; - offset += width; - } else { - // this is last node of a coil, make small gap - offset += 16; - } + for (i = 0; i != nodeCount; i++) + sim.stampRightSide(nodes[i]); + } + + void startIteration() { + int i; + for (i = 0; i != coilCount; i++) { + double val = coilCurrents[i]; + if (isTrapezoidal()) { + int j; + for (j = 0; j != coilCount; j++) { + int n = coilNodes[j]; + double voltdiff = volts[n] - volts[n + 1]; + val += voltdiff * xformMatrix[i][j]; } } - ptCore = newPointArray(4); - for (i = 0; i != 4; i += 2) { - double h = (i == 2) ? -maxWidth : 0; - interpPoint(point1, point2, ptCore[i], cd, h); - interpPoint(point1, point2, ptCore[i+1], 1-cd, h); - } - - if (needDots) { - dots = new Point[coilCount]; - double dotp = Math.abs(7./width); - for (i = 0; i != coilCount; i++) { - int n = coilNodes[i]; - dots[i] = interpPoint(nodeTaps[n], nodeTaps[n+1], coilPolarities[i] > 0 ? dotp : 1-dotp, i < primaryCoils ? -7 : 7); - } - } else - dots = null; - } - Point getPost(int n) { - return nodePoints[n]; + coilCurSourceValues[i] = val; } - int getPostCount() { return nodeCount; } - void reset() { - int i; - for (i = 0; i != coilCount; i++) - coilCurrents[i] = coilCurSourceValues[i] = coilCurCounts[i] = 0; - for (i = 0; i != nodeCount; i++) - volts[i] = nodeCurrents[i] = nodeCurCounts[i] = 0; + } + + void doStep() { + int i; + for (i = 0; i != coilCount; i++) { + int n = coilNodes[i]; + sim.stampCurrentSource(nodes[n], nodes[n + 1], coilCurSourceValues[i]); } - double xformMatrix[][]; - - void stamp() { - // equations for transformer: - // v1 = L1 di1/dt + M12 di2/dt + M13 di3/dt + ... - // v2 = M21 di1/dt + L2 di2/dt + M23 di3/dt + ... - // v3 = ... (one row for each coil) - // we invert that to get: - // di1/dt = a1 v1 + a2 v2 + ... - // di2/dt = a3 v1 + a4 v2 + ... - // integrate di1/dt using trapezoidal approx and we get: - // i1(t2) = i1(t1) + dt/2 (i1(t1) + i1(t2)) - // = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1) + ... + - // a1 dt/2 v1(t2) + a2 dt/2 v2(t2) + ... - // the norton equivalent of this for i1 is: - // a. current source, I = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1) + ... - // b. resistor, G = a1 dt/2 - // c. current source controlled by voltage v2, G = a2 dt/2 - // and for i2: - // a. current source, I = i2(t1) + a3 dt/2 v1(t1) + a4 dt/2 v2(t1) + ... - // b. resistor, G = a3 dt/2 - // c. current source controlled by voltage v2, G = a4 dt/2 - // - // For backward euler, the current source value is just i1(t1) and we use - // dt instead of dt/2 for the resistor and VCCS. - xformMatrix = new double[coilCount][coilCount]; - int i; - // fill diagonal - for (i = 0; i != coilCount; i++) - xformMatrix[i][i] = coilInductances[i]; - int j; - // fill off-diagonal - for (i = 0; i != coilCount; i++) - for (j = 0; j != i; j++) - xformMatrix[i][j] = xformMatrix[j][i] = couplingCoef*Math.sqrt(coilInductances[i]*coilInductances[j])*coilPolarities[i]*coilPolarities[j]; - - CirSim.invertMatrix(xformMatrix, coilCount); - - double ts = isTrapezoidal() ? sim.timeStep/2 : sim.timeStep; - for (i = 0; i != coilCount; i++) + } + + void calculateCurrent() { + int i; + for (i = 0; i != nodeCount; i++) + nodeCurrents[i] = 0; + for (i = 0; i != coilCount; i++) { + double val = coilCurSourceValues[i]; + if (xformMatrix != null) { + int j; for (j = 0; j != coilCount; j++) { - // multiply in dt/2 (or dt for backward euler) - xformMatrix[i][j] *= ts; - int ni = coilNodes[i]; - int nj = coilNodes[j]; - if (i == j) - sim.stampConductance(nodes[ni], nodes[ni+1], xformMatrix[i][i]); - else - sim.stampVCCurrentSource(nodes[ni], nodes[ni+1], nodes[nj], nodes[nj+1], xformMatrix[i][j]); + int n = coilNodes[j]; + double voltdiff = volts[n] - volts[n + 1]; + val += voltdiff * xformMatrix[i][j]; } - for (i = 0; i != nodeCount; i++) - sim.stampRightSide(nodes[i]); - } - - void startIteration() { - int i; - for (i = 0; i != coilCount; i++) { - double val = coilCurrents[i]; - if (isTrapezoidal()) { - int j; - for (j = 0; j != coilCount; j++) { - int n = coilNodes[j]; - double voltdiff = volts[n]-volts[n+1]; - val += voltdiff*xformMatrix[i][j]; - } - } - coilCurSourceValues[i] = val; } + coilCurrents[i] = val; + int ni = coilNodes[i]; + nodeCurrents[ni] += val; + nodeCurrents[ni + 1] -= val; } - - void doStep() { - int i; - for (i = 0; i != coilCount; i++) { - int n = coilNodes[i]; - sim.stampCurrentSource(nodes[n], nodes[n+1], coilCurSourceValues[i]); - } - } - - void calculateCurrent() { - int i; - for (i = 0; i != nodeCount; i++) - nodeCurrents[i] = 0; - for (i = 0; i != coilCount; i++) { - double val = coilCurSourceValues[i]; - if (xformMatrix != null) { - int j; - for (j = 0; j != coilCount; j++) { - int n = coilNodes[j]; - double voltdiff = volts[n]-volts[n+1]; - val += voltdiff*xformMatrix[i][j]; - } - } - coilCurrents[i] = val; - int ni = coilNodes[i]; - nodeCurrents[ni] += val; - nodeCurrents[ni+1] -= val; - } + } + + @Override + double getCurrentIntoNode(int n) { + return -nodeCurrents[n]; + } + + void getInfo(String arr[]) { + arr[0] = "transformer (custom)"; + arr[1] = "L = " + getUnitText(inductance, "H"); + int i; + for (i = 0; i != coilCount; i++) { + if (2 + i * 2 >= arr.length) + break; + int ni = coilNodes[i]; + arr[2 + i * 2] = "Vd" + (i + 1) + " = " + getVoltageText(volts[ni] - volts[ni + 1]); + arr[3 + i * 2] = "I" + (i + 1) + " = " + getCurrentText(coilCurrents[i]); } - - @Override double getCurrentIntoNode(int n) { - return -nodeCurrents[n]; + } + + boolean getConnection(int n1, int n2) { + int i; + for (i = 0; i != coilCount; i++) + if (comparePair(n1, n2, coilNodes[i], coilNodes[i] + 1)) + return true; + return false; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Base Inductance (H)", inductance, .01, 5); + if (n == 1) { + EditInfo ei = new EditInfo(EditInfo.makeLink("customtransformer.html", "Description"), 0, -1, -1); + ei.text = description; + ei.disallowSliders(); + return ei; } - - void getInfo(String arr[]) { - arr[0] = "transformer (custom)"; - arr[1] = "L = " + getUnitText(inductance, "H"); - int i; - for (i = 0; i != coilCount ; i++) { - if (2+i*2 >= arr.length) - break; - int ni = coilNodes[i]; - arr[2+i*2] = "Vd" + (i+1) + " = " + getVoltageText(volts[ni]-volts[ni+1]); - arr[3+i*2] = "I" + (i+1) + " = " + getCurrentText(coilCurrents[i]); - } + if (n == 2) + return new EditInfo("Coupling Coefficient", couplingCoef, 0, 1).setDimensionless(); + if (n == 3) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Trapezoidal Approximation", isTrapezoidal()); + return ei; } - - boolean getConnection(int n1, int n2) { - int i; - for (i = 0; i != coilCount; i++) - if (comparePair(n1, n2, coilNodes[i], coilNodes[i]+1)) - return true; - return false; + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) { + inductance = ei.value; + parseDescription(); } - - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Base Inductance (H)", inductance, .01, 5); - if (n == 1) { - EditInfo ei = new EditInfo(EditInfo.makeLink("customtransformer.html", "Description"), 0, -1, -1); - ei.text = description; - ei.disallowSliders(); - return ei; - } - if (n == 2) - return new EditInfo("Coupling Coefficient", couplingCoef, 0, 1). - setDimensionless(); - if (n == 3) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Trapezoidal Approximation", - isTrapezoidal()); - return ei; + if (n == 1) { + String s = ei.textf.getText(); + if (s != description) { + if (!parseDescription(s)) { + parseDescription(description); + Window.alert("Parse error in description"); + } else + description = s; + setPoints(); } - return null; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) { - inductance = ei.value; - parseDescription(); - } - if (n == 1) { - String s = ei.textf.getText(); - if (s != description) { - if (!parseDescription(s)) { - parseDescription(description); - Window.alert("Parse error in description"); - } else - description = s; - setPoints(); - } - } - if (n == 2 && ei.value > 0 && ei.value < 1) { - couplingCoef = ei.value; - parseDescription(); - } - if (n == 3) { - if (ei.checkbox.getState()) - flags &= ~Inductor.FLAG_BACK_EULER; - else - flags |= Inductor.FLAG_BACK_EULER; - parseDescription(); - } + if (n == 2 && ei.value > 0 && ei.value < 1) { + couplingCoef = ei.value; + parseDescription(); + } + if (n == 3) { + if (ei.checkbox.getState()) + flags &= ~Inductor.FLAG_BACK_EULER; + else + flags |= Inductor.FLAG_BACK_EULER; + parseDescription(); } } +} diff --git a/src/com/lushprojects/circuitjs1/client/DACElm.java b/src/com/lushprojects/circuitjs1/client/DACElm.java index 89fed9b6..b2351513 100644 --- a/src/com/lushprojects/circuitjs1/client/DACElm.java +++ b/src/com/lushprojects/circuitjs1/client/DACElm.java @@ -20,52 +20,76 @@ package com.lushprojects.circuitjs1.client; class DACElm extends ChipElm { - public DACElm(int xx, int yy) { super(xx, yy); } - public DACElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + public DACElm(int xx, int yy) { + super(xx, yy); + } + + public DACElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } - String getChipName() { return "DAC"; } - boolean needsBits() { return true; } + + String getChipName() { + return "DAC"; + } + + boolean needsBits() { + return true; + } + void setupPins() { sizeX = 2; sizeY = bits > 2 ? bits : 2; pins = new Pin[getPostCount()]; int i; for (i = 0; i != bits; i++) - pins[i] = new Pin(bits-1-i, SIDE_W, "D" + i); - pins[bits] = new Pin(0, SIDE_E, "O"); + pins[i] = new Pin(bits - 1 - i, SIDE_W, "D" + i); + pins[bits] = new Pin(0, SIDE_E, "O"); pins[bits].output = true; - pins[bits+1] = new Pin(sizeY-1, SIDE_E, "V+"); + pins[bits + 1] = new Pin(sizeY - 1, SIDE_E, "V+"); allocNodes(); } + void doStep() { int ival = 0; int i; for (i = 0; i != bits; i++) if (volts[i] > getThreshold()) - ival |= 1<= 2) { - bits = (int)ei.value; - setupPins(); - setPoints(); - } + if (n == 0 && ei.value >= 2) { + bits = (int) ei.value; + setupPins(); + setPoints(); + } } } diff --git a/src/com/lushprojects/circuitjs1/client/DCMotorElm.java b/src/com/lushprojects/circuitjs1/client/DCMotorElm.java index cc0c252b..bd2720c1 100644 --- a/src/com/lushprojects/circuitjs1/client/DCMotorElm.java +++ b/src/com/lushprojects/circuitjs1/client/DCMotorElm.java @@ -4,57 +4,73 @@ // based on https://ctms.engin.umich.edu/CTMS/index.php?example=MotorPosition§ion=SystemModeling - class DCMotorElm extends CircuitElm { Inductor ind, indInertia; // Electrical parameters double resistance, inductance; // Electro-mechanical parameters - double K, Kb, J, b, gearRatio, tau; //tau reserved for static friction parameterization + double K, Kb, J, b, gearRatio, tau; // tau reserved for static friction parameterization public double angle; public double speed; - - double coilCurrent; double inertiaCurrent; int[] voltSources = new int[2]; - public DCMotorElm(int xx, int yy) { - super(xx, yy); + + public DCMotorElm(int xx, int yy) { + super(xx, yy); ind = new Inductor(sim); indInertia = new Inductor(sim); - inductance = .5; resistance = 1; angle = pi/2; speed = 0; K = 0.15; b= 0.05; J = 0.02; Kb = 0.15; gearRatio=1; tau=0; + inductance = .5; + resistance = 1; + angle = pi / 2; + speed = 0; + K = 0.15; + b = 0.05; + J = 0.02; + Kb = 0.15; + gearRatio = 1; + tau = 0; ind.setup(inductance, 0, Inductor.FLAG_BACK_EULER); indInertia.setup(J, 0, Inductor.FLAG_BACK_EULER); } - public DCMotorElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public DCMotorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - angle = pi/2;speed = 0; - //read: + angle = pi / 2; + speed = 0; + // read: // inductance; resistance, K, Kb, J, b, gearRatio, tau - inductance = new Double(st.nextToken()).doubleValue(); - resistance = new Double(st.nextToken()).doubleValue(); - K = new Double(st.nextToken()).doubleValue(); - Kb = new Double(st.nextToken()).doubleValue(); - J = new Double(st.nextToken()).doubleValue(); - b = new Double(st.nextToken()).doubleValue(); - gearRatio = new Double(st.nextToken()).doubleValue(); - tau = new Double(st.nextToken()).doubleValue(); + inductance = Double.valueOf(st.nextToken()).doubleValue(); + resistance = Double.valueOf(st.nextToken()).doubleValue(); + K = Double.valueOf(st.nextToken()).doubleValue(); + Kb = Double.valueOf(st.nextToken()).doubleValue(); + J = Double.valueOf(st.nextToken()).doubleValue(); + b = Double.valueOf(st.nextToken()).doubleValue(); + gearRatio = Double.valueOf(st.nextToken()).doubleValue(); + tau = Double.valueOf(st.nextToken()).doubleValue(); ind = new Inductor(sim); indInertia = new Inductor(sim); ind.setup(inductance, 0, Inductor.FLAG_BACK_EULER); indInertia.setup(J, 0, Inductor.FLAG_BACK_EULER); } - int getDumpType() { return 415; } + + int getDumpType() { + return 415; + } + String dump() { // dump: inductance; resistance, K, Kb, J, b, gearRatio, tau - return super.dump() + " " + inductance + " " + resistance + " " + K + " " + Kb + " " + J + " " + b + " " + gearRatio + " " + tau; + return super.dump() + " " + inductance + " " + resistance + " " + K + " " + Kb + " " + J + " " + b + " " + + gearRatio + " " + tau; + } + + public double getAngle() { + return (angle); } - public double getAngle(){ return(angle);} Point motorCenter; @@ -64,116 +80,134 @@ void setPoints() { motorCenter = interpPoint(point1, point2, .5); allocNodes(); } - int getPostCount() { return 2; } - int getInternalNodeCount() { return 4; } - int getVoltageSourceCount() { return 2; } - void setVoltageSource(int n, int v) { voltSources[n] = v; } + + int getPostCount() { + return 2; + } + + int getInternalNodeCount() { + return 4; + } + + int getVoltageSourceCount() { + return 2; + } + + void setVoltageSource(int n, int v) { + voltSources[n] = v; + } + void reset() { super.reset(); ind.reset(); indInertia.reset(); - coilCurrent = 0; + coilCurrent = 0; inertiaCurrent = 0; } void stamp() { - // stamp a bunch of internal parts to help us simulate the motor. It would be better to simulate this mini-circuit in code to reduce + // stamp a bunch of internal parts to help us simulate the motor. It would be + // better to simulate this mini-circuit in code to reduce // the size of the matrix. - - //nodes[0] nodes [1] are the external nodes - //Electrical part: + + // nodes[0] nodes [1] are the external nodes + // Electrical part: // inductor from motor nodes[0] to internal nodes[2] ind.stamp(nodes[0], nodes[2]); // resistor from internal nodes[2] to internal nodes[3] // motor post 2 sim.stampResistor(nodes[2], nodes[3], resistance); // Back emf voltage source from internal nodes[3] to external nodes [1] - sim.stampVoltageSource(nodes[3],nodes[1], voltSources[0]); // + sim.stampVoltageSource(nodes[3], nodes[1], voltSources[0]); // - //Mechanical part: + // Mechanical part: // inertia inductor from internal nodes[4] to internal nodes[5] indInertia.stamp(nodes[4], nodes[5]); - // resistor from internal nodes[5] to ground + // resistor from internal nodes[5] to ground sim.stampResistor(nodes[5], 0, b); - // Voltage Source from internal nodes[4] to ground - //System.out.println("doing stamp voltage"); - sim.stampVoltageSource(nodes[4], 0, voltSources[1]); - //System.out.println("doing stamp voltage "+voltSource); + // Voltage Source from internal nodes[4] to ground + // System.out.println("doing stamp voltage"); + sim.stampVoltageSource(nodes[4], 0, voltSources[1]); + // System.out.println("doing stamp voltage "+voltSource); } + void startIteration() { - ind.startIteration(volts[0]-volts[2]); - indInertia.startIteration(volts[4]-volts[5]); + ind.startIteration(volts[0] - volts[2]); + indInertia.startIteration(volts[4] - volts[5]); // update angle: - angle= angle + speed*sim.timeStep; + angle = angle + speed * sim.timeStep; } - /* boolean hasGroundConnection(int n1) { - if (n1==4|n1==5) return true; - else return false; - } - boolean getConnection(int n1, int n2) { - if((n1==0&n2==2)|(n1==2&n2==3)|(n1==1&n2==3)|(n1==4&n2==5)) - return true; - else - return false; - } + /* + * boolean hasGroundConnection(int n1) { if (n1==4|n1==5) return true; else + * return false; } boolean getConnection(int n1, int n2) { + * if((n1==0&n2==2)|(n1==2&n2==3)|(n1==1&n2==3)|(n1==4&n2==5)) return true; else + * return false; } */ void doStep() { - sim.updateVoltageSource(nodes[4],0, voltSources[1], - coilCurrent*K); - sim.updateVoltageSource(nodes[3],nodes[1], voltSources[0], - inertiaCurrent*Kb); - ind.doStep(volts[0]-volts[2]); - indInertia.doStep(volts[4]-volts[5]); + sim.updateVoltageSource(nodes[4], 0, voltSources[1], coilCurrent * K); + sim.updateVoltageSource(nodes[3], nodes[1], voltSources[0], inertiaCurrent * Kb); + ind.doStep(volts[0] - volts[2]); + indInertia.doStep(volts[4] - volts[5]); } + void calculateCurrent() { - coilCurrent = ind.calculateCurrent(volts[0]-volts[2]); - inertiaCurrent = indInertia.calculateCurrent(volts[4]-volts[5]); -// current = (volts[2]-volts[3])/resistance; - speed=inertiaCurrent; + coilCurrent = ind.calculateCurrent(volts[0] - volts[2]); + inertiaCurrent = indInertia.calculateCurrent(volts[4] - volts[5]); + // current = (volts[2]-volts[3])/resistance; + speed = inertiaCurrent; } -// public double getCurrent() { current = (volts[2]-volts[3])/resistance; return current; } + // public double getCurrent() { current = (volts[2]-volts[3])/resistance; return + // current; } void setCurrent(int vn, double c) { if (vn == voltSources[0]) current = c; } - + void draw(Graphics g) { int cr = 18; int hs = 8; setBbox(point1, point2, cr); draw2Leads(g); - //getCurrent(); + // getCurrent(); doDots(g); setPowerColor(g, true); Color cc = new Color((int) (165), (int) (165), (int) (165)); g.setColor(cc); - g.fillOval(motorCenter.x-(cr), motorCenter.y-(cr), (cr)*2, (cr)*2); + g.fillOval(motorCenter.x - (cr), motorCenter.y - (cr), (cr) * 2, (cr) * 2); cc = new Color((int) (10), (int) (10), (int) (10)); g.setColor(cc); - double angleAux = Math.round(angle*300.0)/300.0; - g.fillOval(motorCenter.x-(int)(cr/2.2), motorCenter.y-(int)(cr/2.2), (int)(2*cr/2.2), (int)(2*cr/2.2)); + double angleAux = Math.round(angle * 300.0) / 300.0; + g.fillOval(motorCenter.x - (int) (cr / 2.2), motorCenter.y - (int) (cr / 2.2), (int) (2 * cr / 2.2), + (int) (2 * cr / 2.2)); g.setColor(cc); - interpPointFix(lead1, lead2, ps1, 0.5 + .28*Math.cos(angleAux*gearRatio), .28*Math.sin(angleAux*gearRatio)); - interpPointFix(lead1, lead2, ps2, 0.5 - .28*Math.cos(angleAux*gearRatio), -.28*Math.sin(angleAux*gearRatio)); + interpPointFix(lead1, lead2, ps1, 0.5 + .28 * Math.cos(angleAux * gearRatio), + .28 * Math.sin(angleAux * gearRatio)); + interpPointFix(lead1, lead2, ps2, 0.5 - .28 * Math.cos(angleAux * gearRatio), + -.28 * Math.sin(angleAux * gearRatio)); drawThickerLine(g, ps1, ps2); - interpPointFix(lead1, lead2, ps1, 0.5 + .28*Math.cos(angleAux*gearRatio+pi/3), .28*Math.sin(angleAux*gearRatio+pi/3)); - interpPointFix(lead1, lead2, ps2, 0.5 - .28*Math.cos(angleAux*gearRatio+pi/3), -.28*Math.sin(angleAux*gearRatio+pi/3)); + interpPointFix(lead1, lead2, ps1, 0.5 + .28 * Math.cos(angleAux * gearRatio + pi / 3), + .28 * Math.sin(angleAux * gearRatio + pi / 3)); + interpPointFix(lead1, lead2, ps2, 0.5 - .28 * Math.cos(angleAux * gearRatio + pi / 3), + -.28 * Math.sin(angleAux * gearRatio + pi / 3)); drawThickerLine(g, ps1, ps2); - interpPointFix(lead1, lead2, ps1, 0.5 + .28*Math.cos(angleAux*gearRatio+2*pi/3), .28*Math.sin(angleAux*gearRatio+2*pi/3)); - interpPointFix(lead1, lead2, ps2, 0.5 - .28*Math.cos(angleAux*gearRatio+2*pi/3), -.28*Math.sin(angleAux*gearRatio+2*pi/3)); + interpPointFix(lead1, lead2, ps1, 0.5 + .28 * Math.cos(angleAux * gearRatio + 2 * pi / 3), + .28 * Math.sin(angleAux * gearRatio + 2 * pi / 3)); + interpPointFix(lead1, lead2, ps2, 0.5 - .28 * Math.cos(angleAux * gearRatio + 2 * pi / 3), + -.28 * Math.sin(angleAux * gearRatio + 2 * pi / 3)); drawThickerLine(g, ps1, ps2); drawPosts(g); } + static void drawThickerLine(Graphics g, Point pa, Point pb) { g.setLineWidth(6.0); g.drawLine(pa.x, pa.y, pb.x, pb.y); @@ -181,21 +215,21 @@ static void drawThickerLine(Graphics g, Point pa, Point pb) { } void interpPointFix(Point a, Point b, Point c, double f, double g) { - int gx = b.y-a.y; - int gy = a.x-b.x; - c.x = (int) Math.round(a.x*(1-f)+b.x*f+g*gx); - c.y = (int) Math.round(a.y*(1-f)+b.y*f+g*gy); + int gx = b.y - a.y; + int gy = a.x - b.x; + c.x = (int) Math.round(a.x * (1 - f) + b.x * f + g * gx); + c.y = (int) Math.round(a.y * (1 - f) + b.y * f + g * gy); } - void getInfo(String arr[]) { arr[0] = "DC Motor"; getBasicInfo(arr); - arr[3] = Locale.LS("speed") + " = " + getUnitText(60*Math.abs(speed)/(2*Math.PI), Locale.LS("RPM")); + arr[3] = Locale.LS("speed") + " = " + getUnitText(60 * Math.abs(speed) / (2 * Math.PI), Locale.LS("RPM")); arr[4] = "L = " + getUnitText(inductance, "H"); arr[5] = "R = " + getUnitText(resistance, Locale.ohmString); arr[6] = "P = " + getUnitText(getPower(), "W"); } + public EditInfo getEditInfo(int n) { if (n == 0) @@ -214,25 +248,26 @@ public EditInfo getEditInfo(int n) { return new EditInfo("Gear Ratio", gearRatio, 0, 0); return null; } + public void setEditValue(int n, EditInfo ei) { - if (ei.value > 0 & n==0) { - inductance = ei.value; - ind.setup(inductance, current, Inductor.FLAG_BACK_EULER); - } - if (ei.value > 0 & n==1) + if (ei.value > 0 & n == 0) { + inductance = ei.value; + ind.setup(inductance, current, Inductor.FLAG_BACK_EULER); + } + if (ei.value > 0 & n == 1) resistance = ei.value; - if (ei.value > 0 & n==2) + if (ei.value > 0 & n == 2) K = ei.value; - if (ei.value > 0 & n==3) + if (ei.value > 0 & n == 3) Kb = ei.value; - if (ei.value > 0 & n==4) { - J = ei.value; - indInertia.setup(J, inertiaCurrent, Inductor.FLAG_BACK_EULER); - } - if (ei.value > 0 & n==5) + if (ei.value > 0 & n == 4) { + J = ei.value; + indInertia.setup(J, inertiaCurrent, Inductor.FLAG_BACK_EULER); + } + if (ei.value > 0 & n == 5) b = ei.value; - if (ei.value > 0 & n==6) + if (ei.value > 0 & n == 6) gearRatio = ei.value; } } diff --git a/src/com/lushprojects/circuitjs1/client/DCVoltageElm.java b/src/com/lushprojects/circuitjs1/client/DCVoltageElm.java index 6f86283c..c5dbcf94 100644 --- a/src/com/lushprojects/circuitjs1/client/DCVoltageElm.java +++ b/src/com/lushprojects/circuitjs1/client/DCVoltageElm.java @@ -19,9 +19,16 @@ package com.lushprojects.circuitjs1.client; - class DCVoltageElm extends VoltageElm { - public DCVoltageElm(int xx, int yy) { super(xx, yy, WF_DC); } - Class getDumpClass() { return VoltageElm.class; } - int getShortcut() { return 'v'; } + public DCVoltageElm(int xx, int yy) { + super(xx, yy, WF_DC); + } + + Class getDumpClass() { + return VoltageElm.class; + } + + int getShortcut() { + return 'v'; } +} diff --git a/src/com/lushprojects/circuitjs1/client/DFlipFlopElm.java b/src/com/lushprojects/circuitjs1/client/DFlipFlopElm.java index 91a52638..c236530c 100644 --- a/src/com/lushprojects/circuitjs1/client/DFlipFlopElm.java +++ b/src/com/lushprojects/circuitjs1/client/DFlipFlopElm.java @@ -19,118 +19,143 @@ package com.lushprojects.circuitjs1.client; - class DFlipFlopElm extends ChipElm { - final int FLAG_RESET = 2; - final int FLAG_SET = 4; - final int FLAG_INVERT_SET_RESET = 8; - boolean hasReset() { return (flags & FLAG_RESET) != 0 || hasSet(); } - boolean hasSet() { return (flags & FLAG_SET) != 0; } - boolean invertSetReset() { return (flags & FLAG_INVERT_SET_RESET) != 0; } - - boolean justLoaded; - - public DFlipFlopElm(int xx, int yy) { - super(xx, yy); - pins[2].value = !pins[1].value; - } - public DFlipFlopElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - pins[2].value = !pins[1].value; - justLoaded = true; +class DFlipFlopElm extends ChipElm { + final int FLAG_RESET = 2; + final int FLAG_SET = 4; + final int FLAG_INVERT_SET_RESET = 8; + + boolean hasReset() { + return (flags & FLAG_RESET) != 0 || hasSet(); + } + + boolean hasSet() { + return (flags & FLAG_SET) != 0; + } + + boolean invertSetReset() { + return (flags & FLAG_INVERT_SET_RESET) != 0; + } + + boolean justLoaded; + + public DFlipFlopElm(int xx, int yy) { + super(xx, yy); + pins[2].value = !pins[1].value; + } + + public DFlipFlopElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + pins[2].value = !pins[1].value; + justLoaded = true; + } + + String getChipName() { + return "D flip-flop"; + } + + void setupPins() { + sizeX = 2; + sizeY = 3; + pins = new Pin[getPostCount()]; + pins[0] = new Pin(0, SIDE_W, "D"); + pins[1] = new Pin(0, SIDE_E, "Q"); + pins[1].output = pins[1].state = true; + pins[2] = new Pin(hasSet() ? 1 : 2, SIDE_E, "Q"); + pins[2].output = true; + pins[2].lineOver = true; + pins[3] = new Pin(1, SIDE_W, ""); + pins[3].clock = true; + if (!hasSet()) { + if (hasReset()) { + pins[4] = new Pin(2, SIDE_W, "R"); + pins[4].bubble = invertSetReset(); + } + } else { + pins[5] = new Pin(2, SIDE_W, "S"); + pins[4] = new Pin(2, SIDE_E, "R"); + pins[4].bubble = pins[5].bubble = invertSetReset(); + } + } + + int getPostCount() { + return 4 + (hasReset() ? 1 : 0) + (hasSet() ? 1 : 0); + } + + int getVoltageSourceCount() { + return 2; + } + + void reset() { + super.reset(); + volts[2] = highVoltage; + pins[2].value = true; + } + + void execute() { + // if we just loaded then the volts[] array is likely to be all zeroes, which + // might force us to do a reset, so defer execution until the next iteration + if (justLoaded) { + justLoaded = false; + return; } - String getChipName() { return "D flip-flop"; } - void setupPins() { - sizeX = 2; - sizeY = 3; - pins = new Pin[getPostCount()]; - pins[0] = new Pin(0, SIDE_W, "D"); - pins[1] = new Pin(0, SIDE_E, "Q"); - pins[1].output = pins[1].state = true; - pins[2] = new Pin(hasSet()?1:2, SIDE_E, "Q"); - pins[2].output = true; - pins[2].lineOver = true; - pins[3] = new Pin(1, SIDE_W, ""); - pins[3].clock = true; - if (!hasSet()) { - if (hasReset()) { - pins[4] = new Pin(2, SIDE_W, "R"); - pins[4].bubble = invertSetReset(); - } - } else { - pins[5] = new Pin(2, SIDE_W, "S"); - pins[4] = new Pin(2, SIDE_E, "R"); - pins[4].bubble = pins[5].bubble = invertSetReset(); - } + + if (pins[3].value && !lastClock) + writeOutput(1, pins[0].value); + if (hasSet() && pins[5].value != invertSetReset()) + writeOutput(1, true); + if (hasReset() && pins[4].value != invertSetReset()) + writeOutput(1, false); + writeOutput(2, !pins[1].value); + lastClock = pins[3].value; + } + + int getDumpType() { + return 155; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Reset Pin", hasReset()); + return ei; } - int getPostCount() { - return 4 + (hasReset() ? 1 : 0) + (hasSet() ? 1 : 0); + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Set Pin", hasSet()); + return ei; } - int getVoltageSourceCount() { return 2; } - void reset() { - super.reset(); - volts[2] = highVoltage; - pins[2].value = true; - } - void execute() { - // if we just loaded then the volts[] array is likely to be all zeroes, which might force us to do a reset, so defer execution until the next iteration - if (justLoaded) { - justLoaded = false; - return; - } - - if (pins[3].value && !lastClock) - writeOutput(1, pins[0].value); - if(hasSet() && pins[5].value != invertSetReset()) - writeOutput(1, true); - if(hasReset() && pins[4].value != invertSetReset()) - writeOutput(1, false); - writeOutput(2, !pins[1].value); - lastClock = pins[3].value; + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Invert Set/Reset", invertSetReset()); + return ei; } - int getDumpType() { return 155; } - public EditInfo getChipEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Reset Pin", hasReset()); - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Set Pin", hasSet()); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Invert Set/Reset", invertSetReset()); - return ei; - } - return super.getChipEditInfo(n); + return super.getChipEditInfo(n); + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0) { + if (ei.checkbox.getState()) + flags |= FLAG_RESET; + else + flags &= ~FLAG_RESET | FLAG_SET; + setupPins(); + allocNodes(); + setPoints(); } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0) { - if (ei.checkbox.getState()) - flags |= FLAG_RESET; - else - flags &= ~FLAG_RESET|FLAG_SET; - setupPins(); - allocNodes(); - setPoints(); - } - if (n == 1) { - if (ei.checkbox.getState()) - flags |= FLAG_SET; - else - flags &= ~FLAG_SET; - setupPins(); - allocNodes(); - setPoints(); - } - if (n == 2) { - flags = ei.changeFlag(flags, FLAG_INVERT_SET_RESET); - setupPins(); - setPoints(); - } - super.setChipEditValue(n, ei); + if (n == 1) { + if (ei.checkbox.getState()) + flags |= FLAG_SET; + else + flags &= ~FLAG_SET; + setupPins(); + allocNodes(); + setPoints(); + } + if (n == 2) { + flags = ei.changeFlag(flags, FLAG_INVERT_SET_RESET); + setupPins(); + setPoints(); } + super.setChipEditValue(n, ei); } +} diff --git a/src/com/lushprojects/circuitjs1/client/DarlingtonElm.java b/src/com/lushprojects/circuitjs1/client/DarlingtonElm.java index 7d6c511a..7a89e6ea 100644 --- a/src/com/lushprojects/circuitjs1/client/DarlingtonElm.java +++ b/src/com/lushprojects/circuitjs1/client/DarlingtonElm.java @@ -6,31 +6,28 @@ // Iain Sharp, Feb 2017 - public class DarlingtonElm extends CompositeElm { private Polygon rectPoly, arrowPoly; private Point rect[], coll[], emit[], base, coll2[]; - private int pnp; // +1 for NPN, -1 for PNP; private double curcount_c, curcount_e, curcount_b; private static String modelString = "NTransistorElm 1 2 4\rNTransistorElm 4 2 3"; - private static int[] modelExternalNodes = {1, 2, 3}; - + private static int[] modelExternalNodes = { 1, 2, 3 }; + DarlingtonElm(int xx, int yy, boolean pnpflag) { super(xx, yy, modelString, modelExternalNodes); pnp = (pnpflag) ? -1 : 1; - ((TransistorElm) compElmList.get(0)).pnp=pnp; - ((TransistorElm) compElmList.get(1)).pnp=pnp; + ((TransistorElm) compElmList.get(0)).pnp = pnp; + ((TransistorElm) compElmList.get(1)).pnp = pnp; noDiagonal = true; - + } - public DarlingtonElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st, modelString, modelExternalNodes); - pnp = new Integer(st.nextToken()).intValue(); + pnp = Integer.valueOf(st.nextToken()).intValue(); noDiagonal = true; } @@ -38,16 +35,15 @@ public void reset() { super.reset(); curcount_c = curcount_e = curcount_b = 0; } - + public int getDumpType() { return 400; } public String dump() { - return super.dump()+" "+pnp; + return super.dump() + " " + pnp; } - void draw(Graphics g) { setBbox(point1, point2, 16); setPowerColor(g, true); @@ -94,9 +90,6 @@ void draw(Graphics g) { drawPosts(g); } - - - void getInfo(String arr[]) { arr[0] = Locale.LS("darlington pair") + " (" + ((pnp == -1) ? "PNP)" : "NPN)"); double vbc = volts[0] - volts[1]; @@ -118,33 +111,30 @@ void setPoints() { coll2 = newPointArray(2); emit = newPointArray(2); interpPoint2(point1, point2, coll[0], emit[0], 1, hs2); - coll2[0]=interpPoint(point1, point2, 1, hs2-5*dsign*pnp); + coll2[0] = interpPoint(point1, point2, 1, hs2 - 5 * dsign * pnp); // calc rectangle edges rect = newPointArray(4); interpPoint2(point1, point2, rect[0], rect[1], 1 - 16 / dn, hs); interpPoint2(point1, point2, rect[2], rect[3], 1 - 13 / dn, hs); // calc points where collector/emitter leads contact rectangle interpPoint2(point1, point2, coll[1], emit[1], 1 - 13 / dn, 6 * dsign * pnp); - coll2[1]=interpPoint(point1, point2, 1-13/dn, dsign*pnp); + coll2[1] = interpPoint(point1, point2, 1 - 13 / dn, dsign * pnp); // calc point where base lead contacts rectangle base = new Point(); interpPoint(point1, point2, base, 1 - 16 / dn); // rectangle rectPoly = createPolygon(rect[0], rect[2], rect[3], rect[1]); // arrow - if (pnp == 1) - arrowPoly = calcArrow(emit[1], emit[0], 8, 4); - else { - Point pt = interpPoint(point1, point2, 1-11/dn, -5*dsign*pnp); - arrowPoly = calcArrow(emit[0], pt, 8, 4); - } + if (pnp == 1) + arrowPoly = calcArrow(emit[1], emit[0], 8, 4); + else { + Point pt = interpPoint(point1, point2, 1 - 11 / dn, -5 * dsign * pnp); + arrowPoly = calcArrow(emit[0], pt, 8, 4); + } setPost(0, point1); - setPost(1,coll[0]); - setPost(2,emit[0]); + setPost(1, coll[0]); + setPost(2, emit[0]); } - - - } diff --git a/src/com/lushprojects/circuitjs1/client/DataInputElm.java b/src/com/lushprojects/circuitjs1/client/DataInputElm.java index e6f906a6..2fa786db 100644 --- a/src/com/lushprojects/circuitjs1/client/DataInputElm.java +++ b/src/com/lushprojects/circuitjs1/client/DataInputElm.java @@ -32,124 +32,131 @@ class DataFileEntry { } class DataInputElm extends RailElm { - ArrayList data; - double sampleLength; - double scaleFactor; - double timeOffset; - int fileNum; - String fileName; - final int FLAG_REPEAT = 1<<8; - - // cache to preserve data when doing cut/paste, or undo/redo - static int fileNumCounter = 1; - static HashMap dataFileMap = new HashMap(); - - public DataInputElm(int xx, int yy) { - super(xx, yy, WF_AC); - scaleFactor = 1; - sampleLength = 1e-3; - } - - public DataInputElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - waveform = WF_AC; - sampleLength = Double.parseDouble(st.nextToken()); - scaleFactor = Double.parseDouble(st.nextToken()); - fileNum = Integer.parseInt(st.nextToken()); - - DataFileEntry ent = dataFileMap.get(fileNum); - if (ent != null) { - fileName = ent.fileName; - data = ent.data; - } - } - - double fmphase; - - String dump() { - // add a file number to the dump so we can preserve the data when doing cut and paste, or undo/redo. - // we don't save the entire file in the dump because it would be huge. - if (data != null) { - if (fileNum == 0) - fileNum = fileNumCounter++; - DataFileEntry ent = new DataFileEntry(); - ent.fileName = fileName; - ent.data = data; - dataFileMap.put(fileNum, ent); - } - return super.dump() + " " + sampleLength + " " + scaleFactor + " " + fileNum; - } - - void reset() { - timeOffset = 0; - } - - void drawRail(Graphics g) { - drawRailText(g, fileName == null ? "No file" : fileName); - } - - String getRailText() { - return fileName == null ? "No file" : fileName; - } - - boolean doesRepeat() { return (flags & FLAG_REPEAT) != 0; } - - double getVoltage() { - if (data == null) - return 0; - int ptr = (int) (timeOffset / sampleLength); - if (ptr >= data.size()) { - if (doesRepeat()) { - ptr = 0; - timeOffset = 0; - } else - ptr = data.size()-1; - } - return data.get(ptr) * scaleFactor; + ArrayList data; + double sampleLength; + double scaleFactor; + double timeOffset; + int fileNum; + String fileName; + final int FLAG_REPEAT = 1 << 8; + + // cache to preserve data when doing cut/paste, or undo/redo + static int fileNumCounter = 1; + static HashMap dataFileMap = new HashMap(); + + public DataInputElm(int xx, int yy) { + super(xx, yy, WF_AC); + scaleFactor = 1; + sampleLength = 1e-3; + } + + public DataInputElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + waveform = WF_AC; + sampleLength = Double.parseDouble(st.nextToken()); + scaleFactor = Double.parseDouble(st.nextToken()); + fileNum = Integer.parseInt(st.nextToken()); + + DataFileEntry ent = dataFileMap.get(fileNum); + if (ent != null) { + fileName = ent.fileName; + data = ent.data; } - - void stepFinished() { - timeOffset += sim.timeStep; + } + + double fmphase; + + String dump() { + // add a file number to the dump so we can preserve the data when doing cut and + // paste, or undo/redo. + // we don't save the entire file in the dump because it would be huge. + if (data != null) { + if (fileNum == 0) + fileNum = fileNumCounter++; + DataFileEntry ent = new DataFileEntry(); + ent.fileName = fileName; + ent.data = data; + dataFileMap.put(fileNum, ent); } - - int getDumpType() { return 424; } - int getShortcut() { return 0; } - - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - final DataInputElm thisElm = this; - final FileUpload file = new FileUpload(); - ei.widget = file; - file.addChangeHandler(new ChangeHandler() { - public void onChange(ChangeEvent event) { - fileName = file.getFilename().replaceAll("^.*\\\\", "").replaceAll("\\.[^.]*$", ""); - DataInputElm.fetchLoadFileData(thisElm, file.getElement()); - } - }); - return ei; - } - if (n == 1) - return new EditInfo("Scale Factor", scaleFactor); - if (n == 2) - return new EditInfo("Sample Length (s)", sampleLength); - if (n == 3) - return EditInfo.createCheckbox("Repeat", doesRepeat()); - return null; + return super.dump() + " " + sampleLength + " " + scaleFactor + " " + fileNum; + } + + void reset() { + timeOffset = 0; + } + + void drawRail(Graphics g) { + drawRailText(g, fileName == null ? "No file" : fileName); + } + + String getRailText() { + return fileName == null ? "No file" : fileName; + } + + boolean doesRepeat() { + return (flags & FLAG_REPEAT) != 0; + } + + double getVoltage() { + if (data == null) + return 0; + int ptr = (int) (timeOffset / sampleLength); + if (ptr >= data.size()) { + if (doesRepeat()) { + ptr = 0; + timeOffset = 0; + } else + ptr = data.size() - 1; } - - public void setEditValue(int n, EditInfo ei) { - if (n == 1) - scaleFactor = ei.value; - if (n == 2) - sampleLength = ei.value; - if (n == 3) - flags = ei.changeFlag(flags, FLAG_REPEAT); + return data.get(ptr) * scaleFactor; + } + + void stepFinished() { + timeOffset += sim.timeStep; + } + + int getDumpType() { + return 424; + } + + int getShortcut() { + return 0; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + final DataInputElm thisElm = this; + final FileUpload file = new FileUpload(); + ei.widget = file; + file.addChangeHandler(new ChangeHandler() { + public void onChange(ChangeEvent event) { + fileName = file.getFilename().replaceAll("^.*\\\\", "").replaceAll("\\.[^.]*$", ""); + DataInputElm.fetchLoadFileData(thisElm, file.getElement()); + } + }); + return ei; } - - // fetch data for a selected file - static native String fetchLoadFileData(DataInputElm elm, Element uploadElement) /*-{ + if (n == 1) + return new EditInfo("Scale Factor", scaleFactor); + if (n == 2) + return new EditInfo("Sample Length (s)", sampleLength); + if (n == 3) + return EditInfo.createCheckbox("Repeat", doesRepeat()); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 1) + scaleFactor = ei.value; + if (n == 2) + sampleLength = ei.value; + if (n == 3) + flags = ei.changeFlag(flags, FLAG_REPEAT); + } + + // fetch data for a selected file + static native String fetchLoadFileData(DataInputElm elm, Element uploadElement) /*-{ var oFiles = uploadElement.files; if (oFiles.length >= 1) { var reader = new FileReader(); @@ -162,41 +169,41 @@ static native String fetchLoadFileData(DataInputElm elm, Element uploadElement) } }-*/; - void doLoadCallback(String s, String t) { - // parse data file. each line contains a single voltage value - String arr[] = s.split("\r*\n"); - data = new ArrayList(); - int i; - for (i = 0; i != arr.length; i++) { - // skip blank lines - if (arr[i].length() == 0) - continue; - - // skip comments - if (arr[i].charAt(0) == '#') - continue; - try { - double d = Double.parseDouble(arr[i]); - data.add(d); - } catch (Exception e) { - CirSim.console("parse error on line " + i); - } - } - } + void doLoadCallback(String s, String t) { + // parse data file. each line contains a single voltage value + String arr[] = s.split("\r*\n"); + data = new ArrayList(); + int i; + for (i = 0; i != arr.length; i++) { + // skip blank lines + if (arr[i].length() == 0) + continue; - void getInfo(String arr[]) { - arr[0] = "data input"; - if (data == null) { - arr[1] = "no file loaded"; - return; + // skip comments + if (arr[i].charAt(0) == '#') + continue; + try { + double d = Double.parseDouble(arr[i]); + data.add(d); + } catch (Exception e) { + CirSim.console("parse error on line " + i); } - arr[1] = "V = " + getVoltageText(volts[0]); - arr[2] = "pos = " + getUnitText(timeOffset, "s"); - double dur = data.size() * sampleLength; - arr[3] = "dur = " + getUnitText(dur, "s"); } - - public static void clearCache() { - dataFileMap.clear(); + } + + void getInfo(String arr[]) { + arr[0] = "data input"; + if (data == null) { + arr[1] = "no file loaded"; + return; } + arr[1] = "V = " + getVoltageText(volts[0]); + arr[2] = "pos = " + getUnitText(timeOffset, "s"); + double dur = data.size() * sampleLength; + arr[3] = "dur = " + getUnitText(dur, "s"); } + + public static void clearCache() { + dataFileMap.clear(); + } +} diff --git a/src/com/lushprojects/circuitjs1/client/DataRecorderElm.java b/src/com/lushprojects/circuitjs1/client/DataRecorderElm.java index 37e4fcc1..9ed073ee 100644 --- a/src/com/lushprojects/circuitjs1/client/DataRecorderElm.java +++ b/src/com/lushprojects/circuitjs1/client/DataRecorderElm.java @@ -11,116 +11,132 @@ public class DataRecorderElm extends CircuitElm { int lastTimeStepCount; double data[]; boolean dataFull; - - public DataRecorderElm(int xx, int yy) { - super(xx, yy); - setDataCount(10240); - } - public DataRecorderElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - setDataCount(Integer.parseInt(st.nextToken())); - } - String dump() { - return super.dump() + " " + dataCount; - } - int getDumpType() { return 210; } - int getPostCount() { return 1; } - void reset() { + + public DataRecorderElm(int xx, int yy) { + super(xx, yy); + setDataCount(10240); + } + + public DataRecorderElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + setDataCount(Integer.parseInt(st.nextToken())); + } + + String dump() { + return super.dump() + " " + dataCount; + } + + int getDumpType() { + return 210; + } + + int getPostCount() { + return 1; + } + + void reset() { + dataPtr = 0; + dataFull = false; + lastTimeStepCount = 0; + } + + void setPoints() { + super.setPoints(); + lead1 = interpPoint(point1, point2, 1 - 8 / dn); + } + + void draw(Graphics g) { + g.save(); + boolean selected = (needsHighlight()); + Font f = new Font("SansSerif", selected ? Font.BOLD : 0, 14); + g.setFont(f); + g.setColor(selected ? selectColor : whiteColor); + setBbox(point1, lead1, 0); + String s = Locale.LS("export"); + drawLabeledNode(g, s, point1, lead1); + setVoltageColor(g, volts[0]); + if (selected) + g.setColor(selectColor); + drawThickLine(g, point1, lead1); + drawPosts(g); + g.restore(); + } + + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "data export"; + arr[1] = "V = " + getVoltageText(volts[0]); + arr[2] = (dataFull ? dataCount : dataPtr) + "/" + dataCount; + } + + void stepFinished() { + if (lastTimeStepCount == sim.timeStepCount) + return; + data[dataPtr++] = volts[0]; + lastTimeStepCount = sim.timeStepCount; + if (dataPtr >= dataCount) { dataPtr = 0; - dataFull = false; - lastTimeStepCount = 0; - } - void setPoints() { - super.setPoints(); - lead1 = interpPoint(point1, point2, 1-8/dn); - } - void draw(Graphics g) { - g.save(); - boolean selected = (needsHighlight()); - Font f = new Font("SansSerif", selected ? Font.BOLD : 0, 14); - g.setFont(f); - g.setColor(selected ? selectColor : whiteColor); - setBbox(point1, lead1, 0); - String s = Locale.LS("export"); - drawLabeledNode(g, s, point1, lead1); - setVoltageColor(g, volts[0]); - if (selected) - g.setColor(selectColor); - drawThickLine(g, point1, lead1); - drawPosts(g); - g.restore(); - } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = "data export"; - arr[1] = "V = " + getVoltageText(volts[0]); - arr[2] = (dataFull ? dataCount : dataPtr) + "/" + dataCount; - } - void stepFinished() { - if (lastTimeStepCount == sim.timeStepCount) - return; - data[dataPtr++] = volts[0]; - lastTimeStepCount = sim.timeStepCount; - if (dataPtr >= dataCount) { - dataPtr = 0; - dataFull = true; - } + dataFull = true; } - - void setDataCount(int ct) { - dataCount = ct; - data = new double[dataCount]; - dataPtr = 0; - dataFull = false; + } + + void setDataCount(int ct) { + dataCount = ct; + data = new double[dataCount]; + dataPtr = 0; + dataFull = false; + } + + static public final native String getBlobUrl(String data) + /*-{ + var datain=[""]; + datain[0]=data; + var oldblob = $doc.recorderBlob; + // remove old blob if any. We should do this when dialog is dismissed, but this is easier + if (oldblob) + URL.revokeObjectURL(oldblob); + var blob=new Blob(datain, {type: 'text/plain' } ); + var url = URL.createObjectURL(blob); + $doc.recorderBlob = url; + return url; + }-*/; + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("# of Data Points", dataCount, -1, -1).setDimensionless(); + return ei; } - - static public final native String getBlobUrl(String data) - /*-{ - var datain=[""]; - datain[0]=data; - var oldblob = $doc.recorderBlob; - // remove old blob if any. We should do this when dialog is dismissed, but this is easier - if (oldblob) - URL.revokeObjectURL(oldblob); - var blob=new Blob(datain, {type: 'text/plain' } ); - var url = URL.createObjectURL(blob); - $doc.recorderBlob = url; - return url; - }-*/; - - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("# of Data Points", dataCount, -1, -1).setDimensionless(); - return ei; + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + String dataStr = "# time step = " + sim.timeStep + " sec\n"; + int i; + if (dataFull) { + for (i = 0; i != dataCount; i++) + dataStr += data[(i + dataPtr) % dataCount] + "\n"; + } else { + for (i = 0; i != dataPtr; i++) + dataStr += data[i] + "\n"; } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - String dataStr = "# time step = " + sim.timeStep + " sec\n"; - int i; - if (dataFull) { - for (i = 0; i != dataCount; i++) - dataStr += data[(i+dataPtr) % dataCount] + "\n"; - } else { - for (i = 0; i != dataPtr; i++) - dataStr += data[i] + "\n"; - } - String url=getBlobUrl(dataStr); - Date date = new Date(); - DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); - String fname = "data-"+ dtf.format(date) + ".circuitjs.txt"; - Anchor a=new Anchor(fname, url); - a.getElement().setAttribute("Download", fname); - ei.widget = a; - return ei; - } - return null; + String url = getBlobUrl(dataStr); + Date date = new Date(); + DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); + String fname = "data-" + dtf.format(date) + ".circuitjs.txt"; + Anchor a = new Anchor(fname, url); + a.getElement().setAttribute("Download", fname); + ei.widget = a; + return ei; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) { - setDataCount((int)ei.value); - } - if (n == 1) - return; + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) { + setDataCount((int) ei.value); } + if (n == 1) + return; + } } diff --git a/src/com/lushprojects/circuitjs1/client/DeMultiplexerElm.java b/src/com/lushprojects/circuitjs1/client/DeMultiplexerElm.java index 2e336eeb..9ef3f7a5 100644 --- a/src/com/lushprojects/circuitjs1/client/DeMultiplexerElm.java +++ b/src/com/lushprojects/circuitjs1/client/DeMultiplexerElm.java @@ -21,72 +21,92 @@ // contributed by Edward Calver - class DeMultiplexerElm extends ChipElm { - int selectBitCount; - int outputCount; - int qPin; - boolean hasReset() {return false;} - public DeMultiplexerElm(int xx, int yy) { super(xx, yy); } - public DeMultiplexerElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - try { - selectBitCount = Integer.parseInt(st.nextToken()); - setupPins(); - allocNodes(); - } catch (Exception e) {} - } - String getChipName() { return "demultiplexer"; } - String dump() { return super.dump() + " " + selectBitCount; } - - void setupPins() { - if (selectBitCount == 0) - selectBitCount = 2; - outputCount = 1 << selectBitCount; - sizeX = 1+selectBitCount; - sizeY = 1+outputCount; - pins = new Pin[getPostCount()]; - int i; - for (i = 0; i != outputCount; i++) { - pins[i] = new Pin(i, SIDE_E, "Q" + i); - pins[i].output=true; - } - for (i = 0; i != selectBitCount; i++) { - int ii = i+outputCount; - pins[ii] = new Pin(i, SIDE_S, "S" + i); - } - qPin = outputCount+selectBitCount; - pins[qPin] = new Pin(0, SIDE_W, "Q"); +class DeMultiplexerElm extends ChipElm { + int selectBitCount; + int outputCount; + int qPin; + + boolean hasReset() { + return false; + } + + public DeMultiplexerElm(int xx, int yy) { + super(xx, yy); + } + + public DeMultiplexerElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + try { + selectBitCount = Integer.parseInt(st.nextToken()); + setupPins(); + allocNodes(); + } catch (Exception e) { } - int getPostCount() { - return qPin+1; + } + + String getChipName() { + return "demultiplexer"; + } + + String dump() { + return super.dump() + " " + selectBitCount; + } + + void setupPins() { + if (selectBitCount == 0) + selectBitCount = 2; + outputCount = 1 << selectBitCount; + sizeX = 1 + selectBitCount; + sizeY = 1 + outputCount; + pins = new Pin[getPostCount()]; + int i; + for (i = 0; i != outputCount; i++) { + pins[i] = new Pin(i, SIDE_E, "Q" + i); + pins[i].output = true; } - int getVoltageSourceCount() { return outputCount; } - - void execute() { - int val = 0; - int i; - for (i = 0; i != selectBitCount; i++) - if (pins[i+outputCount].value) - val |= 1<= 1 && ei.value <= 6) { - selectBitCount = (int)ei.value; - setupPins(); - setPoints(); - } - } - - int getDumpType() { return 185; } + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value >= 1 && ei.value <= 6) { + selectBitCount = (int) ei.value; + setupPins(); + setPoints(); + } + } + int getDumpType() { + return 185; } + +} diff --git a/src/com/lushprojects/circuitjs1/client/DecimalDisplayElm.java b/src/com/lushprojects/circuitjs1/client/DecimalDisplayElm.java index 2a82554c..19ab6399 100644 --- a/src/com/lushprojects/circuitjs1/client/DecimalDisplayElm.java +++ b/src/com/lushprojects/circuitjs1/client/DecimalDisplayElm.java @@ -21,73 +21,88 @@ class DecimalDisplayElm extends ChipElm { int bitCount; - + public DecimalDisplayElm(int xx, int yy) { super(xx, yy); bitCount = 4; setupPins(); } - public DecimalDisplayElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public DecimalDisplayElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); bitCount = 4; try { bitCount = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + } catch (Exception e) { + } setupPins(); } - String getChipName() { return "decimal display"; } - + + String getChipName() { + return "decimal display"; + } + void draw(Graphics g) { - drawChip(g); - int xl = x+cspc + flippedSizeX*cspc; - int yl = y-cspc + flippedSizeY*cspc; + drawChip(g); + int xl = x + cspc + flippedSizeX * cspc; + int yl = y - cspc + flippedSizeY * cspc; if (isFlippedXY()) - yl += ((flags & FLAG_FLIP_Y) != 0) ? -cspc/2 : cspc/2; - g.save(); - g.setFont(new Font("SansSerif", 0, 15*csize)); - g.setColor(whiteColor); - g.context.setTextBaseline("middle"); - int i; - int value = 0; - for (i = 0; i != bitCount; i++) - if (pins[i].value) - value |= 1<= 1 && ei.value <= 16) { - bitCount = (int) ei.value; - setupPins(); - setPoints(); - return; - } - super.setChipEditValue(n, ei); + if (n == 0 && ei.value >= 1 && ei.value <= 16) { + bitCount = (int) ei.value; + setupPins(); + setPoints(); + return; + } + super.setChipEditValue(n, ei); } } - diff --git a/src/com/lushprojects/circuitjs1/client/DelayBufferElm.java b/src/com/lushprojects/circuitjs1/client/DelayBufferElm.java index b38bfab0..6b74bdf3 100644 --- a/src/com/lushprojects/circuitjs1/client/DelayBufferElm.java +++ b/src/com/lushprojects/circuitjs1/client/DelayBufferElm.java @@ -22,121 +22,142 @@ import com.lushprojects.circuitjs1.client.util.Locale; class DelayBufferElm extends CircuitElm { - double delay, threshold, highVoltage; - - public DelayBufferElm(int xx, int yy) { - super(xx, yy); - noDiagonal = true; - threshold = 2.5; - highVoltage = 5; - } - public DelayBufferElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - noDiagonal = true; - delay = Double.parseDouble(st.nextToken()); - threshold = 2.5; - highVoltage = 5; - try { - threshold = Double.parseDouble(st.nextToken()); - highVoltage = Double.parseDouble(st.nextToken()); - } catch (Exception e) {} - } - String dump() { - return super.dump() + " " + delay + " " + threshold + " " + highVoltage; - } - - int getDumpType() { return 422; } - - Point center; - - void draw(Graphics g) { - drawPosts(g); - draw2Leads(g); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - drawThickPolygon(g, gatePoly); - if (GateElm.useEuroGates()) - drawCenteredText(g, "1", center.x, center.y-6, true); - curcount = updateDotCount(current, curcount); - drawDots(g, lead2, point2, curcount); - } - Polygon gatePoly; - void setPoints() { - super.setPoints(); - int hs = 16; - int ww = 16-2; - if (ww > dn/2) - ww = (int) (dn/2); - lead1 = interpPoint(point1, point2, .5-ww/dn); - lead2 = interpPoint(point1, point2, .5+ww/dn); - - if (GateElm.useEuroGates()) { - Point pts[] = newPointArray(4); - Point l2 = interpPoint(point1, point2, .5+(ww-5)/dn); - interpPoint2(lead1, l2, pts[0], pts[1], 0, hs); - interpPoint2(lead1, l2, pts[3], pts[2], 1, hs); - gatePoly = createPolygon(pts); - center = interpPoint(lead1, l2, .5); - } else { - Point triPoints[] = newPointArray(3); - interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); - triPoints[2] = interpPoint(point1, point2, .5+ww/dn); - gatePoly = createPolygon(triPoints); - } - setBbox(point1, point2, hs); - } - int getVoltageSourceCount() { return 1; } - void stamp() { - sim.stampVoltageSource(0, nodes[1], voltSource); - } - - double delayEndTime; - - void doStep() { - boolean inState = volts[0] > threshold; - boolean outState = volts[1] > threshold; - if (inState != outState) { - if (sim.t >= delayEndTime) - outState = inState; - } else - delayEndTime = sim.t + delay; - sim.updateVoltageSource(0, nodes[1], voltSource, outState ? highVoltage : 0); - } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = Locale.LS("buffer"); - arr[1] = Locale.LS("delay = " )+ getUnitText(delay, "s"); - arr[2] = "Vi = " + getVoltageText(volts[0]); - arr[3] = "Vo = " + getVoltageText(volts[1]); - } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Delay (s)", delay, 0, 0); - if (n == 1) - return new EditInfo("Threshold (V)", threshold, 0, 0); - if (n == 2) - return new EditInfo("High Logic Voltage", highVoltage, 0, 0); - return null; - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - delay = ei.value; - if (n == 1) - threshold = ei.value; - if (n == 2) - highVoltage = ei.value; - } - // there is no current path through the inverter input, but there - // is an indirect path through the output to ground. - boolean getConnection(int n1, int n2) { return false; } - boolean hasGroundConnection(int n1) { - return (n1 == 1); + double delay, threshold, highVoltage; + + public DelayBufferElm(int xx, int yy) { + super(xx, yy); + noDiagonal = true; + threshold = 2.5; + highVoltage = 5; + } + + public DelayBufferElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + noDiagonal = true; + delay = Double.parseDouble(st.nextToken()); + threshold = 2.5; + highVoltage = 5; + try { + threshold = Double.parseDouble(st.nextToken()); + highVoltage = Double.parseDouble(st.nextToken()); + } catch (Exception e) { } - - @Override double getCurrentIntoNode(int n) { - if (n == 1) - return current; - return 0; + } + + String dump() { + return super.dump() + " " + delay + " " + threshold + " " + highVoltage; + } + + int getDumpType() { + return 422; + } + + Point center; + + void draw(Graphics g) { + drawPosts(g); + draw2Leads(g); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickPolygon(g, gatePoly); + if (GateElm.useEuroGates()) + drawCenteredText(g, "1", center.x, center.y - 6, true); + curcount = updateDotCount(current, curcount); + drawDots(g, lead2, point2, curcount); + } + + Polygon gatePoly; + + void setPoints() { + super.setPoints(); + int hs = 16; + int ww = 16 - 2; + if (ww > dn / 2) + ww = (int) (dn / 2); + lead1 = interpPoint(point1, point2, .5 - ww / dn); + lead2 = interpPoint(point1, point2, .5 + ww / dn); + + if (GateElm.useEuroGates()) { + Point pts[] = newPointArray(4); + Point l2 = interpPoint(point1, point2, .5 + (ww - 5) / dn); + interpPoint2(lead1, l2, pts[0], pts[1], 0, hs); + interpPoint2(lead1, l2, pts[3], pts[2], 1, hs); + gatePoly = createPolygon(pts); + center = interpPoint(lead1, l2, .5); + } else { + Point triPoints[] = newPointArray(3); + interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); + triPoints[2] = interpPoint(point1, point2, .5 + ww / dn); + gatePoly = createPolygon(triPoints); } + setBbox(point1, point2, hs); + } + + int getVoltageSourceCount() { + return 1; + } + + void stamp() { + sim.stampVoltageSource(0, nodes[1], voltSource); + } + + double delayEndTime; + + void doStep() { + boolean inState = volts[0] > threshold; + boolean outState = volts[1] > threshold; + if (inState != outState) { + if (sim.t >= delayEndTime) + outState = inState; + } else + delayEndTime = sim.t + delay; + sim.updateVoltageSource(0, nodes[1], voltSource, outState ? highVoltage : 0); + } + + double getVoltageDiff() { + return volts[0]; + } + void getInfo(String arr[]) { + arr[0] = Locale.LS("buffer"); + arr[1] = Locale.LS("delay = ") + getUnitText(delay, "s"); + arr[2] = "Vi = " + getVoltageText(volts[0]); + arr[3] = "Vo = " + getVoltageText(volts[1]); } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Delay (s)", delay, 0, 0); + if (n == 1) + return new EditInfo("Threshold (V)", threshold, 0, 0); + if (n == 2) + return new EditInfo("High Logic Voltage", highVoltage, 0, 0); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + delay = ei.value; + if (n == 1) + threshold = ei.value; + if (n == 2) + highVoltage = ei.value; + } + + // there is no current path through the inverter input, but there + // is an indirect path through the output to ground. + boolean getConnection(int n1, int n2) { + return false; + } + + boolean hasGroundConnection(int n1) { + return (n1 == 1); + } + + @Override + double getCurrentIntoNode(int n) { + if (n == 1) + return current; + return 0; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/DiacElm.java b/src/com/lushprojects/circuitjs1/client/DiacElm.java index 2ff52cbf..05316dc1 100644 --- a/src/com/lushprojects/circuitjs1/client/DiacElm.java +++ b/src/com/lushprojects/circuitjs1/client/DiacElm.java @@ -27,7 +27,7 @@ class DiacElm extends CircuitElm { double onresistance, offresistance, breakdown, holdcurrent; boolean state; Diode diode1, diode2; - + public DiacElm(int xx, int yy) { super(xx, yy); offresistance = 1e8; @@ -37,53 +37,59 @@ public DiacElm(int xx, int yy) { state = false; createDiodes(); } - public DiacElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public DiacElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - onresistance = new Double(st.nextToken()).doubleValue(); - offresistance = new Double(st.nextToken()).doubleValue(); - breakdown = new Double(st.nextToken()).doubleValue(); - holdcurrent = new Double(st.nextToken()).doubleValue(); + onresistance = Double.valueOf(st.nextToken()).doubleValue(); + offresistance = Double.valueOf(st.nextToken()).doubleValue(); + breakdown = Double.valueOf(st.nextToken()).doubleValue(); + holdcurrent = Double.valueOf(st.nextToken()).doubleValue(); createDiodes(); } - + void createDiodes() { diode1 = new Diode(sim); diode2 = new Diode(sim); diode1.setupForDefaultModel(); diode2.setupForDefaultModel(); } - boolean nonLinear() {return true;} - int getDumpType() { return 203; } + + boolean nonLinear() { + return true; + } + + int getDumpType() { + return 203; + } + String dump() { - return super.dump() + " " + onresistance + " " + offresistance + " " - + breakdown + " " + holdcurrent; + return super.dump() + " " + onresistance + " " + offresistance + " " + breakdown + " " + holdcurrent; } - + Polygon arrows[]; Point plate1[], plate2[]; - + void setPoints() { super.setPoints(); calcLeads(16); - + plate1 = newPointArray(2); plate2 = newPointArray(2); interpPoint2(lead1, lead2, plate1[0], plate1[1], 0, 16); interpPoint2(lead1, lead2, plate2[0], plate2[1], 1, 16); - + arrows = new Polygon[2]; - + int i; for (i = 0; i != 2; i++) { - int sgn = -1+i*2; - Point p1 = interpPoint(lead1, lead2, i, 8*sgn); - Point p2 = interpPoint(lead1, lead2, 1-i, 16*sgn); - Point p3 = interpPoint(lead1, lead2, 1-i, 0*sgn); + int sgn = -1 + i * 2; + Point p1 = interpPoint(lead1, lead2, i, 8 * sgn); + Point p2 = interpPoint(lead1, lead2, 1 - i, 16 * sgn); + Point p3 = interpPoint(lead1, lead2, 1 - i, 0 * sgn); arrows[i] = createPolygon(p1, p2, p3); } } - + void draw(Graphics g) { double v1 = volts[0]; double v2 = volts[1]; @@ -103,30 +109,39 @@ void draw(Graphics g) { doDots(g); drawPosts(g); } - + void calculateCurrent() { double r = (state) ? onresistance : offresistance; - current = (volts[0]-volts[2])/r + (volts[0]-volts[3])/r; + current = (volts[0] - volts[2]) / r + (volts[0] - volts[3]) / r; } + void startIteration() { double vd = volts[0] - volts[1]; - if(Math.abs(current) < holdcurrent) state = false; - if(Math.abs(vd) > breakdown) state = true; + if (Math.abs(current) < holdcurrent) + state = false; + if (Math.abs(vd) > breakdown) + state = true; } + void doStep() { double r = (state) ? onresistance : offresistance; sim.stampResistor(nodes[0], nodes[2], r); sim.stampResistor(nodes[0], nodes[3], r); - diode1.doStep(volts[2]-volts[1]); - diode2.doStep(volts[1]-volts[3]); + diode1.doStep(volts[2] - volts[1]); + diode2.doStep(volts[1] - volts[3]); } + void stamp() { sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); diode1.stamp(nodes[2], nodes[1]); diode2.stamp(nodes[1], nodes[3]); } - int getInternalNodeCount() { return 2; } + + int getInternalNodeCount() { + return 2; + } + void getInfo(String arr[]) { arr[0] = "DIAC"; getBasicInfo(arr); @@ -135,8 +150,9 @@ void getInfo(String arr[]) { arr[5] = "Roff = " + getUnitText(offresistance, Locale.ohmString); arr[6] = "Vbrkdn = " + getUnitText(breakdown, "V"); arr[7] = "Ihold = " + getUnitText(holdcurrent, "A"); - arr[8] = "P = " + getUnitText(getPower(), "W"); + arr[8] = "P = " + getUnitText(getPower(), "W"); } + public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("On resistance (ohms)", onresistance, 0, 0); @@ -148,6 +164,7 @@ public EditInfo getEditInfo(int n) { return new EditInfo("Hold current (amps)", holdcurrent, 0, 0); return null; } + public void setEditValue(int n, EditInfo ei) { if (ei.value > 0 && n == 0) onresistance = ei.value; @@ -159,4 +176,3 @@ public void setEditValue(int n, EditInfo ei) { holdcurrent = ei.value; } } - diff --git a/src/com/lushprojects/circuitjs1/client/Dialog.java b/src/com/lushprojects/circuitjs1/client/Dialog.java index 98d7781d..3e05a247 100644 --- a/src/com/lushprojects/circuitjs1/client/Dialog.java +++ b/src/com/lushprojects/circuitjs1/client/Dialog.java @@ -19,33 +19,29 @@ package com.lushprojects.circuitjs1.client; - import com.google.gwt.user.client.ui.DialogBox; -class Dialog extends DialogBox { +class Dialog extends DialogBox { - boolean closeOnEnter; + boolean closeOnEnter; - Dialog() { - closeOnEnter = true; - } + Dialog() { + closeOnEnter = true; + } - public void closeDialog() - { - hide(); - if (CirSim.dialogShowing == this) - CirSim.dialogShowing = null; - } - - - public void enterPressed() { - if (closeOnEnter) { - apply(); - closeDialog(); - } - } + public void closeDialog() { + hide(); + if (CirSim.dialogShowing == this) + CirSim.dialogShowing = null; + } - void apply() { + public void enterPressed() { + if (closeOnEnter) { + apply(); + closeDialog(); } -} + } + void apply() { + } +} diff --git a/src/com/lushprojects/circuitjs1/client/Diode.java b/src/com/lushprojects/circuitjs1/client/Diode.java index be1bacb7..2ee90e01 100644 --- a/src/com/lushprojects/circuitjs1/client/Diode.java +++ b/src/com/lushprojects/circuitjs1/client/Diode.java @@ -23,72 +23,82 @@ class Diode { int nodes[]; CirSim sim; - + Diode(CirSim s) { sim = s; nodes = new int[2]; } + void setup(DiodeModel model) { leakage = model.saturationCurrent; zvoltage = model.breakdownVoltage; vscale = model.vscale; vdcoef = model.vdcoef; - -// sim.console("setup " + leakage + " " + zvoltage + " " + model.emissionCoefficient + " " + vdcoef); + + // sim.console("setup " + leakage + " " + zvoltage + " " + + // model.emissionCoefficient + " " + vdcoef); // critical voltage for limiting; current is vscale/sqrt(2) at // this voltage - vcrit = vscale * Math.log(vscale/(Math.sqrt(2)*leakage)); - // translated, *positive* critical voltage for limiting in Zener breakdown region; - // limitstep() uses this with translated voltages in an analogous fashion to vcrit. - vzcrit = vt * Math.log(vt/(Math.sqrt(2)*leakage)); + vcrit = vscale * Math.log(vscale / (Math.sqrt(2) * leakage)); + // translated, *positive* critical voltage for limiting in Zener breakdown + // region; + // limitstep() uses this with translated voltages in an analogous fashion to + // vcrit. + vzcrit = vt * Math.log(vt / (Math.sqrt(2) * leakage)); if (zvoltage == 0) zoffset = 0; else { // calculate offset which will give us 5mA at zvoltage double i = -.005; - zoffset = zvoltage-Math.log(-(1+i/leakage))/vzcoef; + zoffset = zvoltage - Math.log(-(1 + i / leakage)) / vzcoef; } } - + void setupForDefaultModel() { setup(DiodeModel.getDefaultModel()); } - + void reset() { lastvoltdiff = 0; } - + // Electron thermal voltage at SPICE's default temperature of 27 C (300.15 K): static final double vt = 0.025865; - // The diode's "scale voltage", the voltage increase which will raise current by a factor of e. + // The diode's "scale voltage", the voltage increase which will raise current by + // a factor of e. double vscale; // The multiplicative equivalent of dividing by vscale (for speed). double vdcoef; - // The Zener breakdown curve is represented by a steeper exponential, one like the ideal - // Shockley curve, but flipped and translated. This curve removes the moderating influence + // The Zener breakdown curve is represented by a steeper exponential, one like + // the ideal + // Shockley curve, but flipped and translated. This curve removes the moderating + // influence // of emcoef, replacing vscale and vdcoef with vt and vzcoef. // vzcoef is the multiplicative equivalent of dividing by vt (for speed). static final double vzcoef = 1 / vt; // User-specified diode parameters for forward voltage drop and Zener voltage. double fwdrop, zvoltage; - // The diode current's scale factor, calculated from the user-specified forward voltage drop. + // The diode current's scale factor, calculated from the user-specified forward + // voltage drop. double leakage; - // Voltage offset for Zener breakdown exponential, calculated from user-specified Zener voltage. + // Voltage offset for Zener breakdown exponential, calculated from + // user-specified Zener voltage. double zoffset; - // Critical voltages for limiting the normal diode and Zener breakdown exponentials. + // Critical voltages for limiting the normal diode and Zener breakdown + // exponentials. double vcrit, vzcrit; double lastvoltdiff; - + double limitStep(double vnew, double vold) { double arg; double oo = vnew; // check new voltage; has current changed by factor of e^2? if (vnew > vcrit && Math.abs(vnew - vold) > (vscale + vscale)) { - if(vold > 0) { + if (vold > 0) { arg = 1 + (vnew - vold) / vscale; - if(arg > 0) { + if (arg > 0) { // adjust vnew so that the current is the same // as in linearized model from previous iteration. // current at vnew = old current * arg @@ -100,104 +110,96 @@ void reset() { // adjust vnew so that the current is the same // as in linearized model from previous iteration. // (1/vscale = slope of load line) - vnew = vscale *Math.log(vnew/vscale); + vnew = vscale * Math.log(vnew / vscale); } sim.converged = false; - //System.out.println(vnew + " " + oo + " " + vold); + // System.out.println(vnew + " " + oo + " " + vold); } else if (vnew < 0 && zoffset != 0) { // for Zener breakdown, use the same logic but translate the values, // and replace the normal values with the Zener-specific ones to // account for the steeper exponential of our Zener breakdown curve. vnew = -vnew - zoffset; vold = -vold - zoffset; - + if (vnew > vzcrit && Math.abs(vnew - vold) > (vt + vt)) { - if(vold > 0) { + if (vold > 0) { arg = 1 + (vnew - vold) / vt; - if(arg > 0) { + if (arg > 0) { vnew = vold + vt * Math.log(arg); - //System.out.println(oo + " " + vnew); + // System.out.println(oo + " " + vnew); } else { vnew = vzcrit; } } else { - vnew = vt *Math.log(vnew/vt); + vnew = vt * Math.log(vnew / vt); } sim.converged = false; } - vnew = -(vnew+zoffset); + vnew = -(vnew + zoffset); } return vnew; } - + void stamp(int n0, int n1) { nodes[0] = n0; nodes[1] = n1; sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); } - + void doStep(double voltdiff) { // used to have .1 here, but needed .01 for peak detector - if (Math.abs(voltdiff-lastvoltdiff) > .01) + if (Math.abs(voltdiff - lastvoltdiff) > .01) sim.converged = false; voltdiff = limitStep(voltdiff, lastvoltdiff); lastvoltdiff = voltdiff; - // To prevent a possible singular matrix or other numeric issues, put a tiny conductance + // To prevent a possible singular matrix or other numeric issues, put a tiny + // conductance // in parallel with each P-N junction. double gmin = leakage * 0.01; if (sim.subIterations > 100) { // if we have trouble converging, put a conductance in parallel with the diode. // Gradually increase the conductance value for each iteration. - gmin = Math.exp(-9*Math.log(10)*(1-sim.subIterations/3000.)); + gmin = Math.exp(-9 * Math.log(10) * (1 - sim.subIterations / 3000.)); if (gmin > .1) gmin = .1; } if (voltdiff >= 0 || zvoltage == 0) { // regular diode or forward-biased zener - double eval = Math.exp(voltdiff*vdcoef); - double geq = vdcoef*leakage*eval + gmin; - double nc = (eval-1)*leakage - geq*voltdiff; + double eval = Math.exp(voltdiff * vdcoef); + double geq = vdcoef * leakage * eval + gmin; + double nc = (eval - 1) * leakage - geq * voltdiff; sim.stampConductance(nodes[0], nodes[1], geq); sim.stampCurrentSource(nodes[0], nodes[1], nc); } else { // Zener diode - + // For reverse-biased Zener diodes, mimic the Zener breakdown curve with an // exponential similar to the ideal Shockley curve. (The real breakdown curve // isn't a simple exponential, but this approximation should be OK.) - /* + /* * I(Vd) = Is * (exp[Vd*C] - exp[(-Vd-Vz)*Cz] - 1 ) * - * geq is I'(Vd) - * nc is I(Vd) + I'(Vd)*(-Vd) + * geq is I'(Vd) nc is I(Vd) + I'(Vd)*(-Vd) */ - double geq = leakage* ( - vdcoef*Math.exp(voltdiff*vdcoef) + vzcoef*Math.exp((-voltdiff-zoffset)*vzcoef) - ) + gmin; + double geq = leakage + * (vdcoef * Math.exp(voltdiff * vdcoef) + vzcoef * Math.exp((-voltdiff - zoffset) * vzcoef)) + gmin; - double nc = leakage* ( - Math.exp(voltdiff*vdcoef) - - Math.exp((-voltdiff-zoffset)*vzcoef) - - 1 - ) + geq*(-voltdiff); + double nc = leakage * (Math.exp(voltdiff * vdcoef) - Math.exp((-voltdiff - zoffset) * vzcoef) - 1) + + geq * (-voltdiff); sim.stampConductance(nodes[0], nodes[1], geq); - sim.stampCurrentSource(nodes[0], nodes[1], nc); + sim.stampCurrentSource(nodes[0], nodes[1], nc); } } - + double calculateCurrent(double voltdiff) { if (voltdiff >= 0 || zvoltage == 0) - return leakage*(Math.exp(voltdiff*vdcoef)-1); - return leakage* ( - Math.exp(voltdiff*vdcoef) - - Math.exp((-voltdiff-zoffset)*vzcoef) - - 1 - ); + return leakage * (Math.exp(voltdiff * vdcoef) - 1); + return leakage * (Math.exp(voltdiff * vdcoef) - Math.exp((-voltdiff - zoffset) * vzcoef) - 1); } } diff --git a/src/com/lushprojects/circuitjs1/client/DiodeElm.java b/src/com/lushprojects/circuitjs1/client/DiodeElm.java index 18f1d720..5b9c10b7 100644 --- a/src/com/lushprojects/circuitjs1/client/DiodeElm.java +++ b/src/com/lushprojects/circuitjs1/client/DiodeElm.java @@ -34,16 +34,15 @@ class DiodeElm extends CircuitElm { static String lastModelName = "default"; boolean hasResistance; int diodeEndNode; - + public DiodeElm(int xx, int yy) { super(xx, yy); modelName = lastModelName; diode = new Diode(sim); setup(); } - - public DiodeElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public DiodeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); final double defaultdrop = .805904783; diode = new Diode(sim); @@ -54,54 +53,62 @@ public DiodeElm(int xa, int ya, int xb, int yb, int f, } else { if ((f & FLAG_FWDROP) > 0) { try { - fwdrop = new Double(st.nextToken()).doubleValue(); + fwdrop = Double.valueOf(st.nextToken()).doubleValue(); } catch (Exception e) { } } model = DiodeModel.getModelWithParameters(fwdrop, zvoltage); modelName = model.name; -// CirSim.console("model name wparams = " + modelName); + // CirSim.console("model name wparams = " + modelName); } setup(); } - boolean nonLinear() { return true; } - + + boolean nonLinear() { + return true; + } + void setup() { -// CirSim.console("setting up for model " + modelName + " " + model); - model = DiodeModel.getModelWithNameOrCopy(modelName, model); - modelName = model.name; // in case we couldn't find that model + // CirSim.console("setting up for model " + modelName + " " + model); + model = DiodeModel.getModelWithNameOrCopy(modelName, model); + modelName = model.name; // in case we couldn't find that model diode.setup(model); hasResistance = (model.seriesResistance > 0); diodeEndNode = (hasResistance) ? 2 : 1; allocNodes(); } - - int getInternalNodeCount() { return hasResistance ? 1 : 0; } - + + int getInternalNodeCount() { + return hasResistance ? 1 : 0; + } + public void updateModels() { setup(); } - - int getDumpType() { return 'd'; } + + int getDumpType() { + return 'd'; + } + String dump() { flags |= FLAG_MODEL; -/* if (modelName == null) { - sim.console("model name is null??"); - modelName = "default"; - }*/ + /* + * if (modelName == null) { sim.console("model name is null??"); modelName = + * "default"; } + */ return super.dump() + " " + CustomLogicModel.escape(modelName); } - + String dumpModel() { if (model.builtIn || model.dumped) return null; return model.dump(); } - + final int hs = 8; Polygon poly; Point cathode[]; - + void setPoints() { super.setPoints(); calcLeads(16); @@ -111,20 +118,20 @@ void setPoints() { interpPoint2(lead1, lead2, cathode[0], cathode[1], 1, hs); poly = createPolygon(pa[0], pa[1], lead2); } - + void draw(Graphics g) { drawDiode(g); doDots(g); drawPosts(g); } - + void reset() { diode.reset(); volts[0] = volts[1] = curcount = 0; if (hasResistance) volts[2] = 0; } - + void drawDiode(Graphics g) { setBbox(point1, point2, hs); @@ -143,7 +150,7 @@ void drawDiode(Graphics g) { setPowerColor(g, true); drawThickLine(g, cathode[0], cathode[1]); } - + void stamp() { if (hasResistance) { // create diode from node 0 to internal node @@ -154,12 +161,15 @@ void stamp() { // don't need any internal nodes if no series resistance diode.stamp(nodes[0], nodes[1]); } + void doStep() { - diode.doStep(volts[0]-volts[diodeEndNode]); + diode.doStep(volts[0] - volts[diodeEndNode]); } + void calculateCurrent() { - current = diode.calculateCurrent(volts[0]-volts[diodeEndNode]); + current = diode.calculateCurrent(volts[0] - volts[diodeEndNode]); } + void getInfo(String arr[]) { if (model.oldStyle) arr[0] = "diode"; @@ -171,12 +181,12 @@ void getInfo(String arr[]) { if (model.oldStyle) arr[4] = "Vf = " + getVoltageText(model.fwdrop); } - + Vector models; - + public EditInfo getEditInfo(int n) { if (n == 0) { - EditInfo ei = new EditInfo("Model", 0, -1, -1); + EditInfo ei = new EditInfo("Model", 0, -1, -1); models = DiodeModel.getModelList(this instanceof ZenerElm); ei.choice = new Choice(); int i; @@ -188,32 +198,32 @@ public EditInfo getEditInfo(int n) { } return ei; } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Create New Simple Model")); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Create New Advanced Model")); - return ei; - } - if (n == 3) { - if (model.readOnly) - return null; - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Edit Model")); - return ei; - } - return null; + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Create New Simple Model")); + return ei; + } + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Create New Advanced Model")); + return ei; + } + if (n == 3) { + if (model.readOnly) + return null; + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Edit Model")); + return ei; + } + return null; } - + public void newModelCreated(DiodeModel dm) { model = dm; modelName = model.name; setup(); } - + public void setEditValue(int n, EditInfo ei) { if (n == 0) { model = models.get(ei.choice.getSelectedIndex()); @@ -222,41 +232,44 @@ public void setEditValue(int n, EditInfo ei) { ei.newDialog = true; return; } - if (n == 1 || n == 2) { - DiodeModel newModel = new DiodeModel(model); - newModel.setSimple(n == 1); - if (newModel.isSimple()) - newModel.setForwardVoltage(); - EditDialog editDialog = new EditDiodeModelDialog(newModel, sim, this); - CirSim.diodeModelEditDialog = editDialog; - editDialog.show(); - return; - } - if (n == 3) { - if (model.readOnly) { - // probably never reached - Window.alert(Locale.LS("This model cannot be modified. Change the model name to allow customization.")); - return; - } - if (model.isSimple()) - model.setForwardVoltage(); - EditDialog editDialog = new EditDiodeModelDialog(model, sim, null); - CirSim.diodeModelEditDialog = editDialog; - editDialog.show(); - return; - } + if (n == 1 || n == 2) { + DiodeModel newModel = new DiodeModel(model); + newModel.setSimple(n == 1); + if (newModel.isSimple()) + newModel.setForwardVoltage(); + EditDialog editDialog = new EditDiodeModelDialog(newModel, sim, this); + CirSim.diodeModelEditDialog = editDialog; + editDialog.show(); + return; + } + if (n == 3) { + if (model.readOnly) { + // probably never reached + Window.alert( + Locale.LS("This model cannot be modified. Change the model name to allow customization.")); + return; + } + if (model.isSimple()) + model.setForwardVoltage(); + EditDialog editDialog = new EditDiodeModelDialog(model, sim, null); + CirSim.diodeModelEditDialog = editDialog; + editDialog.show(); + return; + } } - int getShortcut() { return 'd'; } - + + int getShortcut() { + return 'd'; + } + void setLastModelName(String n) { lastModelName = n; } - + void stepFinished() { - // stop for huge currents that make simulator act weird - if (Math.abs(current) > 1e12) - sim.stop("max current exceeded", this); + // stop for huge currents that make simulator act weird + if (Math.abs(current) > 1e12) + sim.stop("max current exceeded", this); } - } diff --git a/src/com/lushprojects/circuitjs1/client/DiodeModel.java b/src/com/lushprojects/circuitjs1/client/DiodeModel.java index 15d441f1..c264c13c 100644 --- a/src/com/lushprojects/circuitjs1/client/DiodeModel.java +++ b/src/com/lushprojects/circuitjs1/client/DiodeModel.java @@ -11,41 +11,42 @@ public class DiodeModel implements Editable, Comparable { static HashMap modelMap; - + int flags; String name, description; double saturationCurrent, seriesResistance, emissionCoefficient, breakdownVoltage; - + // used for UI code, not guaranteed to be set double forwardVoltage, forwardCurrent; - + boolean dumped; boolean readOnly; boolean builtIn; boolean oldStyle; boolean internal; - static final int FLAGS_SIMPLE = 1; - + static final int FLAGS_SIMPLE = 1; + // Electron thermal voltage at SPICE's default temperature of 27 C (300.15 K): static final double vt = 0.025865; - // The diode's "scale voltage", the voltage increase which will raise current by a factor of e. + // The diode's "scale voltage", the voltage increase which will raise current by + // a factor of e. double vscale; // The multiplicative equivalent of dividing by vscale (for speed). double vdcoef; // voltage drop @ 1A double fwdrop; - + protected DiodeModel(double sc, double sr, double ec, double bv, String d) { saturationCurrent = sc; seriesResistance = sr; emissionCoefficient = ec; breakdownVoltage = bv; description = d; -// CirSim.console("creating diode model " + this); -// CirSim.debugger(); + // CirSim.console("creating diode model " + this); + // CirSim.debugger(); updateModel(); } - + static DiodeModel getModelWithName(String name) { createModelMap(); DiodeModel lm = modelMap.get(name); @@ -56,7 +57,7 @@ static DiodeModel getModelWithName(String name) { modelMap.put(name, lm); return lm; } - + static DiodeModel getModelWithNameOrCopy(String name, DiodeModel oldmodel) { createModelMap(); DiodeModel lm = modelMap.get(name); @@ -66,25 +67,27 @@ static DiodeModel getModelWithNameOrCopy(String name, DiodeModel oldmodel) { CirSim.console("model not found: " + name); return getDefaultModel(); } -// CirSim.console("copying to " + name); + // CirSim.console("copying to " + name); lm = new DiodeModel(oldmodel); lm.name = name; modelMap.put(name, lm); return lm; } - + static void createModelMap() { if (modelMap != null) return; - modelMap = new HashMap(); + modelMap = new HashMap(); addDefaultModel("spice-default", new DiodeModel(1e-14, 0, 1, 0, null)); addDefaultModel("default", new DiodeModel(1.7143528192808883e-7, 0, 2, 0, null)); addDefaultModel("default-zener", new DiodeModel(1.7143528192808883e-7, 0, 2, 5.6, null)); - - // old default LED with saturation current that is way too small (causes numerical errors) + + // old default LED with saturation current that is way too small (causes + // numerical errors) addDefaultModel("old-default-led", new DiodeModel(2.2349907006671927e-18, 0, 2, 0, null).setInternal()); - - // default for newly created LEDs, https://www.diyaudio.com/forums/software-tools/25884-spice-models-led.html + + // default for newly created LEDs, + // https://www.diyaudio.com/forums/software-tools/25884-spice-models-led.html addDefaultModel("default-led", new DiodeModel(93.2e-12, .042, 3.73, 0, null)); // https://www.allaboutcircuits.com/textbook/semiconductors/chpt-3/spice-models/ @@ -92,15 +95,16 @@ static void createModelMap() { addDefaultModel("1N5712", new DiodeModel(680e-12, 12, 1.003, 20, "Schottky")); addDefaultModel("1N34", new DiodeModel(200e-12, 84e-3, 2.19, 60, "germanium")); addDefaultModel("1N4004", new DiodeModel(18.8e-9, 28.6e-3, 2, 400, "general purpose")); -// addDefaultModel("1N3891", new DiodeModel(63e-9, 9.6e-3, 2, 0)); // doesn't match datasheet very well - + // addDefaultModel("1N3891", new DiodeModel(63e-9, 9.6e-3, 2, 0)); // doesn't + // match datasheet very well + // http://users.skynet.be/hugocoolens/spice/diodes/1n4148.htm addDefaultModel("1N4148", new DiodeModel(4.352e-9, .6458, 1.906, 75, "switching")); addDefaultModel("x2n2646-emitter", new DiodeModel(2.13e-11, 0, 1.8, 0, null).setInternal()); - + // for TL431 loadInternalModel("~tl431ed-d_ed 0 1e-14 5 1 0 0"); - + // for LM317 loadInternalModel("~lm317-dz 0 1e-14 0 1 6.3 0"); } @@ -115,21 +119,24 @@ DiodeModel setInternal() { internal = true; return this; } - - // create a new model using given parameters, keeping backward compatibility. The method we use has problems, but we don't want to - // change circuit behavior. We don't do this anymore because we discovered that changing the leakage current to get a given fwdrop + + // create a new model using given parameters, keeping backward compatibility. + // The method we use has problems, but we don't want to + // change circuit behavior. We don't do this anymore because we discovered that + // changing the leakage current to get a given fwdrop // does not work well; the leakage currents can be way too high or low. static DiodeModel getModelWithParameters(double fwdrop, double zvoltage) { createModelMap(); - + final double emcoef = 2; // look for existing model with same parameters Iterator it = modelMap.entrySet().iterator(); while (it.hasNext()) { - Map.Entry pair = (Map.Entry)it.next(); + Map.Entry pair = (Map.Entry) it.next(); DiodeModel dm = pair.getValue(); - if (Math.abs(dm.fwdrop-fwdrop) < 1e-8 && dm.seriesResistance == 0 && Math.abs(dm.breakdownVoltage-zvoltage) < 1e-8 && dm.emissionCoefficient == emcoef) + if (Math.abs(dm.fwdrop - fwdrop) < 1e-8 && dm.seriesResistance == 0 + && Math.abs(dm.breakdownVoltage - zvoltage) < 1e-8 && dm.emissionCoefficient == emcoef) return dm; } @@ -141,25 +148,26 @@ static DiodeModel getModelWithParameters(double fwdrop, double zvoltage) { if (zvoltage != 0) name = name + " zvoltage=" + zvoltage; DiodeModel dm = getModelWithName(name); -// CirSim.console("got model with name " + name); + // CirSim.console("got model with name " + name); dm.saturationCurrent = leakage; dm.emissionCoefficient = emcoef; dm.breakdownVoltage = zvoltage; dm.readOnly = dm.oldStyle = true; -// CirSim.console("at drop current is " + (leakage*(Math.exp(fwdrop*vdcoef)-1))); -// CirSim.console("sat " + leakage + " em " + emcoef); + // CirSim.console("at drop current is " + + // (leakage*(Math.exp(fwdrop*vdcoef)-1))); + // CirSim.console("sat " + leakage + " em " + emcoef); dm.updateModel(); return dm; } - + static DiodeModel getDefaultModel() { return getModelWithName("default"); } - + static void loadInternalModel(String s) { - StringTokenizer st = new StringTokenizer(s); - DiodeModel dm = undumpModel(st); - dm.builtIn = dm.internal = true; + StringTokenizer st = new StringTokenizer(s); + DiodeModel dm = undumpModel(st); + dm.builtIn = dm.internal = true; } static void clearDumpedFlags() { @@ -167,16 +175,16 @@ static void clearDumpedFlags() { return; Iterator it = modelMap.entrySet().iterator(); while (it.hasNext()) { - Map.Entry pair = (Map.Entry)it.next(); + Map.Entry pair = (Map.Entry) it.next(); pair.getValue().dumped = false; } } - + static Vector getModelList(boolean zener) { Vector vector = new Vector(); Iterator it = modelMap.entrySet().iterator(); while (it.hasNext()) { - Map.Entry pair = (Map.Entry)it.next(); + Map.Entry pair = (Map.Entry) it.next(); DiodeModel dm = pair.getValue(); if (dm.internal) continue; @@ -192,13 +200,13 @@ static Vector getModelList(boolean zener) { public int compareTo(DiodeModel dm) { return name.compareTo(dm.name); } - + String getDescription() { if (description == null) return name; return name + " (" + Locale.LS(description) + ")"; } - + DiodeModel() { saturationCurrent = 1e-14; seriesResistance = 0; @@ -206,7 +214,7 @@ String getDescription() { breakdownVoltage = 0; updateModel(); } - + DiodeModel(DiodeModel copy) { flags = copy.flags; saturationCurrent = copy.saturationCurrent; @@ -223,19 +231,20 @@ static DiodeModel undumpModel(StringTokenizer st) { dm.undump(st); return dm; } - + void undump(StringTokenizer st) { - flags = new Integer(st.nextToken()).intValue(); + flags = Integer.valueOf(st.nextToken()).intValue(); saturationCurrent = Double.parseDouble(st.nextToken()); seriesResistance = Double.parseDouble(st.nextToken()); emissionCoefficient = Double.parseDouble(st.nextToken()); breakdownVoltage = Double.parseDouble(st.nextToken()); try { forwardCurrent = Double.parseDouble(st.nextToken()); - } catch (Exception e) {} + } catch (Exception e) { + } updateModel(); } - + public EditInfo getEditInfo(int n) { if (n == 0) { EditInfo ei = new EditInfo("Model Name", 0); @@ -253,7 +262,8 @@ public EditInfo getEditInfo(int n) { if (n == 2) return new EditInfo("Series Resistance", seriesResistance, -1, -1); if (n == 3) - return new EditInfo(EditInfo.makeLink("diodecalc.html", "Emission Coefficient"), emissionCoefficient, -1, -1); + return new EditInfo(EditInfo.makeLink("diodecalc.html", "Emission Coefficient"), emissionCoefficient, + -1, -1); } if (n == 4) return new EditInfo("Breakdown Voltage", breakdownVoltage, -1, -1); @@ -286,39 +296,40 @@ public void setEditValue(int n, EditInfo ei) { CirSim.theSim.updateModels(); } - // set emission coefficient for simple mode if we have enough data + // set emission coefficient for simple mode if we have enough data void setEmissionCoefficient() { if (forwardCurrent > 0 && forwardVoltage > 0) - emissionCoefficient = (forwardVoltage/Math.log(forwardCurrent/saturationCurrent+1)) / vt; + emissionCoefficient = (forwardVoltage / Math.log(forwardCurrent / saturationCurrent + 1)) / vt; seriesResistance = 0; } - + public void setForwardVoltage() { if (forwardCurrent == 0) forwardCurrent = 1; - forwardVoltage = emissionCoefficient*vt * Math.log(forwardCurrent/saturationCurrent+1); + forwardVoltage = emissionCoefficient * vt * Math.log(forwardCurrent / saturationCurrent + 1); } - + void updateModel() { vscale = emissionCoefficient * vt; - vdcoef = 1/vscale; - fwdrop = Math.log(1/saturationCurrent + 1) * emissionCoefficient * vt; + vdcoef = 1 / vscale; + fwdrop = Math.log(1 / saturationCurrent + 1) * emissionCoefficient * vt; } - + String dump() { dumped = true; - return "34 " + CustomLogicModel.escape(name) + " " + flags + " " + saturationCurrent + " " + seriesResistance + " " + emissionCoefficient + " " + breakdownVoltage + " " + forwardCurrent; + return "34 " + CustomLogicModel.escape(name) + " " + flags + " " + saturationCurrent + " " + seriesResistance + + " " + emissionCoefficient + " " + breakdownVoltage + " " + forwardCurrent; } - + boolean isSimple() { return (flags & FLAGS_SIMPLE) != 0; } - + void setSimple(boolean s) { flags = (s) ? FLAGS_SIMPLE : 0; } - + void pickName() { if (breakdownVoltage > 0 && breakdownVoltage < 20) name = "zener-" + CircuitElm.showFormat.format(breakdownVoltage); @@ -328,7 +339,7 @@ else if (isSimple()) name = "diodemodel"; if (modelMap.get(name) != null) { int num = 2; - for (; ; num++) { + for (;; num++) { String n = name + "-" + num; if (modelMap.get(n) == null) { name = n; diff --git a/src/com/lushprojects/circuitjs1/client/EditCompositeModelDialog.java b/src/com/lushprojects/circuitjs1/client/EditCompositeModelDialog.java index 89824110..fbcd4e50 100644 --- a/src/com/lushprojects/circuitjs1/client/EditCompositeModelDialog.java +++ b/src/com/lushprojects/circuitjs1/client/EditCompositeModelDialog.java @@ -50,310 +50,314 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; -public class EditCompositeModelDialog extends Dialog implements MouseDownHandler, MouseMoveHandler, MouseUpHandler, MouseOutHandler, MouseOverHandler { - - VerticalPanel vp; - boolean error; - CustomCompositeChipElm chip; - int postCount; - Context2d context; - CustomCompositeModel model; - - void setModel(CustomCompositeModel m) { model = m; } - - boolean createModel() { - HashSet nodeSet = new HashSet(); - model = CirSim.theSim.getCircuitAsComposite(); - if (model == null) - return false; - if (model.extList.size() == 0) { - Window.alert(Locale.LS("Device has no external inputs/outputs!")); - return false; - } - Collections.sort(model.extList, new Comparator() { - public int compare(ExtListEntry a, ExtListEntry b) { - return a.name.toLowerCase().compareTo(b.name.toLowerCase()); - } - }); - int i; - int postCount = model.extList.size(); - int sideCounts[] = new int[] { 0, 0, 0, 0 }; - for (i = 0; i != postCount; i++) { - ExtListEntry pin = model.extList.get(i); - sideCounts[pin.side] += 1; - - if (nodeSet.contains(pin.node)) { - Window.alert(Locale.LS("Can't have two input/output nodes connected!")); - return false; - } - nodeSet.add(pin.node); - } - - int xOffsetLeft = (sideCounts[ChipElm.SIDE_W] > 0) ? 1 : 0; - int xOffsetRight = (sideCounts[ChipElm.SIDE_E] > 0) ? 1 : 0; - for (i = 0; i != postCount; i++) { - ExtListEntry pin = model.extList.get(i); - if (pin.side == ChipElm.SIDE_N || pin.side == ChipElm.SIDE_S) { - pin.pos += xOffsetLeft; - } - } - - int minHeight = (sideCounts[ChipElm.SIDE_N] > 0 && sideCounts[ChipElm.SIDE_S] > 0) ? 2 : 1; - int minWidth = 2; - int pinsNS = Math.max(sideCounts[ChipElm.SIDE_N], sideCounts[ChipElm.SIDE_S]); - int pinsWE = Math.max(sideCounts[ChipElm.SIDE_W], sideCounts[ChipElm.SIDE_E]); - model.sizeX = Math.max(minWidth, pinsNS + xOffsetLeft + xOffsetRight); - model.sizeY = Math.max(minHeight, pinsWE); - - model.modelCircuit = CirSim.theSim.dumpCircuit(); - return true; - } - - public EditCompositeModelDialog() { - super(); - closeOnEnter = true; +public class EditCompositeModelDialog extends Dialog + implements MouseDownHandler, MouseMoveHandler, MouseUpHandler, MouseOutHandler, MouseOverHandler { + + VerticalPanel vp; + boolean error; + CustomCompositeChipElm chip; + int postCount; + Context2d context; + CustomCompositeModel model; + + void setModel(CustomCompositeModel m) { + model = m; + } + + boolean createModel() { + HashSet nodeSet = new HashSet(); + model = CirSim.theSim.getCircuitAsComposite(); + if (model == null) + return false; + if (model.extList.size() == 0) { + Window.alert(Locale.LS("Device has no external inputs/outputs!")); + return false; } - - TextBox modelNameTextBox = null; - Checkbox saveCheck = null; - Checkbox labelCheck = null; - - void createDialog() { - Button okButton; - Anchor a; - vp=new VerticalPanel(); - setWidget(vp); - setText(Locale.LS("Edit Subcircuit Pin Layout")); - vp.add(new Label(Locale.LS("Drag the pins to the desired position"))); - Date date = new Date(); - - Canvas canvas = Canvas.createIfSupported(); - canvas.setWidth("400 px"); - canvas.setHeight("400 px"); - canvas.setCoordinateSpaceWidth(400); - canvas.setCoordinateSpaceHeight(400); - vp.add(canvas); - CirSim.doTouchHandlers(null, canvas.getCanvasElement()); - context = canvas.getContext2d(); - - chip = new CustomCompositeChipElm(50, 50); - chip.x2 = 200; - chip.y2 = 50; - selectedPin = -1; - createPinsFromModel(); - - if (model.name == null) { - vp.add(new Label(Locale.LS("Model Name"))); - modelNameTextBox = new TextBox(); - vp.add(modelNameTextBox); - modelNameTextBox.addValueChangeHandler(new ValueChangeHandler() { - @Override - public void onValueChange(ValueChangeEvent event) { - drawChip(); - } - }); -// modelNameTextBox.setText(model.name); - } - - HorizontalPanel hp = new HorizontalPanel(); - hp.add(new Label(Locale.LS("Width"))); - Button b; - hp.add(b = new Button("+")); - b.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - adjustChipSize(1, 0); - } - }); - hp.add(b = new Button("-")); - b.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - adjustChipSize(-1, 0); - } - }); - hp.add(new Label(Locale.LS("Height"))); - hp.add(b = new Button("+")); - b.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - adjustChipSize(0, 1); - } - }); - hp.add(b = new Button("-")); - b.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - adjustChipSize(0, -1); - } - }); - vp.add(hp); - hp.addStyleName("topSpace"); - vp.add(labelCheck = new Checkbox(Locale.LS("Show Label"))); - labelCheck.setState(model.showLabel()); - labelCheck.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - model.setShowLabel(labelCheck.getValue()); - drawChip(); - } - }); - vp.add(saveCheck = new Checkbox(Locale.LS("Save Across Sessions"))); - saveCheck.setState(model.isSaved()); - - canvas.addMouseDownHandler(this); - canvas.addMouseUpHandler(this); - canvas.addMouseMoveHandler(this); - canvas.addMouseOutHandler(this); - canvas.addMouseOverHandler(this); - - hp = new HorizontalPanel(); - hp.setWidth("100%"); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); - hp.setStyleName("topSpace"); - vp.add(hp); - hp.add(okButton = new Button(Locale.LS("OK"))); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); - Button cancelButton; - if (model.name == null) { - hp.add(cancelButton = new Button(Locale.LS("Cancel"))); - cancelButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - closeDialog(); - } - }); - } - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - if (modelNameTextBox != null) { - String name = modelNameTextBox.getText(); - if (name.length() == 0) { - Window.alert(Locale.LS("Please enter a model name.")); - return; - } - model.setName(CustomCompositeElm.lastModelName = name); - } - model.setSaved(saveCheck.getState()); - CirSim.theSim.updateModels(); - CirSim.theSim.needAnalyze(); // will get singular matrix if we don't do this - closeDialog(); - } - }); - this.center(); + Collections.sort(model.extList, new Comparator() { + public int compare(ExtListEntry a, ExtListEntry b) { + return a.name.toLowerCase().compareTo(b.name.toLowerCase()); + } + }); + int i; + int postCount = model.extList.size(); + int sideCounts[] = new int[] { 0, 0, 0, 0 }; + for (i = 0; i != postCount; i++) { + ExtListEntry pin = model.extList.get(i); + sideCounts[pin.side] += 1; + + if (nodeSet.contains(pin.node)) { + Window.alert(Locale.LS("Can't have two input/output nodes connected!")); + return false; + } + nodeSet.add(pin.node); } - - void createPinsFromModel() { - postCount = model.extList.size(); - chip.allocPins(postCount); - chip.sizeX = model.sizeX; - chip.sizeY = model.sizeY; - for (int i = 0; i != postCount; i++) { - ExtListEntry pin = model.extList.get(i); - chip.setPin(i, pin.pos, pin.side, pin.name); - chip.volts[i] = 0; - if (i == selectedPin) - chip.pins[i].selected = true; + + int xOffsetLeft = (sideCounts[ChipElm.SIDE_W] > 0) ? 1 : 0; + int xOffsetRight = (sideCounts[ChipElm.SIDE_E] > 0) ? 1 : 0; + for (i = 0; i != postCount; i++) { + ExtListEntry pin = model.extList.get(i); + if (pin.side == ChipElm.SIDE_N || pin.side == ChipElm.SIDE_S) { + pin.pos += xOffsetLeft; } - chip.setPoints(); } - - double scale; - - void drawChip() { - Graphics g = new Graphics(context); - double scalew = context.getCanvas().getWidth() / (double)(chip.boundingBox.width + chip.boundingBox.x*2); - double scaleh = context.getCanvas().getHeight() / (double)(chip.boundingBox.height + chip.boundingBox.y*2); - scale = 1/Math.min(scalew, scaleh); - context.setFillStyle(CirSim.theSim.getBackgroundColor().getHexValue()); - context.setTransform(1, 0, 0, 1, 0, 0); - context.fillRect(0, 0, context.getCanvas().getWidth(), context.getCanvas().getHeight()); - context.setTransform(1/scale, 0, 0, 1/scale, 0, 0); - chip.setLabel(!labelCheck.getValue() ? null : (modelNameTextBox != null) ? modelNameTextBox.getText() : model.name); - chip.draw(g); + + int minHeight = (sideCounts[ChipElm.SIDE_N] > 0 && sideCounts[ChipElm.SIDE_S] > 0) ? 2 : 1; + int minWidth = 2; + int pinsNS = Math.max(sideCounts[ChipElm.SIDE_N], sideCounts[ChipElm.SIDE_S]); + int pinsWE = Math.max(sideCounts[ChipElm.SIDE_W], sideCounts[ChipElm.SIDE_E]); + model.sizeX = Math.max(minWidth, pinsNS + xOffsetLeft + xOffsetRight); + model.sizeY = Math.max(minHeight, pinsWE); + + model.modelCircuit = CirSim.theSim.dumpCircuit(); + return true; + } + + public EditCompositeModelDialog() { + super(); + closeOnEnter = true; + } + + TextBox modelNameTextBox = null; + Checkbox saveCheck = null; + Checkbox labelCheck = null; + + void createDialog() { + Button okButton; + Anchor a; + vp = new VerticalPanel(); + setWidget(vp); + setText(Locale.LS("Edit Subcircuit Pin Layout")); + vp.add(new Label(Locale.LS("Drag the pins to the desired position"))); + Date date = new Date(); + + Canvas canvas = Canvas.createIfSupported(); + canvas.setWidth("400 px"); + canvas.setHeight("400 px"); + canvas.setCoordinateSpaceWidth(400); + canvas.setCoordinateSpaceHeight(400); + vp.add(canvas); + CirSim.doTouchHandlers(null, canvas.getCanvasElement()); + context = canvas.getContext2d(); + + chip = new CustomCompositeChipElm(50, 50); + chip.x2 = 200; + chip.y2 = 50; + selectedPin = -1; + createPinsFromModel(); + + if (model.name == null) { + vp.add(new Label(Locale.LS("Model Name"))); + modelNameTextBox = new TextBox(); + vp.add(modelNameTextBox); + modelNameTextBox.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + drawChip(); + } + }); + // modelNameTextBox.setText(model.name); + } + + HorizontalPanel hp = new HorizontalPanel(); + hp.add(new Label(Locale.LS("Width"))); + Button b; + hp.add(b = new Button("+")); + b.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + adjustChipSize(1, 0); + } + }); + hp.add(b = new Button("-")); + b.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + adjustChipSize(-1, 0); + } + }); + hp.add(new Label(Locale.LS("Height"))); + hp.add(b = new Button("+")); + b.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + adjustChipSize(0, 1); + } + }); + hp.add(b = new Button("-")); + b.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + adjustChipSize(0, -1); + } + }); + vp.add(hp); + hp.addStyleName("topSpace"); + vp.add(labelCheck = new Checkbox(Locale.LS("Show Label"))); + labelCheck.setState(model.showLabel()); + labelCheck.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + model.setShowLabel(labelCheck.getValue()); + drawChip(); + } + }); + vp.add(saveCheck = new Checkbox(Locale.LS("Save Across Sessions"))); + saveCheck.setState(model.isSaved()); + + canvas.addMouseDownHandler(this); + canvas.addMouseUpHandler(this); + canvas.addMouseMoveHandler(this); + canvas.addMouseOutHandler(this); + canvas.addMouseOverHandler(this); + + hp = new HorizontalPanel(); + hp.setWidth("100%"); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); + hp.setStyleName("topSpace"); + vp.add(hp); + hp.add(okButton = new Button(Locale.LS("OK"))); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + Button cancelButton; + if (model.name == null) { + hp.add(cancelButton = new Button(Locale.LS("Cancel"))); + cancelButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); } - - void adjustChipSize(int dx, int dy) { - if (dx < 0 || dy < 0) { - for (int i = 0; i != postCount; i++) { - Pin p = chip.pins[i]; - if (dx < 0 && (p.side == ChipElm.SIDE_N || p.side == ChipElm.SIDE_S) && p.pos >= chip.sizeX+dx) - return; - if (dy < 0 && (p.side == ChipElm.SIDE_E || p.side == ChipElm.SIDE_W) && p.pos >= chip.sizeY+dy) + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + if (modelNameTextBox != null) { + String name = modelNameTextBox.getText(); + if (name.length() == 0) { + Window.alert(Locale.LS("Please enter a model name.")); return; + } + model.setName(CustomCompositeElm.lastModelName = name); } + model.setSaved(saveCheck.getState()); + CirSim.theSim.updateModels(); + CirSim.theSim.needAnalyze(); // will get singular matrix if we don't do this + closeDialog(); } - if (chip.sizeX + dx < 1 || chip.sizeY + dy < 1) - return; - model.sizeX += dx; - model.sizeY += dy; - createPinsFromModel(); - drawChip(); - } - - boolean dragging; - - public void onMouseOver(MouseOverEvent event) { - // TODO Auto-generated method stub - - } + }); + this.center(); + } - public void onMouseOut(MouseOutEvent event) { - // TODO Auto-generated method stub - + void createPinsFromModel() { + postCount = model.extList.size(); + chip.allocPins(postCount); + chip.sizeX = model.sizeX; + chip.sizeY = model.sizeY; + for (int i = 0; i != postCount; i++) { + ExtListEntry pin = model.extList.get(i); + chip.setPin(i, pin.pos, pin.side, pin.name); + chip.volts[i] = 0; + if (i == selectedPin) + chip.pins[i].selected = true; } + chip.setPoints(); + } - public void onMouseUp(MouseUpEvent event) { - dragging = false; - } + double scale; - int selectedPin; - - public void onMouseMove(MouseMoveEvent event) { - mouseMoved(event.getX(), event.getY()); - } - - void mouseMoved(int x, int y) { - if (dragging) { - if (selectedPin < 0) + void drawChip() { + Graphics g = new Graphics(context); + double scalew = context.getCanvas().getWidth() / (double) (chip.boundingBox.width + chip.boundingBox.x * 2); + double scaleh = context.getCanvas().getHeight() / (double) (chip.boundingBox.height + chip.boundingBox.y * 2); + scale = 1 / Math.min(scalew, scaleh); + context.setFillStyle(CirSim.theSim.getBackgroundColor().getHexValue()); + context.setTransform(1, 0, 0, 1, 0, 0); + context.fillRect(0, 0, context.getCanvas().getWidth(), context.getCanvas().getHeight()); + context.setTransform(1 / scale, 0, 0, 1 / scale, 0, 0); + chip.setLabel( + !labelCheck.getValue() ? null : (modelNameTextBox != null) ? modelNameTextBox.getText() : model.name); + chip.draw(g); + } + + void adjustChipSize(int dx, int dy) { + if (dx < 0 || dy < 0) { + for (int i = 0; i != postCount; i++) { + Pin p = chip.pins[i]; + if (dx < 0 && (p.side == ChipElm.SIDE_N || p.side == ChipElm.SIDE_S) && p.pos >= chip.sizeX + dx) return; - int pos[] = new int[2]; - if (!chip.getPinPos((int)(x*scale), (int)(y*scale), selectedPin, pos)) + if (dy < 0 && (p.side == ChipElm.SIDE_E || p.side == ChipElm.SIDE_W) && p.pos >= chip.sizeY + dy) return; - ExtListEntry p = model.extList.get(selectedPin); - int pn = chip.getOverlappingPin(pos[0], pos[1], selectedPin); - if (pn != -1) { - // swap positions with overlapping pin - ExtListEntry p2 = model.extList.get(pn); - p2.pos = p.pos; - p2.side = p.side; - } - p.pos = pos[0]; - p.side = pos[1]; - createPinsFromModel(); - drawChip(); - } else { - int i; - double bestdist = 20; - selectedPin = -1; - for (i = 0; i != postCount; i++) { - Pin p = chip.pins[i]; - int dx = (int)(x*scale) - p.textloc.x; - int dy = (int)(y*scale) - p.textloc.y; - double dist = Math.hypot(dx, dy); - if (dist < bestdist) { - bestdist = dist; - selectedPin = i; - } - p.selected = false; - } - if (selectedPin >= 0) - chip.pins[selectedPin].selected = true; - drawChip(); } } + if (chip.sizeX + dx < 1 || chip.sizeY + dy < 1) + return; + model.sizeX += dx; + model.sizeY += dy; + createPinsFromModel(); + drawChip(); + } - public void onMouseDown(MouseDownEvent event) { - mouseMoved(event.getX(), event.getY()); - dragging = true; - } + boolean dragging; - public void show() { - super.show(); + public void onMouseOver(MouseOverEvent event) { + // TODO Auto-generated method stub + + } + + public void onMouseOut(MouseOutEvent event) { + // TODO Auto-generated method stub + + } + + public void onMouseUp(MouseUpEvent event) { + dragging = false; + } + + int selectedPin; + + public void onMouseMove(MouseMoveEvent event) { + mouseMoved(event.getX(), event.getY()); + } + + void mouseMoved(int x, int y) { + if (dragging) { + if (selectedPin < 0) + return; + int pos[] = new int[2]; + if (!chip.getPinPos((int) (x * scale), (int) (y * scale), selectedPin, pos)) + return; + ExtListEntry p = model.extList.get(selectedPin); + int pn = chip.getOverlappingPin(pos[0], pos[1], selectedPin); + if (pn != -1) { + // swap positions with overlapping pin + ExtListEntry p2 = model.extList.get(pn); + p2.pos = p.pos; + p2.side = p.side; + } + p.pos = pos[0]; + p.side = pos[1]; + createPinsFromModel(); + drawChip(); + } else { + int i; + double bestdist = 20; + selectedPin = -1; + for (i = 0; i != postCount; i++) { + Pin p = chip.pins[i]; + int dx = (int) (x * scale) - p.textloc.x; + int dy = (int) (y * scale) - p.textloc.y; + double dist = Math.hypot(dx, dy); + if (dist < bestdist) { + bestdist = dist; + selectedPin = i; + } + p.selected = false; + } + if (selectedPin >= 0) + chip.pins[selectedPin].selected = true; drawChip(); } + } + + public void onMouseDown(MouseDownEvent event) { + mouseMoved(event.getX(), event.getY()); + dragging = true; + } + + public void show() { + super.show(); + drawChip(); + } } diff --git a/src/com/lushprojects/circuitjs1/client/EditDialog.java b/src/com/lushprojects/circuitjs1/client/EditDialog.java index 35129604..3e3a820a 100644 --- a/src/com/lushprojects/circuitjs1/client/EditDialog.java +++ b/src/com/lushprojects/circuitjs1/client/EditDialog.java @@ -19,7 +19,6 @@ package com.lushprojects.circuitjs1.client; - import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.VerticalPanel; @@ -39,283 +38,306 @@ interface Editable { EditInfo getEditInfo(int n); + void setEditValue(int n, EditInfo ei); } class EditDialog extends Dialog { - Editable elm; - CirSim cframe; - Button applyButton, okButton, cancelButton; - EditInfo einfos[]; - int einfocount; - final int barmax = 1000; - VerticalPanel vp; - HorizontalPanel hp; - static NumberFormat noCommaFormat = NumberFormat.getFormat("####.##########"); + Editable elm; + CirSim cframe; + Button applyButton, okButton, cancelButton; + EditInfo einfos[]; + int einfocount; + final int barmax = 1000; + VerticalPanel vp; + HorizontalPanel hp; + static NumberFormat noCommaFormat = NumberFormat.getFormat("####.##########"); - EditDialog(Editable ce, CirSim f) { -// super(f, "Edit Component", false); - super(); // Do we need this? - setText(Locale.LS("Edit Component")); - cframe = f; - elm = ce; -// setLayout(new EditDialogLayout()); - vp=new VerticalPanel(); - setWidget(vp); - einfos = new EditInfo[10]; -// noCommaFormat = DecimalFormat.getInstance(); -// noCommaFormat.setMaximumFractionDigits(10); -// noCommaFormat.setGroupingUsed(false); - hp=new HorizontalPanel(); - hp.setWidth("100%"); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); - hp.setStyleName("topSpace"); - vp.add(hp); - applyButton = new Button(Locale.LS("Apply")); - hp.add(applyButton); - applyButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - apply(); - } + EditDialog(Editable ce, CirSim f) { + // super(f, "Edit Component", false); + super(); // Do we need this? + setText(Locale.LS("Edit Component")); + cframe = f; + elm = ce; + // setLayout(new EditDialogLayout()); + vp = new VerticalPanel(); + setWidget(vp); + einfos = new EditInfo[10]; + // noCommaFormat = DecimalFormat.getInstance(); + // noCommaFormat.setMaximumFractionDigits(10); + // noCommaFormat.setGroupingUsed(false); + hp = new HorizontalPanel(); + hp.setWidth("100%"); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); + hp.setStyleName("topSpace"); + vp.add(hp); + applyButton = new Button(Locale.LS("Apply")); + hp.add(applyButton); + applyButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + apply(); + } + }); + hp.add(okButton = new Button(Locale.LS("OK"))); + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + apply(); + closeDialog(); + } + }); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + hp.add(cancelButton = new Button(Locale.LS("Cancel"))); + cancelButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); + buildDialog(); + this.center(); + } + + void buildDialog() { + int i; + int idx; + for (i = 0;; i++) { + Label l = null; + einfos[i] = elm.getEditInfo(i); + if (einfos[i] == null) + break; + final EditInfo ei = einfos[i]; + idx = vp.getWidgetIndex(hp); + String name = Locale.LS(ei.name); + if (ei.name.startsWith("<")) + vp.insert(l = new HTML(name), idx); + else + vp.insert(l = new Label(name), idx); + if (i != 0 && l != null) + l.setStyleName("topSpace"); + idx = vp.getWidgetIndex(hp); + if (ei.choice != null) { + vp.insert(ei.choice, idx); + ei.choice.addChangeHandler(new ChangeHandler() { + public void onChange(ChangeEvent e) { + itemStateChanged(e); + } }); - hp.add(okButton = new Button(Locale.LS("OK"))); - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - apply(); - closeDialog(); - } + } else if (ei.checkbox != null) { + vp.insert(ei.checkbox, idx); + ei.checkbox.addValueChangeHandler(new ValueChangeHandler() { + public void onValueChange(ValueChangeEvent e) { + itemStateChanged(e); + } }); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); - hp.add(cancelButton = new Button(Locale.LS("Cancel"))); - cancelButton.addClickHandler(new ClickHandler() { + } else if (ei.button != null) { + vp.insert(ei.button, idx); + if (ei.loadFile != null) { + // Open file dialog + vp.add(ei.loadFile); + ei.button.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { - closeDialog(); + ei.loadFile.open(); } - }); - buildDialog(); - this.center(); - } - - void buildDialog() { - int i; - int idx; - for (i = 0; ; i++) { - Label l = null; - einfos[i] = elm.getEditInfo(i); - if (einfos[i] == null) - break; - final EditInfo ei = einfos[i]; - idx = vp.getWidgetIndex(hp); - String name = Locale.LS(ei.name); - if (ei.name.startsWith("<")) - vp.insert(l = new HTML(name),idx); - else - vp.insert(l = new Label(name),idx); - if (i!=0 && l != null) - l.setStyleName("topSpace"); - idx = vp.getWidgetIndex(hp); - if (ei.choice != null) { - vp.insert(ei.choice,idx); - ei.choice.addChangeHandler( new ChangeHandler() { - public void onChange(ChangeEvent e){ - itemStateChanged(e); - } - }); - } else if (ei.checkbox != null) { - vp.insert(ei.checkbox,idx); - ei.checkbox.addValueChangeHandler( new ValueChangeHandler() { - public void onValueChange(ValueChangeEvent e){ - itemStateChanged(e); - } - }); - } else if (ei.button != null) { - vp.insert(ei.button, idx); - if (ei.loadFile != null) { - //Open file dialog - vp.add(ei.loadFile); - ei.button.addClickHandler( new ClickHandler() { - public void onClick(ClickEvent event) { - ei.loadFile.open(); - } - }); - } else { - //Normal button press - ei.button.addClickHandler( new ClickHandler() { - public void onClick(ClickEvent event) { - itemStateChanged(event); - } - }); - } - } else if (ei.textArea != null) { - vp.insert(ei.textArea, idx); - closeOnEnter = false; - } else if (ei.widget != null) { - vp.insert(ei.widget, idx); - } else { - vp.insert(ei.textf = new TextBox(), idx); - if (ei.text != null) { - ei.textf.setText(ei.text); - ei.textf.setVisibleLength(50); - } - if (ei.text == null) { - ei.textf.setText(unitString(ei)); - } + }); + } else { + // Normal button press + ei.button.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + itemStateChanged(event); } + }); } - einfocount = i; + } else if (ei.textArea != null) { + vp.insert(ei.textArea, idx); + closeOnEnter = false; + } else if (ei.widget != null) { + vp.insert(ei.widget, idx); + } else { + vp.insert(ei.textf = new TextBox(), idx); + if (ei.text != null) { + ei.textf.setText(ei.text); + ei.textf.setVisibleLength(50); + } + if (ei.text == null) { + ei.textf.setText(unitString(ei)); + } + } } + einfocount = i; + } - static final double ROOT2 = 1.41421356237309504880; - - double diffFromInteger(double x) { - return Math.abs(x-Math.round(x)); - } - - String unitString(EditInfo ei) { - // for voltage elements, express values in rms if that would be shorter - if (elm != null && elm instanceof VoltageElm && - Math.abs(ei.value) > 1e-4 && - diffFromInteger(ei.value*1e4) > diffFromInteger(ei.value*1e4/ROOT2)) - return unitString(ei, ei.value/ROOT2) + "rms"; - return unitString(ei, ei.value); - } + static final double ROOT2 = 1.41421356237309504880; - static String unitString(EditInfo ei, double v) { - double va = Math.abs(v); - if (ei != null && ei.dimensionless) - return noCommaFormat.format(v); - if (Double.isInfinite(va)) - return noCommaFormat.format(v); - if (v == 0) return "0"; - if (va < 1e-12) - return noCommaFormat.format(v*1e15) + "f"; - if (va < 1e-9) - return noCommaFormat.format(v*1e12) + "p"; - if (va < 1e-6) - return noCommaFormat.format(v*1e9) + "n"; - if (va < 1e-3) - return noCommaFormat.format(v*1e6) + "u"; - if (va < 1 /*&& !ei.forceLargeM*/) - return noCommaFormat.format(v*1e3) + "m"; - if (va < 1e3) - return noCommaFormat.format(v); - if (va < 1e6) - return noCommaFormat.format(v*1e-3) + "k"; - if (va < 1e9) - return noCommaFormat.format(v*1e-6) + "M"; - return noCommaFormat.format(v*1e-9) + "G"; - } + double diffFromInteger(double x) { + return Math.abs(x - Math.round(x)); + } - double parseUnits(EditInfo ei) throws java.text.ParseException { - String s = ei.textf.getText(); - return parseUnits(s); - } - - static double parseUnits(String s) throws java.text.ParseException { - s = s.trim(); - double rmsMult = 1; - if (s.endsWith("rms")) { - s = s.substring(0, s.length()-3).trim(); - rmsMult = ROOT2; - } - // rewrite shorthand (eg "2k2") in to normal format (eg 2.2k) using regex - s=s.replaceAll("([0-9]+)([pPnNuUmMkKgG])([0-9]+)", "$1.$3$2"); - // rewrite meg to M - s=s.replaceAll("[mM][eE][gG]$", "M"); - int len = s.length(); - char uc = s.charAt(len-1); - double mult = 1; - switch (uc) { - case 'f': case 'F': mult = 1e-15; break; - case 'p': case 'P': mult = 1e-12; break; - case 'n': case 'N': mult = 1e-9; break; - case 'u': case 'U': mult = 1e-6; break; + String unitString(EditInfo ei) { + // for voltage elements, express values in rms if that would be shorter + if (elm != null && elm instanceof VoltageElm && Math.abs(ei.value) > 1e-4 + && diffFromInteger(ei.value * 1e4) > diffFromInteger(ei.value * 1e4 / ROOT2)) + return unitString(ei, ei.value / ROOT2) + "rms"; + return unitString(ei, ei.value); + } - // for ohm values, we used to assume mega for lowercase m, otherwise milli - case 'm': mult = /*(ei.forceLargeM) ? 1e6 : */ 1e-3; break; + static String unitString(EditInfo ei, double v) { + double va = Math.abs(v); + if (ei != null && ei.dimensionless) + return noCommaFormat.format(v); + if (Double.isInfinite(va)) + return noCommaFormat.format(v); + if (v == 0) + return "0"; + if (va < 1e-12) + return noCommaFormat.format(v * 1e15) + "f"; + if (va < 1e-9) + return noCommaFormat.format(v * 1e12) + "p"; + if (va < 1e-6) + return noCommaFormat.format(v * 1e9) + "n"; + if (va < 1e-3) + return noCommaFormat.format(v * 1e6) + "u"; + if (va < 1 /* && !ei.forceLargeM */) + return noCommaFormat.format(v * 1e3) + "m"; + if (va < 1e3) + return noCommaFormat.format(v); + if (va < 1e6) + return noCommaFormat.format(v * 1e-3) + "k"; + if (va < 1e9) + return noCommaFormat.format(v * 1e-6) + "M"; + return noCommaFormat.format(v * 1e-9) + "G"; + } - case 'k': case 'K': mult = 1e3; break; - case 'M': mult = 1e6; break; - case 'G': case 'g': mult = 1e9; break; - } - if (mult != 1) - s = s.substring(0, len-1).trim(); - return noCommaFormat.parse(s) * mult * rmsMult; + double parseUnits(EditInfo ei) throws java.text.ParseException { + String s = ei.textf.getText(); + return parseUnits(s); + } + + static double parseUnits(String s) throws java.text.ParseException { + s = s.trim(); + double rmsMult = 1; + if (s.endsWith("rms")) { + s = s.substring(0, s.length() - 3).trim(); + rmsMult = ROOT2; } + // rewrite shorthand (eg "2k2") in to normal format (eg 2.2k) using regex + s = s.replaceAll("([0-9]+)([pPnNuUmMkKgG])([0-9]+)", "$1.$3$2"); + // rewrite meg to M + s = s.replaceAll("[mM][eE][gG]$", "M"); + int len = s.length(); + char uc = s.charAt(len - 1); + double mult = 1; + switch (uc) { + case 'f': + case 'F': + mult = 1e-15; + break; + case 'p': + case 'P': + mult = 1e-12; + break; + case 'n': + case 'N': + mult = 1e-9; + break; + case 'u': + case 'U': + mult = 1e-6; + break; - void apply() { - int i; - for (i = 0; i != einfocount; i++) { - EditInfo ei = einfos[i]; - if (ei.textf!=null && ei.text==null) { - try { - double d = parseUnits(ei); - ei.value = d; - } catch (Exception ex) { /* ignored */ } - } - if (ei.button != null) - continue; - elm.setEditValue(i, ei); - - // update slider if any - if (elm instanceof CircuitElm) { - Adjustable adj = cframe.findAdjustable((CircuitElm)elm, i); - if (adj != null) - adj.setSliderValue(ei.value); - } - } - cframe.needAnalyze(); + // for ohm values, we used to assume mega for lowercase m, otherwise milli + case 'm': + mult = /* (ei.forceLargeM) ? 1e6 : */ 1e-3; + break; + + case 'k': + case 'K': + mult = 1e3; + break; + case 'M': + mult = 1e6; + break; + case 'G': + case 'g': + mult = 1e9; + break; } + if (mult != 1) + s = s.substring(0, len - 1).trim(); + return noCommaFormat.parse(s) * mult * rmsMult; + } - public void itemStateChanged(GwtEvent e) { - Object src = e.getSource(); - int i; - boolean changed = false; - boolean applied = false; - for (i = 0; i != einfocount; i++) { - EditInfo ei = einfos[i]; - if (ei.choice == src || ei.checkbox == src || ei.button == src) { - - // if we're pressing a button, make sure to apply changes first - if (ei.button == src && !ei.newDialog) { - apply(); - applied = true; - } - - elm.setEditValue(i, ei); - if (ei.newDialog) - changed = true; - cframe.needAnalyze(); - } + void apply() { + int i; + for (i = 0; i != einfocount; i++) { + EditInfo ei = einfos[i]; + if (ei.textf != null && ei.text == null) { + try { + double d = parseUnits(ei); + ei.value = d; + } catch (Exception ex) { + /* ignored */ } + } + if (ei.button != null) + continue; + elm.setEditValue(i, ei); + + // update slider if any + if (elm instanceof CircuitElm) { + Adjustable adj = cframe.findAdjustable((CircuitElm) elm, i); + if (adj != null) + adj.setSliderValue(ei.value); } - if (changed) { - // apply changes before we reset everything - // (need to check if we already applied changes; otherwise Diode create simple model button doesn't work) - if (!applied) + } + cframe.needAnalyze(); + } + + public void itemStateChanged(GwtEvent e) { + Object src = e.getSource(); + int i; + boolean changed = false; + boolean applied = false; + for (i = 0; i != einfocount; i++) { + EditInfo ei = einfos[i]; + if (ei.choice == src || ei.checkbox == src || ei.button == src) { + + // if we're pressing a button, make sure to apply changes first + if (ei.button == src && !ei.newDialog) { apply(); - - clearDialog(); - buildDialog(); + applied = true; + } + + elm.setEditValue(i, ei); + if (ei.newDialog) + changed = true; + cframe.needAnalyze(); } } - - public void resetDialog() { + if (changed) { + // apply changes before we reset everything + // (need to check if we already applied changes; otherwise Diode create simple + // model button doesn't work) + if (!applied) + apply(); + clearDialog(); buildDialog(); } - - public void clearDialog() { - while (vp.getWidget(0)!=hp) - vp.remove(0); - } - - public void closeDialog() - { - super.closeDialog(); - if (CirSim.editDialog == this) - CirSim.editDialog = null; - if (CirSim.customLogicEditDialog == this) - CirSim.customLogicEditDialog = null; - } -} + } + + public void resetDialog() { + clearDialog(); + buildDialog(); + } + public void clearDialog() { + while (vp.getWidget(0) != hp) + vp.remove(0); + } + + public void closeDialog() { + super.closeDialog(); + if (CirSim.editDialog == this) + CirSim.editDialog = null; + if (CirSim.customLogicEditDialog == this) + CirSim.customLogicEditDialog = null; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/EditDialogLoadFile.java b/src/com/lushprojects/circuitjs1/client/EditDialogLoadFile.java index 8822a703..c8e0a7fc 100644 --- a/src/com/lushprojects/circuitjs1/client/EditDialogLoadFile.java +++ b/src/com/lushprojects/circuitjs1/client/EditDialogLoadFile.java @@ -28,31 +28,33 @@ /* * An abstract class for circuitjs which allows components to prompt for files from the user. */ -public abstract class EditDialogLoadFile extends FileUpload implements ChangeHandler { - - static public final boolean isSupported() { return LoadFile.isSupported(); } - - static public void doErrorCallback(String msg) { - Window.alert(Locale.LS(msg)); - } - - EditDialogLoadFile() { - super(); - this.setName(Locale.LS("Load File")); - this.getElement().setId("EditDialogLoadFileElement"); - this.addChangeHandler(this); - this.addStyleName("offScreen"); - this.setPixelSize(0, 0); - } - - public void onChange(ChangeEvent e) { - handle(); - } - - public final native void open() - /*-{ - $doc.getElementById("EditDialogLoadFileElement").click(); - }-*/; - - public abstract void handle(); +public abstract class EditDialogLoadFile extends FileUpload implements ChangeHandler { + + static public final boolean isSupported() { + return LoadFile.isSupported(); + } + + static public void doErrorCallback(String msg) { + Window.alert(Locale.LS(msg)); + } + + EditDialogLoadFile() { + super(); + this.setName(Locale.LS("Load File")); + this.getElement().setId("EditDialogLoadFileElement"); + this.addChangeHandler(this); + this.addStyleName("offScreen"); + this.setPixelSize(0, 0); + } + + public void onChange(ChangeEvent e) { + handle(); + } + + public final native void open() + /*-{ + $doc.getElementById("EditDialogLoadFileElement").click(); + }-*/; + + public abstract void handle(); } diff --git a/src/com/lushprojects/circuitjs1/client/EditDiodeModelDialog.java b/src/com/lushprojects/circuitjs1/client/EditDiodeModelDialog.java index a6ec08c7..75e474a5 100644 --- a/src/com/lushprojects/circuitjs1/client/EditDiodeModelDialog.java +++ b/src/com/lushprojects/circuitjs1/client/EditDiodeModelDialog.java @@ -4,7 +4,7 @@ public class EditDiodeModelDialog extends EditDialog { DiodeModel model; DiodeElm diodeElm; - + public EditDiodeModelDialog(DiodeModel dm, CirSim f, DiodeElm de) { super(dm, f); model = dm; @@ -19,13 +19,13 @@ void apply() { if (diodeElm != null) diodeElm.newModelCreated(model); } - + public void closeDialog() { super.closeDialog(); EditDialog edlg = CirSim.editDialog; CirSim.console("resetting dialog " + edlg); if (edlg != null) - edlg.resetDialog(); + edlg.resetDialog(); CirSim.diodeModelEditDialog = null; } } diff --git a/src/com/lushprojects/circuitjs1/client/EditInfo.java b/src/com/lushprojects/circuitjs1/client/EditInfo.java index 77fec216..d62692d3 100644 --- a/src/com/lushprojects/circuitjs1/client/EditInfo.java +++ b/src/com/lushprojects/circuitjs1/client/EditInfo.java @@ -18,6 +18,7 @@ */ package com.lushprojects.circuitjs1.client; + import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; import com.lushprojects.circuitjs1.client.util.Locale; @@ -25,63 +26,70 @@ import com.google.gwt.user.client.ui.TextArea; class EditInfo { - - EditInfo(String n, double val, double mn, double mx) { - name = n; - value = val; - dimensionless = false; - minVal = mn; - maxVal = mx; - } - - EditInfo(String n, double val) { - name = n; - value = val; - dimensionless = false; - } - - EditInfo(String n, String txt) { - name = n; - text = txt; - } - - static EditInfo createCheckbox(String name, boolean flag) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox(name, flag); - return ei; - } - - EditInfo setDimensionless() { dimensionless = true; return this; } - EditInfo disallowSliders() { noSliders = true; return this; } - int changeFlag(int flags, int bit) { - if (checkbox.getState()) - return flags | bit; - return flags & ~bit; - } - - String name, text; - double value; - TextBox textf; - Choice choice; - Checkbox checkbox; - Button button; - EditDialogLoadFile loadFile = null; //if non-null, the button will open a file dialog - TextArea textArea; - Widget widget; - boolean newDialog; - boolean dimensionless; - boolean noSliders; - double minVal, maxVal; - - // for slider dialog - TextBox minBox, maxBox, labelBox; - - boolean canCreateAdjustable() { - return choice == null && checkbox == null && button == null && textArea == null && - widget == null && !noSliders; - } - - static String makeLink(String file, String text) { - return "" + Locale.LS(text) + ""; - } + + EditInfo(String n, double val, double mn, double mx) { + name = n; + value = val; + dimensionless = false; + minVal = mn; + maxVal = mx; + } + + EditInfo(String n, double val) { + name = n; + value = val; + dimensionless = false; + } + + EditInfo(String n, String txt) { + name = n; + text = txt; + } + + static EditInfo createCheckbox(String name, boolean flag) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox(name, flag); + return ei; + } + + EditInfo setDimensionless() { + dimensionless = true; + return this; + } + + EditInfo disallowSliders() { + noSliders = true; + return this; + } + + int changeFlag(int flags, int bit) { + if (checkbox.getState()) + return flags | bit; + return flags & ~bit; + } + + String name, text; + double value; + TextBox textf; + Choice choice; + Checkbox checkbox; + Button button; + EditDialogLoadFile loadFile = null; // if non-null, the button will open a file dialog + TextArea textArea; + Widget widget; + boolean newDialog; + boolean dimensionless; + boolean noSliders; + double minVal, maxVal; + + // for slider dialog + TextBox minBox, maxBox, labelBox; + + boolean canCreateAdjustable() { + return choice == null && checkbox == null && button == null && textArea == null && widget == null && !noSliders; + } + + static String makeLink(String file, String text) { + return "" + Locale.LS(text) + ""; + } } diff --git a/src/com/lushprojects/circuitjs1/client/EditOptions.java b/src/com/lushprojects/circuitjs1/client/EditOptions.java index 0194359e..665d07a3 100644 --- a/src/com/lushprojects/circuitjs1/client/EditOptions.java +++ b/src/com/lushprojects/circuitjs1/client/EditOptions.java @@ -24,144 +24,172 @@ import com.lushprojects.circuitjs1.client.util.Locale; class EditOptions implements Editable { - CirSim sim; - - public EditOptions(CirSim s) { sim = s; } - - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Time step size (s)", sim.maxTimeStep, 0, 0); - if (n == 1) - return new EditInfo("Range for voltage color (V)", - CircuitElm.voltageRange, 0, 0); - if (n == 2) { - EditInfo ei = new EditInfo("Change Language", 0, -1, -1); - ei.choice = new Choice(); - ei.choice.add("(no change)"); - ei.choice.add("ÄŒeÅ¡tina"); - ei.choice.add("Dansk"); - ei.choice.add("Deutsch"); - ei.choice.add("English"); - ei.choice.add("Español"); - ei.choice.add("Français"); - ei.choice.add("Italiano"); - ei.choice.add("Norsk bokmÃ¥l"); - ei.choice.add("Polski"); - ei.choice.add("Português"); - ei.choice.add("\u0420\u0443\u0441\u0441\u043a\u0438\u0439"); // Russian - ei.choice.add("\u4e2d\u6587 (\u4e2d\u56fd\u5927\u9646)"); // Chinese - ei.choice.add("\u4e2d\u6587 (\u53f0\u6e7e)"); // Chinese (tw) - return ei; - } - - if (n == 3) - return new EditInfo("Positive Color", CircuitElm.positiveColor.getHexValue()); - if (n == 4) - return new EditInfo("Negative Color", CircuitElm.negativeColor.getHexValue()); - if (n == 5) - return new EditInfo("Neutral Color", CircuitElm.neutralColor.getHexValue()); - if (n == 6) - return new EditInfo("Selection Color", CircuitElm.selectColor.getHexValue()); - if (n == 7) - return new EditInfo("Current Color", CircuitElm.currentColor.getHexValue()); - if (n == 8) - return new EditInfo("# of Decimal Digits (short format)", CircuitElm.shortDecimalDigits); - if (n == 9) - return new EditInfo("# of Decimal Digits (long format)", CircuitElm.decimalDigits); - if (n == 10) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Developer Mode", sim.developerMode); - return ei; - } - if (n == 11) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Auto-Adjust Timestep", sim.adjustTimeStep); - return ei; - } - if (n == 12 && sim.adjustTimeStep) - return new EditInfo("Minimum time step size (s)", sim.minTimeStep, 0, 0); + CirSim sim; - return null; + public EditOptions(CirSim s) { + sim = s; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Time step size (s)", sim.maxTimeStep, 0, 0); + if (n == 1) + return new EditInfo("Range for voltage color (V)", CircuitElm.voltageRange, 0, 0); + if (n == 2) { + EditInfo ei = new EditInfo("Change Language", 0, -1, -1); + ei.choice = new Choice(); + ei.choice.add("(no change)"); + ei.choice.add("ÄŒeÅ¡tina"); + ei.choice.add("Dansk"); + ei.choice.add("Deutsch"); + ei.choice.add("English"); + ei.choice.add("Español"); + ei.choice.add("Français"); + ei.choice.add("Italiano"); + ei.choice.add("Norsk bokmÃ¥l"); + ei.choice.add("Polski"); + ei.choice.add("Português"); + ei.choice.add("\u0420\u0443\u0441\u0441\u043a\u0438\u0439"); // Russian + ei.choice.add("\u4e2d\u6587 (\u4e2d\u56fd\u5927\u9646)"); // Chinese + ei.choice.add("\u4e2d\u6587 (\u53f0\u6e7e)"); // Chinese (tw) + return ei; + } + + if (n == 3) + return new EditInfo("Positive Color", CircuitElm.positiveColor.getHexValue()); + if (n == 4) + return new EditInfo("Negative Color", CircuitElm.negativeColor.getHexValue()); + if (n == 5) + return new EditInfo("Neutral Color", CircuitElm.neutralColor.getHexValue()); + if (n == 6) + return new EditInfo("Selection Color", CircuitElm.selectColor.getHexValue()); + if (n == 7) + return new EditInfo("Current Color", CircuitElm.currentColor.getHexValue()); + if (n == 8) + return new EditInfo("# of Decimal Digits (short format)", CircuitElm.shortDecimalDigits); + if (n == 9) + return new EditInfo("# of Decimal Digits (long format)", CircuitElm.decimalDigits); + if (n == 10) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Developer Mode", sim.developerMode); + return ei; } - - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) { - sim.maxTimeStep = ei.value; + if (n == 11) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Auto-Adjust Timestep", sim.adjustTimeStep); + return ei; + } + if (n == 12 && sim.adjustTimeStep) + return new EditInfo("Minimum time step size (s)", sim.minTimeStep, 0, 0); + + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) { + sim.maxTimeStep = ei.value; - // if timestep changed manually, prompt before changing it again - AudioOutputElm.okToChangeTimeStep = false; - } - if (n == 1 && ei.value > 0) - CircuitElm.voltageRange = ei.value; - if (n == 2) { - int lang = ei.choice.getSelectedIndex(); - if (lang == 0) - return; - String langString = null; - switch (lang) { - // Czech is csx instead of cs because we are not ready to use it automatically yet - case 1: langString = "csx"; break; - case 2: langString = "da"; break; - case 3: langString = "de"; break; - case 4: langString = "en"; break; - case 5: langString = "es"; break; - case 6: langString = "fr"; break; - case 7: langString = "it"; break; - case 8: langString = "nb"; break; - case 9: langString = "pl"; break; - case 10: langString = "pt"; break; - case 11: langString = "ru"; break; - case 12: langString = "zh"; break; - case 13: langString = "zh-tw"; break; - } - if (langString == null) - return; - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) { - Window.alert(Locale.LS("Can't set language")); - return; - } - stor.setItem("language", langString); - if (Window.confirm(Locale.LS("Must restart to set language. Restart now?"))) - Window.Location.reload(); - } - if (n == 3) { - CircuitElm.positiveColor = setColor("positiveColor", ei, Color.green); - CircuitElm.setColorScale(); - } - if (n == 4) { - CircuitElm.negativeColor = setColor("negativeColor", ei, Color.red); - CircuitElm.setColorScale(); - } - if (n == 5) { - CircuitElm.neutralColor = setColor("neutralColor", ei, Color.gray); - CircuitElm.setColorScale(); - } - if (n == 6) - CircuitElm.selectColor = setColor("selectColor", ei, Color.cyan); - if (n == 7) - CircuitElm.currentColor = setColor("currentColor", ei, Color.yellow); - if (n == 8) - CircuitElm.setDecimalDigits((int)ei.value, true, true); - if (n == 9) - CircuitElm.setDecimalDigits((int)ei.value, false, true); - if (n == 10) - sim.developerMode = ei.checkbox.getState(); - if (n == 11) { - sim.adjustTimeStep = ei.checkbox.getState(); - ei.newDialog = true; - } - if (n == 12 && ei.value > 0) - sim.minTimeStep = ei.value; + // if timestep changed manually, prompt before changing it again + AudioOutputElm.okToChangeTimeStep = false; } - - Color setColor(String name, EditInfo ei, Color def) { - String val = ei.textf.getText(); - if (val.length() == 0) - val = def.getHexValue(); + if (n == 1 && ei.value > 0) + CircuitElm.voltageRange = ei.value; + if (n == 2) { + int lang = ei.choice.getSelectedIndex(); + if (lang == 0) + return; + String langString = null; + switch (lang) { + // Czech is csx instead of cs because we are not ready to use it automatically + // yet + case 1: + langString = "csx"; + break; + case 2: + langString = "da"; + break; + case 3: + langString = "de"; + break; + case 4: + langString = "en"; + break; + case 5: + langString = "es"; + break; + case 6: + langString = "fr"; + break; + case 7: + langString = "it"; + break; + case 8: + langString = "nb"; + break; + case 9: + langString = "pl"; + break; + case 10: + langString = "pt"; + break; + case 11: + langString = "ru"; + break; + case 12: + langString = "zh"; + break; + case 13: + langString = "zh-tw"; + break; + } + if (langString == null) + return; Storage stor = Storage.getLocalStorageIfSupported(); - if (stor != null) - stor.setItem(name, val); - return new Color(val); + if (stor == null) { + Window.alert(Locale.LS("Can't set language")); + return; + } + stor.setItem("language", langString); + if (Window.confirm(Locale.LS("Must restart to set language. Restart now?"))) + Window.Location.reload(); } + if (n == 3) { + CircuitElm.positiveColor = setColor("positiveColor", ei, Color.green); + CircuitElm.setColorScale(); + } + if (n == 4) { + CircuitElm.negativeColor = setColor("negativeColor", ei, Color.red); + CircuitElm.setColorScale(); + } + if (n == 5) { + CircuitElm.neutralColor = setColor("neutralColor", ei, Color.gray); + CircuitElm.setColorScale(); + } + if (n == 6) + CircuitElm.selectColor = setColor("selectColor", ei, Color.cyan); + if (n == 7) + CircuitElm.currentColor = setColor("currentColor", ei, Color.yellow); + if (n == 8) + CircuitElm.setDecimalDigits((int) ei.value, true, true); + if (n == 9) + CircuitElm.setDecimalDigits((int) ei.value, false, true); + if (n == 10) + sim.developerMode = ei.checkbox.getState(); + if (n == 11) { + sim.adjustTimeStep = ei.checkbox.getState(); + ei.newDialog = true; + } + if (n == 12 && ei.value > 0) + sim.minTimeStep = ei.value; + } + + Color setColor(String name, EditInfo ei, Color def) { + String val = ei.textf.getText(); + if (val.length() == 0) + val = def.getHexValue(); + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor != null) + stor.setItem(name, val); + return new Color(val); + } }; diff --git a/src/com/lushprojects/circuitjs1/client/EditTransistorModelDialog.java b/src/com/lushprojects/circuitjs1/client/EditTransistorModelDialog.java index ef732ef1..367e06b2 100644 --- a/src/com/lushprojects/circuitjs1/client/EditTransistorModelDialog.java +++ b/src/com/lushprojects/circuitjs1/client/EditTransistorModelDialog.java @@ -4,28 +4,28 @@ public class EditTransistorModelDialog extends EditDialog { TransistorModel model; TransistorElm transistorElm; - + public EditTransistorModelDialog(TransistorModel dm, CirSim f, TransistorElm te) { super(dm, f); model = dm; - transistorElm = te; + transistorElm = te; applyButton.removeFromParent(); } void apply() { super.apply(); -// if (model.name == null || model.name.length() == 0) -// model.pickName(); + // if (model.name == null || model.name.length() == 0) + // model.pickName(); if (transistorElm != null) transistorElm.newModelCreated(model); } - + public void closeDialog() { super.closeDialog(); EditDialog edlg = CirSim.editDialog; CirSim.console("resetting dialog " + edlg); if (edlg != null) - edlg.resetDialog(); + edlg.resetDialog(); CirSim.diodeModelEditDialog = null; } } diff --git a/src/com/lushprojects/circuitjs1/client/ExportAsImageDialog.java b/src/com/lushprojects/circuitjs1/client/ExportAsImageDialog.java index 44950192..cea45051 100644 --- a/src/com/lushprojects/circuitjs1/client/ExportAsImageDialog.java +++ b/src/com/lushprojects/circuitjs1/client/ExportAsImageDialog.java @@ -30,43 +30,43 @@ import com.google.gwt.i18n.client.DateTimeFormat; public class ExportAsImageDialog extends Dialog { - - VerticalPanel vp; - - private static native String b64encode(String a) /*-{ + + VerticalPanel vp; + + private static native String b64encode(String a) /*-{ // string may have unicode text strings in it, so we don't just call btoa() return window.btoa(unescape(encodeURIComponent(a))); }-*/; - public ExportAsImageDialog(int type) { - super(); - Button okButton; - Anchor a; - vp=new VerticalPanel(); - setWidget(vp); - setText(Locale.LS("Export as Image")); - vp.add(new Label(Locale.LS("Click on the link below to save your image"))); - Date date = new Date(); - DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); - String dataURL; - String ext = ".png"; - if (type == CirSim.CAC_IMAGE) { - dataURL = CirSim.theSim.getCircuitAsCanvas(type).toDataUrl(); - } else { - String data = CirSim.theSim.getCircuitAsSVG(); - dataURL = "data:text/plain;base64," + b64encode(data); - ext = ".svg"; - } - a=new Anchor("image" + ext, dataURL); - String fname = "circuit-"+ dtf.format(date) + ext; - a.getElement().setAttribute("Download", fname); - vp.add(a); - vp.add(okButton = new Button(Locale.LS("OK"))); - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - closeDialog(); - } - }); - this.center(); + public ExportAsImageDialog(int type) { + super(); + Button okButton; + Anchor a; + vp = new VerticalPanel(); + setWidget(vp); + setText(Locale.LS("Export as Image")); + vp.add(new Label(Locale.LS("Click on the link below to save your image"))); + Date date = new Date(); + DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); + String dataURL; + String ext = ".png"; + if (type == CirSim.CAC_IMAGE) { + dataURL = CirSim.theSim.getCircuitAsCanvas(type).toDataUrl(); + } else { + String data = CirSim.theSim.getCircuitAsSVG(); + dataURL = "data:text/plain;base64," + b64encode(data); + ext = ".svg"; } + a = new Anchor("image" + ext, dataURL); + String fname = "circuit-" + dtf.format(date) + ext; + a.getElement().setAttribute("Download", fname); + vp.add(a); + vp.add(okButton = new Button(Locale.LS("OK"))); + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); + this.center(); + } } diff --git a/src/com/lushprojects/circuitjs1/client/ExportAsLocalFileDialog.java b/src/com/lushprojects/circuitjs1/client/ExportAsLocalFileDialog.java index 2d0653f0..975641c6 100644 --- a/src/com/lushprojects/circuitjs1/client/ExportAsLocalFileDialog.java +++ b/src/com/lushprojects/circuitjs1/client/ExportAsLocalFileDialog.java @@ -36,103 +36,103 @@ import com.google.gwt.i18n.client.DateTimeFormat; public class ExportAsLocalFileDialog extends Dialog implements ValueChangeHandler { - - VerticalPanel vp; - - static public final native boolean downloadIsSupported() - /*-{ - return !!(("download" in $doc.createElement("a"))); - }-*/; - - static public final native String getBlobUrl(String data) - /*-{ - var datain=[""]; - datain[0]=data; - var oldblob = $doc.exportBlob; - if (oldblob) - URL.revokeObjectURL(oldblob); - var blob=new Blob(datain, {type: 'text/plain' } ); - var url = URL.createObjectURL(blob); - $doc.exportBlob = url; - return url; - }-*/; - - TextBox textBox; - static String lastFileName; - String url; - - public static void setLastFileName(String s) { - // remember filename for use when saving a new file. - // if s is null or automatically generated then just clear out old filename. - if (s == null || (s.startsWith("circuit-") && s.contains(".circuitjs"))) - lastFileName = null; - else - lastFileName = s; - } - public ExportAsLocalFileDialog(String data) { - super(); - Button okButton, cancelButton; - vp=new VerticalPanel(); - setWidget(vp); - setText(Locale.LS("Export as Local File")); - vp.add(new Label(Locale.LS("File name:"))); - textBox = new TextBox(); - textBox.addValueChangeHandler(this); - textBox.setWidth("250px"); // "90%"); - vp.add(textBox); - url=getBlobUrl(data); - Date date = new Date(); - String fname; - if (lastFileName != null) - fname = lastFileName; - else { - DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); - fname = "circuit-"+ dtf.format(date) + ".circuitjs.txt"; - } - textBox.setText(fname); - - HorizontalPanel hp = new HorizontalPanel(); - hp.setWidth("100%"); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); - hp.setStyleName("topSpace"); - vp.add(hp); - hp.add(okButton = new Button(Locale.LS("OK"))); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); - hp.add(cancelButton = new Button(Locale.LS("Cancel"))); - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - apply(); - closeDialog(); - } - }); - cancelButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - closeDialog(); - } - }); - this.center(); + VerticalPanel vp; + + static public final native boolean downloadIsSupported() + /*-{ + return !!(("download" in $doc.createElement("a"))); + }-*/; + + static public final native String getBlobUrl(String data) + /*-{ + var datain=[""]; + datain[0]=data; + var oldblob = $doc.exportBlob; + if (oldblob) + URL.revokeObjectURL(oldblob); + var blob=new Blob(datain, {type: 'text/plain' } ); + var url = URL.createObjectURL(blob); + $doc.exportBlob = url; + return url; + }-*/; + + TextBox textBox; + static String lastFileName; + String url; + + public static void setLastFileName(String s) { + // remember filename for use when saving a new file. + // if s is null or automatically generated then just clear out old filename. + if (s == null || (s.startsWith("circuit-") && s.contains(".circuitjs"))) + lastFileName = null; + else + lastFileName = s; + } + + public ExportAsLocalFileDialog(String data) { + super(); + Button okButton, cancelButton; + vp = new VerticalPanel(); + setWidget(vp); + setText(Locale.LS("Export as Local File")); + vp.add(new Label(Locale.LS("File name:"))); + textBox = new TextBox(); + textBox.addValueChangeHandler(this); + textBox.setWidth("250px"); // "90%"); + vp.add(textBox); + url = getBlobUrl(data); + Date date = new Date(); + String fname; + if (lastFileName != null) + fname = lastFileName; + else { + DateTimeFormat dtf = DateTimeFormat.getFormat("yyyyMMdd-HHmm"); + fname = "circuit-" + dtf.format(date) + ".circuitjs.txt"; } - - static native void click(Element elem) /*-{ + textBox.setText(fname); + + HorizontalPanel hp = new HorizontalPanel(); + hp.setWidth("100%"); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); + hp.setStyleName("topSpace"); + vp.add(hp); + hp.add(okButton = new Button(Locale.LS("OK"))); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + hp.add(cancelButton = new Button(Locale.LS("Cancel"))); + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + apply(); + closeDialog(); + } + }); + cancelButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); + this.center(); + } + + static native void click(Element elem) /*-{ elem.click(); }-*/; - - void apply() { - String fname = textBox.getText(); - if (!fname.contains(".")) - fname += ".txt"; - Anchor a = new Anchor(fname, url); - a.getElement().setAttribute("Download", fname); - vp.add(a); - click(a.getElement()); - } - - public void onValueChange(ValueChangeEvent event) { - // update filename - String fname = textBox.getText(); - if (fname.length() == 0) - return; - lastFileName = fname; - } + + void apply() { + String fname = textBox.getText(); + if (!fname.contains(".")) + fname += ".txt"; + Anchor a = new Anchor(fname, url); + a.getElement().setAttribute("Download", fname); + vp.add(a); + click(a.getElement()); + } + + public void onValueChange(ValueChangeEvent event) { + // update filename + String fname = textBox.getText(); + if (fname.length() == 0) + return; + lastFileName = fname; + } } diff --git a/src/com/lushprojects/circuitjs1/client/ExportAsTextDialog.java b/src/com/lushprojects/circuitjs1/client/ExportAsTextDialog.java index 36300980..76f8a6b1 100644 --- a/src/com/lushprojects/circuitjs1/client/ExportAsTextDialog.java +++ b/src/com/lushprojects/circuitjs1/client/ExportAsTextDialog.java @@ -31,75 +31,78 @@ import com.google.gwt.safehtml.shared.SafeHtml; public class ExportAsTextDialog extends Dialog { - - VerticalPanel vp; - CirSim sim; - TextArea textArea; - - public ExportAsTextDialog(CirSim asim, String s) { - super(); - closeOnEnter = false; - sim = asim; - // RichTextArea tb; - TextArea ta; - Button okButton, importButton, copyButton; - Label la2; - SafeHtml html; - vp=new VerticalPanel(); - setWidget(vp); - setText(Locale.LS("Export as Text")); - vp.add(new Label(Locale.LS("Text file for this circuit is..."))); -// vp.add(tb = new RichTextArea()); -// html=SafeHtmlUtils.fromString(s); -// html=SafeHtmlUtils.fromTrustedString(html.asString().replace("\n", "
")); -// tb.setHTML(html); - vp.add(ta= new TextArea()); - ta.setWidth("400px"); - ta.setHeight("300px"); - ta.setText(s); - textArea = ta; - // vp.add(la2 = new Label(sim.LS("To save this file select it all (eg click in text and type control-A) and copy to your clipboard (eg control-C) before pasting to an empty text file (eg on Windows Notepad) and saving as a new file."), true)); - // la2.setWidth("300px"); - HorizontalPanel hp = new HorizontalPanel(); - hp.setWidth("100%"); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); - hp.setStyleName("topSpace"); - vp.add(hp); - hp.add(okButton = new Button(Locale.LS("OK"))); - hp.add(copyButton = new Button(Locale.LS("Copy to Clipboard"))); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); - hp.add(importButton = new Button(Locale.LS("Re-Import"))); - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - closeDialog(); - } - }); - importButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - String s; - sim.pushUndo(); - closeDialog(); -// s=textBox.getHTML(); -// s=s.replace("
", "\r"); - s=textArea.getText(); - if (s!=null) { - sim.readCircuit(s); - sim.allowSave(false); - } - } - }); - copyButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - textArea.setFocus(true); - textArea.selectAll(); - copyToClipboard(); - textArea.setSelectionRange(0,0); - } - }); - this.center(); - } - - private static native boolean copyToClipboard() /*-{ + + VerticalPanel vp; + CirSim sim; + TextArea textArea; + + public ExportAsTextDialog(CirSim asim, String s) { + super(); + closeOnEnter = false; + sim = asim; + // RichTextArea tb; + TextArea ta; + Button okButton, importButton, copyButton; + Label la2; + SafeHtml html; + vp = new VerticalPanel(); + setWidget(vp); + setText(Locale.LS("Export as Text")); + vp.add(new Label(Locale.LS("Text file for this circuit is..."))); + // vp.add(tb = new RichTextArea()); + // html=SafeHtmlUtils.fromString(s); + // html=SafeHtmlUtils.fromTrustedString(html.asString().replace("\n", "
")); + // tb.setHTML(html); + vp.add(ta = new TextArea()); + ta.setWidth("400px"); + ta.setHeight("300px"); + ta.setText(s); + textArea = ta; + // vp.add(la2 = new Label(sim.LS("To save this file select it all (eg click in + // text and type control-A) and copy to your clipboard (eg control-C) before + // pasting to an empty text file (eg on Windows Notepad) and saving as a new + // file."), true)); + // la2.setWidth("300px"); + HorizontalPanel hp = new HorizontalPanel(); + hp.setWidth("100%"); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); + hp.setStyleName("topSpace"); + vp.add(hp); + hp.add(okButton = new Button(Locale.LS("OK"))); + hp.add(copyButton = new Button(Locale.LS("Copy to Clipboard"))); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + hp.add(importButton = new Button(Locale.LS("Re-Import"))); + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); + importButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + String s; + sim.pushUndo(); + closeDialog(); + // s=textBox.getHTML(); + // s=s.replace("
", "\r"); + s = textArea.getText(); + if (s != null) { + sim.readCircuit(s); + sim.allowSave(false); + } + } + }); + copyButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + textArea.setFocus(true); + textArea.selectAll(); + copyToClipboard(); + textArea.setSelectionRange(0, 0); + } + }); + this.center(); + } + + private static native boolean copyToClipboard() /*-{ return $doc.execCommand('copy'); }-*/; diff --git a/src/com/lushprojects/circuitjs1/client/ExportAsUrlDialog.java b/src/com/lushprojects/circuitjs1/client/ExportAsUrlDialog.java index 5996cb24..78cc4257 100644 --- a/src/com/lushprojects/circuitjs1/client/ExportAsUrlDialog.java +++ b/src/com/lushprojects/circuitjs1/client/ExportAsUrlDialog.java @@ -38,120 +38,121 @@ import com.google.gwt.http.client.Request; public class ExportAsUrlDialog extends Dialog { - - VerticalPanel vp; - Button shortButton; - static TextArea textArea; - String requrl; - - public boolean shortIsSupported() { - return circuitjs1.shortRelaySupported; - } - -// static public final native boolean bitlyIsSupported() -// /*-{ -// return !!($wnd.bitlytoken !==undefined && $wnd.bitlytoken !==null); -// }-*/; -// - - - static public void createShort(String urlin) - { - String url; - url = "shortrelay.php"+"?v="+urlin; - textArea.setText("Waiting for short URL for web service..."); - RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); - try { - requestBuilder.sendRequest(null, new RequestCallback() { - public void onError(Request request, Throwable exception) { - GWT.log("File Error Response", exception); - } - - public void onResponseReceived(Request request, Response response) { - // processing goes here - if (response.getStatusCode()==Response.SC_OK) { - String text = response.getText(); - textArea.setText(text); - // end or processing - } - else { - String text="Shortner error:"+response.getStatusText(); - textArea.setText(text); - GWT.log(text ); - } - } - }); - } catch (RequestException e) { - GWT.log("failed file reading", e); + + VerticalPanel vp; + Button shortButton; + static TextArea textArea; + String requrl; + + public boolean shortIsSupported() { + return circuitjs1.shortRelaySupported; + } + + // static public final native boolean bitlyIsSupported() + // /*-{ + // return !!($wnd.bitlytoken !==undefined && $wnd.bitlytoken !==null); + // }-*/; + // + + static public void createShort(String urlin) { + String url; + url = "shortrelay.php" + "?v=" + urlin; + textArea.setText("Waiting for short URL for web service..."); + RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); + try { + requestBuilder.sendRequest(null, new RequestCallback() { + public void onError(Request request, Throwable exception) { + GWT.log("File Error Response", exception); } + + public void onResponseReceived(Request request, Response response) { + // processing goes here + if (response.getStatusCode() == Response.SC_OK) { + String text = response.getText(); + textArea.setText(text); + // end or processing + } else { + String text = "Shortner error:" + response.getStatusText(); + textArea.setText(text); + GWT.log(text); + } + } + }); + } catch (RequestException e) { + GWT.log("failed file reading", e); + } } - - native String compress(String dump) /*-{ + + native String compress(String dump) /*-{ return $wnd.LZString.compressToEncodedURIComponent(dump); }-*/; - - public ExportAsUrlDialog( String dump) { - super(); - closeOnEnter = false; - String start[] = Location.getHref().split("\\?"); - String query="?ctz=" + compress(dump); - dump = start[0] + query; - requrl = URL.encodeQueryString(query); - Button okButton, copyButton; - - Label la1, la2; - vp=new VerticalPanel(); - setWidget(vp); - setText(Locale.LS("Export as URL")); - vp.add(new Label(Locale.LS("URL for this circuit is..."))); - if (dump.length()>2000) { - vp.add( la1= new Label(Locale.LS("Warning: this URL is longer than 2000 characters and may not work in some browsers."), true)); - la1.setWidth("300px"); - } - vp.add(textArea = new TextArea()); - textArea.setWidth("400px"); - textArea.setHeight("300px"); - textArea.setText(dump); -// tb.setMaxLength(s.length()); -// tb.setVisibleLength(s.length()); -// vp.add(la2 = new Label(CirSim.LS("To save this URL select it all (eg click in text and type control-A) and copy to your clipboard (eg control-C) before pasting to a suitable place."), true)); -// la2.setWidth("300px"); - - HorizontalPanel hp = new HorizontalPanel(); - hp.setWidth("100%"); - hp.setStyleName("topSpace"); - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); - hp.add(okButton = new Button(Locale.LS("OK"))); - hp.add(copyButton = new Button(Locale.LS("Copy to Clipboard"))); - vp.add(hp); - if (shortIsSupported()) { - hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); - - hp.add(shortButton = new Button(Locale.LS("Create short URL"))); - shortButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - shortButton.setVisible(false); - createShort(requrl); - } - }); + + public ExportAsUrlDialog(String dump) { + super(); + closeOnEnter = false; + String start[] = Location.getHref().split("\\?"); + String query = "?ctz=" + compress(dump); + dump = start[0] + query; + requrl = URL.encodeQueryString(query); + Button okButton, copyButton; + + Label la1, la2; + vp = new VerticalPanel(); + setWidget(vp); + setText(Locale.LS("Export as URL")); + vp.add(new Label(Locale.LS("URL for this circuit is..."))); + if (dump.length() > 2000) { + vp.add(la1 = new Label( + Locale.LS("Warning: this URL is longer than 2000 characters and may not work in some browsers."), + true)); + la1.setWidth("300px"); + } + vp.add(textArea = new TextArea()); + textArea.setWidth("400px"); + textArea.setHeight("300px"); + textArea.setText(dump); + // tb.setMaxLength(s.length()); + // tb.setVisibleLength(s.length()); + // vp.add(la2 = new Label(CirSim.LS("To save this URL select it all (eg click in + // text and type control-A) and copy to your clipboard (eg control-C) before + // pasting to a suitable place."), true)); + // la2.setWidth("300px"); + + HorizontalPanel hp = new HorizontalPanel(); + hp.setWidth("100%"); + hp.setStyleName("topSpace"); + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT); + hp.add(okButton = new Button(Locale.LS("OK"))); + hp.add(copyButton = new Button(Locale.LS("Copy to Clipboard"))); + vp.add(hp); + if (shortIsSupported()) { + hp.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + + hp.add(shortButton = new Button(Locale.LS("Create short URL"))); + shortButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + shortButton.setVisible(false); + createShort(requrl); } - okButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - closeDialog(); - } - }); - copyButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - textArea.setFocus(true); - textArea.selectAll(); - copyToClipboard(); - textArea.setSelectionRange(0,0); - } - }); - this.center(); + }); } - - private static native boolean copyToClipboard() /*-{ + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); + copyButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + textArea.setFocus(true); + textArea.selectAll(); + copyToClipboard(); + textArea.setSelectionRange(0, 0); + } + }); + this.center(); + } + + private static native boolean copyToClipboard() /*-{ return $doc.execCommand('copy'); }-*/; diff --git a/src/com/lushprojects/circuitjs1/client/Expr.java b/src/com/lushprojects/circuitjs1/client/Expr.java index dc38d0cc..0a06b7ea 100644 --- a/src/com/lushprojects/circuitjs1/client/Expr.java +++ b/src/com/lushprojects/circuitjs1/client/Expr.java @@ -3,25 +3,26 @@ import java.util.Vector; class ExprState { - //int n; + // int n; double values[]; double lastValues[]; double lastOutput; double t; + ExprState(int xx) { - //n = xx; + // n = xx; values = new double[9]; lastValues = new double[9]; values[4] = Math.E; } - + void updateLastValues(double lastOut) { lastOutput = lastOut; int i; for (i = 0; i != values.length; i++) lastValues[i] = values[i]; } - + void reset() { for (int i = 0; i != values.length; i++) lastValues[i] = 0; @@ -37,13 +38,16 @@ class Expr { children.add(e2); type = v; } + Expr(int v, double vv) { type = v; value = vv; } + Expr(int v) { type = v; } + double eval(ExprState es) { Expr left = null; Expr right = null; @@ -53,57 +57,90 @@ class Expr { right = children.lastElement(); } switch (type) { - case E_ADD: return left.eval(es)+right.eval(es); - case E_SUB: return left.eval(es)-right.eval(es); - case E_MUL: return left.eval(es)*right.eval(es); - case E_DIV: return left.eval(es)/right.eval(es); - case E_POW: return Math.pow(left.eval(es), right.eval(es)); - case E_OR: return (left.eval(es) != 0 || right.eval(es) != 0) ? 1 : 0; - case E_AND: return (left.eval(es) != 0 && right.eval(es) != 0) ? 1 : 0; - case E_EQUALS: return (left.eval(es) == right.eval(es)) ? 1 : 0; - case E_NEQ: return (left.eval(es) != right.eval(es)) ? 1 : 0; - case E_LEQ: return (left.eval(es) <= right.eval(es)) ? 1 : 0; - case E_GEQ: return (left.eval(es) >= right.eval(es)) ? 1 : 0; - case E_LESS: return (left.eval(es) < right.eval(es)) ? 1 : 0; - case E_GREATER: return (left.eval(es) > right.eval(es)) ? 1 : 0; - case E_TERNARY: return children.get(left.eval(es) != 0 ? 1 : 2).eval(es); - case E_UMINUS: return -left.eval(es); - case E_NOT: return left.eval(es) == 0 ? 1 : 0; - case E_VAL: return value; - case E_T: return es.t; - case E_SIN: return Math.sin(left.eval(es)); - case E_COS: return Math.cos(left.eval(es)); - case E_ABS: return Math.abs(left.eval(es)); - case E_EXP: return Math.exp(left.eval(es)); - case E_LOG: return Math.log(left.eval(es)); - case E_SQRT: return Math.sqrt(left.eval(es)); - case E_TAN: return Math.tan(left.eval(es)); - case E_ASIN: return Math.asin(left.eval(es)); - case E_ACOS: return Math.acos(left.eval(es)); - case E_ATAN: return Math.atan(left.eval(es)); - case E_SINH: return Math.sinh(left.eval(es)); - case E_COSH: return Math.cosh(left.eval(es)); - case E_TANH: return Math.tanh(left.eval(es)); - case E_FLOOR: return Math.floor(left.eval(es)); - case E_CEIL: return Math.ceil(left.eval(es)); + case E_ADD: + return left.eval(es) + right.eval(es); + case E_SUB: + return left.eval(es) - right.eval(es); + case E_MUL: + return left.eval(es) * right.eval(es); + case E_DIV: + return left.eval(es) / right.eval(es); + case E_POW: + return Math.pow(left.eval(es), right.eval(es)); + case E_OR: + return (left.eval(es) != 0 || right.eval(es) != 0) ? 1 : 0; + case E_AND: + return (left.eval(es) != 0 && right.eval(es) != 0) ? 1 : 0; + case E_EQUALS: + return (left.eval(es) == right.eval(es)) ? 1 : 0; + case E_NEQ: + return (left.eval(es) != right.eval(es)) ? 1 : 0; + case E_LEQ: + return (left.eval(es) <= right.eval(es)) ? 1 : 0; + case E_GEQ: + return (left.eval(es) >= right.eval(es)) ? 1 : 0; + case E_LESS: + return (left.eval(es) < right.eval(es)) ? 1 : 0; + case E_GREATER: + return (left.eval(es) > right.eval(es)) ? 1 : 0; + case E_TERNARY: + return children.get(left.eval(es) != 0 ? 1 : 2).eval(es); + case E_UMINUS: + return -left.eval(es); + case E_NOT: + return left.eval(es) == 0 ? 1 : 0; + case E_VAL: + return value; + case E_T: + return es.t; + case E_SIN: + return Math.sin(left.eval(es)); + case E_COS: + return Math.cos(left.eval(es)); + case E_ABS: + return Math.abs(left.eval(es)); + case E_EXP: + return Math.exp(left.eval(es)); + case E_LOG: + return Math.log(left.eval(es)); + case E_SQRT: + return Math.sqrt(left.eval(es)); + case E_TAN: + return Math.tan(left.eval(es)); + case E_ASIN: + return Math.asin(left.eval(es)); + case E_ACOS: + return Math.acos(left.eval(es)); + case E_ATAN: + return Math.atan(left.eval(es)); + case E_SINH: + return Math.sinh(left.eval(es)); + case E_COSH: + return Math.cosh(left.eval(es)); + case E_TANH: + return Math.tanh(left.eval(es)); + case E_FLOOR: + return Math.floor(left.eval(es)); + case E_CEIL: + return Math.ceil(left.eval(es)); case E_MIN: { int i; double x = left.eval(es); for (i = 1; i < children.size(); i++) - x = Math.min(x, children.get(i).eval(es)); + x = Math.min(x, children.get(i).eval(es)); return x; } case E_MAX: { int i; double x = left.eval(es); for (i = 1; i < children.size(); i++) - x = Math.max(x, children.get(i).eval(es)); + x = Math.max(x, children.get(i).eval(es)); return x; } case E_CLAMP: return Math.min(Math.max(left.eval(es), children.get(1).eval(es)), children.get(2).eval(es)); case E_STEP: { - double x = left.eval(es); + double x = left.eval(es); if (right == null) return (x < 0) ? 0 : 1; return (x > right.eval(es)) ? 0 : (x < 0) ? 0 : 1; @@ -113,12 +150,12 @@ class Expr { return children.get(x > 0 ? 2 : 1).eval(es); } case E_TRIANGLE: { - double x = posmod(left.eval(es), Math.PI*2)/Math.PI; - return (x < 1) ? -1+x*2 : 3-x*2; + double x = posmod(left.eval(es), Math.PI * 2) / Math.PI; + return (x < 1) ? -1 + x * 2 : 3 - x * 2; } case E_SAWTOOTH: { - double x = posmod(left.eval(es), Math.PI*2)/Math.PI; - return x-1; + double x = posmod(left.eval(es), Math.PI * 2) / Math.PI; + return x - 1; } case E_MOD: return left.eval(es) % right.eval(es); @@ -129,8 +166,8 @@ class Expr { case E_PWRS: { double x = left.eval(es); if (x < 0) - return -Math.pow(-x, right.eval(es)); - return Math.pow(x, right.eval(es)); + return -Math.pow(-x, right.eval(es)); + return Math.pow(x, right.eval(es)); } case E_LASTOUTPUT: return es.lastOutput; @@ -138,16 +175,16 @@ class Expr { return CirSim.theSim.timeStep; default: if (type >= E_LASTA) - return es.lastValues[type-E_LASTA]; + return es.lastValues[type - E_LASTA]; if (type >= E_DADT) - return (es.values[type-E_DADT]-es.lastValues[type-E_DADT])/CirSim.theSim.timeStep; + return (es.values[type - E_DADT] - es.lastValues[type - E_DADT]) / CirSim.theSim.timeStep; if (type >= E_A) - return es.values[type-E_A]; + return es.values[type - E_A]; CirSim.console("unknown\n"); } return 0; } - + double pwl(ExprState es, Vector args) { double x = args.get(0).eval(es); double x0 = args.get(1).eval(es); @@ -159,13 +196,13 @@ class Expr { int i = 5; while (true) { if (x < x1) - return y0+(x-x0)*(y1-y0)/(x1-x0); - if (i+1 >= args.size()) + return y0 + (x - x0) * (y1 - y0) / (x1 - x0); + if (i + 1 >= args.size()) break; x0 = x1; y0 = y1; - x1 = args.get(i ).eval(es); - y1 = args.get(i+1).eval(es); + x1 = args.get(i).eval(es); + y1 = args.get(i + 1).eval(es); i += 2; } return y1; @@ -173,9 +210,9 @@ class Expr { double posmod(double x, double y) { x %= y; - return (x >= 0) ? x : x+y; + return (x >= 0) ? x : x + y; } - + Vector children; double value; int type; @@ -227,8 +264,8 @@ class Expr { static final int E_COSH = 48; static final int E_TANH = 49; static final int E_A = 50; - static final int E_DADT = E_A+10; // must be E_A+10 - static final int E_LASTA = E_DADT+10; // should be at end and equal to E_DADT+10 + static final int E_DADT = E_A + 10; // must be E_A+10 + static final int E_LASTA = E_DADT + 10; // should be at end and equal to E_DADT+10 }; class ExprParser { @@ -254,8 +291,7 @@ void getToken() { if (i < tlen && (text.charAt(i) == '+' || text.charAt(i) == '-')) i++; } - if (!((text.charAt(i) >= '0' && text.charAt(i) <= '9') || - text.charAt(i) == '.')) + if (!((text.charAt(i) >= '0' && text.charAt(i) <= '9') || text.charAt(i) == '.')) break; } } else if (c >= 'a' && c <= 'z') { @@ -289,7 +325,7 @@ void setError(String s) { if (err == null) err = s; } - + void skipOrError(String s) { if (!skip(s)) { setError("expected " + s + ", got " + token); @@ -318,7 +354,7 @@ Expr parse() { } return e; } - + Expr parseOr() { Expr e = parseAnd(); while (skip("||")) { @@ -326,7 +362,7 @@ Expr parseOr() { } return e; } - + Expr parseAnd() { Expr e = parseEquals(); while (skip("&&")) { @@ -334,14 +370,14 @@ Expr parseAnd() { } return e; } - + Expr parseEquals() { Expr e = parseCompare(); if (skip("==")) return new Expr(e, parseCompare(), Expr.E_EQUALS); return e; } - + Expr parseCompare() { Expr e = parseAdd(); if (skip("<=")) @@ -438,21 +474,21 @@ Expr parseTerm() { char c = token.charAt(0); if (c >= 'a' && c <= 'i') { getToken(); - return new Expr(Expr.E_A + (c-'a')); + return new Expr(Expr.E_A + (c - 'a')); } } if (token.startsWith("last") && token.length() == 5) { char c = token.charAt(4); if (c >= 'a' && c <= 'i') { getToken(); - return new Expr(Expr.E_LASTA + (c-'a')); + return new Expr(Expr.E_LASTA + (c - 'a')); } } if (token.endsWith("dt") && token.startsWith("d") && token.length() == 4) { char c = token.charAt(1); if (c >= 'a' && c <= 'i') { getToken(); - return new Expr(Expr.E_DADT + (c-'a')); + return new Expr(Expr.E_DADT + (c - 'a')); } } if (skip("lastoutput")) @@ -461,8 +497,8 @@ Expr parseTerm() { return new Expr(Expr.E_TIMESTEP); if (skip("pi")) return new Expr(Expr.E_VAL, 3.14159265358979323846); -// if (skip("e")) -// return new Expr(Expr.E_VAL, 2.7182818284590452354); + // if (skip("e")) + // return new Expr(Expr.E_VAL, 2.7182818284590452354); if (skip("sin")) return parseFunc(Expr.E_SIN); if (skip("cos")) @@ -535,6 +571,8 @@ Expr parseTerm() { err = null; getToken(); } - - String gotError() { return err; } + + String gotError() { + return err; + } }; diff --git a/src/com/lushprojects/circuitjs1/client/ExtVoltageElm.java b/src/com/lushprojects/circuitjs1/client/ExtVoltageElm.java index 9dd4afaa..a3698186 100644 --- a/src/com/lushprojects/circuitjs1/client/ExtVoltageElm.java +++ b/src/com/lushprojects/circuitjs1/client/ExtVoltageElm.java @@ -22,47 +22,65 @@ import com.lushprojects.circuitjs1.client.util.Locale; class ExtVoltageElm extends RailElm { - public ExtVoltageElm(int xx, int yy) { super(xx, yy, WF_AC); name = "ext"; } - public ExtVoltageElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - name = CustomLogicModel.unescape(st.nextToken()); - waveform = WF_AC; - } - - String name; - double voltage; - - String dump() { return super.dump() + " " + CustomLogicModel.escape(name); } - - void drawRail(Graphics g) { - drawRailText(g, name); - } - void setVoltage(double v) { if (!Double.isNaN(v)) voltage = v; } - String getName() { return name; } - - double getVoltage() { - return voltage; - } + public ExtVoltageElm(int xx, int yy) { + super(xx, yy, WF_AC); + name = "ext"; + } - int getDumpType() { return 418; } - int getShortcut() { return 0; } + public ExtVoltageElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + name = CustomLogicModel.unescape(st.nextToken()); + waveform = WF_AC; + } - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("Name", 0, -1, -1); - ei.text = name; - return ei; - } - return null; - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - name = ei.textf.getText(); - } + String name; + double voltage; + + String dump() { + return super.dump() + " " + CustomLogicModel.escape(name); + } + + void drawRail(Graphics g) { + drawRailText(g, name); + } + + void setVoltage(double v) { + if (!Double.isNaN(v)) + voltage = v; + } - void getInfo(String arr[]) { - super.getInfo(arr); - arr[0] = Locale.LS("ext. voltage") + " (" + name + ")"; + String getName() { + return name; + } + + double getVoltage() { + return voltage; + } + + int getDumpType() { + return 418; + } + + int getShortcut() { + return 0; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("Name", 0, -1, -1); + ei.text = name; + return ei; } + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + name = ei.textf.getText(); + } + + void getInfo(String arr[]) { + super.getInfo(arr); + arr[0] = Locale.LS("ext. voltage") + " (" + name + ")"; } +} diff --git a/src/com/lushprojects/circuitjs1/client/FFT.java b/src/com/lushprojects/circuitjs1/client/FFT.java index e9243a37..6b203267 100644 --- a/src/com/lushprojects/circuitjs1/client/FFT.java +++ b/src/com/lushprojects/circuitjs1/client/FFT.java @@ -26,70 +26,69 @@ class FFT { private double[] sinTable; FFT(int n) { - size = n; - bits = (int) (Math.log(size) / Math.log(2)); - cosTable = new double[size / 2]; - sinTable = new double[size / 2]; - double dtheta = -2 * Math.PI / size; - for (int i = 0; i < cosTable.length; i++) { - cosTable[i] = Math.cos(dtheta * i); - sinTable[i] = Math.sin(dtheta * i); - } + size = n; + bits = (int) (Math.log(size) / Math.log(2)); + cosTable = new double[size / 2]; + sinTable = new double[size / 2]; + double dtheta = -2 * Math.PI / size; + for (int i = 0; i < cosTable.length; i++) { + cosTable[i] = Math.cos(dtheta * i); + sinTable[i] = Math.sin(dtheta * i); + } } /* - * This uses the radix-2 decimation-in-time FFT algorithm. - * Based on + * This uses the radix-2 decimation-in-time FFT algorithm. Based on * http://www.ee.columbia.edu/~ronw/code/MEAPsoft/doc/html/FFT_8java-source.html - * Douglas L. Jones - * University of Illinois at Urbana-Champaign - * January 19, 1992 + * Douglas L. Jones University of Illinois at Urbana-Champaign January 19, 1992 * http://cnx.rice.edu/content/m12016/latest/ */ void fft(double[] real, double[] imag) { - int j = 0; - int n2 = real.length / 2; - for (int i=1; i < real.length - 1; i++) { - int n1 = n2; - while (j >= n1) { - j -= n1; - n1 /= 2; - } - j += n1; - if (i < j) { - double t1 = real[i]; - real[i] = real[j]; - real[j] = t1; - t1 = imag[i]; - imag[i] = imag[j]; - imag[j] = t1; - } - } - n2 = 1; - for (int i = 0; i < bits; i++) { - int n1 = n2; - n2 <<= 1; - int a = 0; - for (j = 0; j < n1; j++) { - double c = cosTable[a]; - double s = sinTable[a]; - a += 1 << (bits - i - 1); - for (int k = j; k < real.length; k += n2) { - int t = k + n1; - double t1 = c * real[t] - s * imag[t]; - double t2 = s * real[t] + c * imag[t]; - real[k+n1] = real[k] - t1; - imag[k+n1] = imag[k] - t2; - real[k] += t1; - imag[k] += t2; - } - } - } + int j = 0; + int n2 = real.length / 2; + for (int i = 1; i < real.length - 1; i++) { + int n1 = n2; + while (j >= n1) { + j -= n1; + n1 /= 2; + } + j += n1; + if (i < j) { + double t1 = real[i]; + real[i] = real[j]; + real[j] = t1; + t1 = imag[i]; + imag[i] = imag[j]; + imag[j] = t1; + } + } + n2 = 1; + for (int i = 0; i < bits; i++) { + int n1 = n2; + n2 <<= 1; + int a = 0; + for (j = 0; j < n1; j++) { + double c = cosTable[a]; + double s = sinTable[a]; + a += 1 << (bits - i - 1); + for (int k = j; k < real.length; k += n2) { + int t = k + n1; + double t1 = c * real[t] - s * imag[t]; + double t2 = s * real[t] + c * imag[t]; + real[k + n1] = real[k] - t1; + imag[k + n1] = imag[k] - t2; + real[k] += t1; + imag[k] += t2; + } + } + } + } + + int getSize() { + return size; } - int getSize() { return size; } - double magnitude(double real, double imag) { - return Math.sqrt(real * real + imag * imag) / size; + return Math.sqrt(real * real + imag * imag) / size; } } diff --git a/src/com/lushprojects/circuitjs1/client/FMElm.java b/src/com/lushprojects/circuitjs1/client/FMElm.java index 3995cdf8..7750326d 100644 --- a/src/com/lushprojects/circuitjs1/client/FMElm.java +++ b/src/com/lushprojects/circuitjs1/client/FMElm.java @@ -23,58 +23,69 @@ class FMElm extends CircuitElm { static final int FLAG_COS = 2; - double carrierfreq,signalfreq, maxVoltage, freqTimeZero,deviation; - double lasttime=0; - double funcx=0; + double carrierfreq, signalfreq, maxVoltage, freqTimeZero, deviation; + double lasttime = 0; + double funcx = 0; + public FMElm(int xx, int yy) { super(xx, yy); - deviation=200; + deviation = 200; maxVoltage = 5; - carrierfreq =800; - signalfreq=40; + carrierfreq = 800; + signalfreq = 40; reset(); } - public FMElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public FMElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - carrierfreq = new Double(st.nextToken()).doubleValue(); - signalfreq= new Double(st.nextToken()).doubleValue(); - maxVoltage = new Double(st.nextToken()).doubleValue(); - deviation = new Double(st.nextToken()).doubleValue(); + carrierfreq = Double.valueOf(st.nextToken()).doubleValue(); + signalfreq = Double.valueOf(st.nextToken()).doubleValue(); + maxVoltage = Double.valueOf(st.nextToken()).doubleValue(); + deviation = Double.valueOf(st.nextToken()).doubleValue(); if ((flags & FLAG_COS) != 0) { flags &= ~FLAG_COS; } reset(); } - int getDumpType() { return 201; } + + int getDumpType() { + return 201; + } + String dump() { - return super.dump() + " " +carrierfreq+" " + signalfreq + " " +maxVoltage + " " +deviation; + return super.dump() + " " + carrierfreq + " " + signalfreq + " " + maxVoltage + " " + deviation; } - /*void setCurrent(double c) { - current = c; - System.out.print("v current set to " + c + "\n"); - }*/ + /* + * void setCurrent(double c) { current = c; System.out.print("v current set to " + * + c + "\n"); } + */ void reset() { freqTimeZero = 0; curcount = 0; } - int getPostCount() { return 1; } - - void stamp() { - sim.stampVoltageSource(0, nodes[0], voltSource); + + int getPostCount() { + return 1; + } + + void stamp() { + sim.stampVoltageSource(0, nodes[0], voltSource); } + void doStep() { - sim.updateVoltageSource(0, nodes[0], voltSource, getVoltage()); + sim.updateVoltageSource(0, nodes[0], voltSource, getVoltage()); } + double getVoltage() { - double deltaT=sim.t-lasttime; - lasttime=sim.t; - double signalamplitude=Math.sin((2*pi*(sim.t-freqTimeZero))*signalfreq); - funcx+=deltaT*(carrierfreq+(signalamplitude*deviation)); - double w = 2*pi*funcx; - return Math.sin(w)*maxVoltage; + double deltaT = sim.t - lasttime; + lasttime = sim.t; + double signalamplitude = Math.sin((2 * pi * (sim.t - freqTimeZero)) * signalfreq); + funcx += deltaT * (carrierfreq + (signalamplitude * deviation)); + double w = 2 * pi * funcx; + return Math.sin(w) * maxVoltage; } + final int circleSize = 17; void draw(Graphics g) { @@ -82,55 +93,62 @@ void draw(Graphics g) { setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); - Font f = new Font("SansSerif", 0, 12); - g.setFont(f); - g.setColor(needsHighlight() ? selectColor : whiteColor); - setPowerColor(g, false); - double v = getVoltage(); - String s = "FM"; - drawCenteredText(g, s, x2, y2, true); - drawWaveform(g, point2); + Font f = new Font("SansSerif", 0, 12); + g.setFont(f); + g.setColor(needsHighlight() ? selectColor : whiteColor); + setPowerColor(g, false); + double v = getVoltage(); + String s = "FM"; + drawCenteredText(g, s, x2, y2, true); + drawWaveform(g, point2); drawPosts(g); curcount = updateDotCount(-current, curcount); if (sim.dragElm != this) drawDots(g, point1, lead1, curcount); } - + void drawWaveform(Graphics g, Point center) { g.setColor(needsHighlight() ? selectColor : Color.gray); setPowerColor(g, false); - int xc = center.x; int yc = center.y; + int xc = center.x; + int yc = center.y; drawThickCircle(g, xc, yc, circleSize); int wl = 8; - adjustBbox(xc-circleSize, yc-circleSize, - xc+circleSize, yc+circleSize); + adjustBbox(xc - circleSize, yc - circleSize, xc + circleSize, yc + circleSize); } - - void setPoints() { + void setPoints() { super.setPoints(); - lead1 = interpPoint(point1, point2, 1-circleSize/dn); + lead1 = interpPoint(point1, point2, 1 - circleSize / dn); } - - double getVoltageDiff() { return volts[0]; } - - boolean hasGroundConnection(int n1) { return true; } - + + double getVoltageDiff() { + return volts[0]; + } + + boolean hasGroundConnection(int n1) { + return true; + } + int getVoltageSourceCount() { return 1; } - double getPower() { return -getVoltageDiff()*current; } + + double getPower() { + return -getVoltageDiff() * current; + } + void getInfo(String arr[]) { - + arr[0] = "FM Source"; arr[1] = "I = " + getCurrentText(getCurrent()); - arr[2] = "V = " + - getVoltageText(getVoltageDiff()); - arr[3] = "cf = " + getUnitText(carrierfreq, "Hz"); - arr[4] = "sf = " + getUnitText(signalfreq, "Hz"); - arr[5]= "dev =" + getUnitText(deviation, "Hz"); - arr[6] = "Vmax = " + getVoltageText(maxVoltage); + arr[2] = "V = " + getVoltageText(getVoltageDiff()); + arr[3] = "cf = " + getUnitText(carrierfreq, "Hz"); + arr[4] = "sf = " + getUnitText(signalfreq, "Hz"); + arr[5] = "dev =" + getUnitText(deviation, "Hz"); + arr[6] = "Vmax = " + getVoltageText(maxVoltage); } + public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Max Voltage", maxVoltage, -20, 20); @@ -140,17 +158,18 @@ public EditInfo getEditInfo(int n) { return new EditInfo("Signal Frequency (Hz)", signalfreq, 4, 500); if (n == 3) return new EditInfo("Deviation (Hz)", deviation, 4, 500); - + return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) maxVoltage = ei.value; if (n == 1) carrierfreq = ei.value; if (n == 2) - signalfreq=ei.value; + signalfreq = ei.value; if (n == 3) - deviation=ei.value; + deviation = ei.value; } } diff --git a/src/com/lushprojects/circuitjs1/client/Font.java b/src/com/lushprojects/circuitjs1/client/Font.java index f7d332e7..bb2be196 100644 --- a/src/com/lushprojects/circuitjs1/client/Font.java +++ b/src/com/lushprojects/circuitjs1/client/Font.java @@ -19,21 +19,19 @@ package com.lushprojects.circuitjs1.client; +class Font { + static final int BOLD = 1; + String fontname; + int size; -class Font { - static final int BOLD=1; - - String fontname; - int size; - - public Font(String name, int style, int size){ - String styleStr="normal "; - if (name=="SansSerif") - name="sans-serif"; - if ((style & BOLD) !=0) - styleStr="bold "; - fontname=styleStr+size+"px "+name; - this.size=size; - } + public Font(String name, int style, int size) { + String styleStr = "normal "; + if (name == "SansSerif") + name = "sans-serif"; + if ((style & BOLD) != 0) + styleStr = "bold "; + fontname = styleStr + size + "px " + name; + this.size = size; + } } \ No newline at end of file diff --git a/src/com/lushprojects/circuitjs1/client/FullAdderElm.java b/src/com/lushprojects/circuitjs1/client/FullAdderElm.java index c3e41a6f..87793395 100644 --- a/src/com/lushprojects/circuitjs1/client/FullAdderElm.java +++ b/src/com/lushprojects/circuitjs1/client/FullAdderElm.java @@ -19,77 +19,92 @@ package com.lushprojects.circuitjs1.client; - class FullAdderElm extends ChipElm { - public FullAdderElm(int xx, int yy) { - super(xx, yy); - flags |= FLAG_BITS; - bits = 4; - setupPins(); +class FullAdderElm extends ChipElm { + public FullAdderElm(int xx, int yy) { + super(xx, yy); + flags |= FLAG_BITS; + bits = 4; + setupPins(); + } + + public FullAdderElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + if (!needsBits()) + bits = 1; + setupPins(); + } + + static final int FLAG_BITS = 2; + + String getChipName() { + return "Adder"; + } + + int carryIn, carryOut; + + void setupPins() { + sizeX = 2; + sizeY = bits * 2 + 1; + pins = new Pin[getPostCount()]; + + int i; + for (i = 0; i != bits; i++) { + pins[i] = new Pin(bits - 1 - i, SIDE_W, "A" + i); + pins[i + bits] = new Pin(bits - 1 - i + bits, SIDE_W, "B" + i); + pins[i + bits * 2] = new Pin(bits - 1 - i + 2, SIDE_E, "S" + i); + pins[i + bits * 2].output = true; } - public FullAdderElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - if (!needsBits()) - bits = 1; - setupPins(); + carryIn = bits * 3; + carryOut = bits * 3 + 1; + pins[carryOut] = new Pin(0, SIDE_E, "C"); + pins[carryOut].output = true; + pins[carryIn] = new Pin(bits * 2, SIDE_W, "Cin"); + allocNodes(); + } + + int getPostCount() { + return bits * 3 + 2; + } + + int getVoltageSourceCount() { + return bits + 1; + } + + void execute() { + int i; + int c = pins[carryIn].value ? 1 : 0; + for (i = 0; i != bits; i++) { + int v = (pins[i].value ? 1 : 0) + (pins[i + bits].value ? 1 : 0) + c; + c = (v > 1) ? 1 : 0; + writeOutput(i + bits * 2, ((v & 1) == 1)); } - static final int FLAG_BITS = 2; - - String getChipName() { return "Adder"; } - int carryIn, carryOut; - - void setupPins() { - sizeX=2; - sizeY=bits*2+1; - pins=new Pin[getPostCount()]; - - int i; - for (i = 0; i != bits; i++) { - pins[i ] = new Pin(bits-1-i, SIDE_W, "A" + i); - pins[i+bits ] = new Pin(bits-1-i+bits, SIDE_W, "B" + i); - pins[i+bits*2] = new Pin(bits-1-i+2, SIDE_E, "S" + i); - pins[i+bits*2].output=true; - } - carryIn = bits*3; - carryOut = bits*3+1; - pins[carryOut] = new Pin(0, SIDE_E, "C"); - pins[carryOut].output=true; - pins[carryIn] = new Pin(bits*2, SIDE_W, "Cin"); + writeOutput(carryOut, (c == 1)); + } + + int getDumpType() { + return 196; + } + + boolean needsBits() { + return (flags & FLAG_BITS) != 0; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) + return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); + return super.getChipEditInfo(n); + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) { + bits = (int) ei.value; + flags |= FLAG_BITS; + setupPins(); + setPoints(); allocNodes(); + return; } - int getPostCount() { - return bits*3+2; - } - int getVoltageSourceCount() { return bits+1; } - - void execute() { - int i; - int c = pins[carryIn].value ? 1 : 0; - for (i = 0; i != bits; i++) { - int v = (pins[i].value ? 1 : 0) + (pins[i+bits].value ? 1 : 0) + c; - c = (v > 1) ? 1 : 0; - writeOutput(i+bits*2, ((v & 1) == 1)); - } - writeOutput(carryOut, (c == 1)); - } - int getDumpType() { return 196; } - boolean needsBits() { return (flags & FLAG_BITS) != 0; } - - public EditInfo getChipEditInfo(int n) { - if (n == 0) - return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); - return super.getChipEditInfo(n); - } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) { - bits = (int)ei.value; - flags |= FLAG_BITS; - setupPins(); - setPoints(); - allocNodes(); - return; - } - super.setChipEditValue(n, ei); - } - + super.setChipEditValue(n, ei); } + +} diff --git a/src/com/lushprojects/circuitjs1/client/FuseElm.java b/src/com/lushprojects/circuitjs1/client/FuseElm.java index f283986a..71bef0de 100644 --- a/src/com/lushprojects/circuitjs1/client/FuseElm.java +++ b/src/com/lushprojects/circuitjs1/client/FuseElm.java @@ -22,154 +22,174 @@ import com.lushprojects.circuitjs1.client.util.Locale; class FuseElm extends CircuitElm { - double resistance; - double heat; - double i2t; - boolean blown; - final int FLAG_IEC_SYMBOL = 1; - final double blownResistance = 1e9; - public FuseElm(int xx, int yy) { - super(xx, yy); - // from https://m.littelfuse.com/~/media/electronics/datasheets/fuses/littelfuse_fuse_218_datasheet.pdf.pdf - i2t = 6.73; - resistance = .0613; + double resistance; + double heat; + double i2t; + boolean blown; + final int FLAG_IEC_SYMBOL = 1; + final double blownResistance = 1e9; + + public FuseElm(int xx, int yy) { + super(xx, yy); + // from + // https://m.littelfuse.com/~/media/electronics/datasheets/fuses/littelfuse_fuse_218_datasheet.pdf.pdf + i2t = 6.73; + resistance = .0613; + } + + public FuseElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + resistance = Double.valueOf(st.nextToken()).doubleValue(); + i2t = Double.valueOf(st.nextToken()).doubleValue(); + heat = Double.valueOf(st.nextToken()).doubleValue(); + blown = Boolean.valueOf(st.nextToken()).booleanValue(); + } + + String dump() { + return super.dump() + " " + resistance + " " + i2t + " " + heat + " " + blown; + } + + int getDumpType() { + return 404; + } + + boolean isIECSymbol() { + return (flags & FLAG_IEC_SYMBOL) != 0; + } + + void reset() { + super.reset(); + heat = 0; + blown = false; + } + + void setPoints() { + super.setPoints(); + int llen = isIECSymbol() ? 32 : 16; + calcLeads(llen); + } + + Color getTempColor(Graphics g) { + Color c = getVoltageColor(g, volts[0]); + double temp = heat / i2t; + if (temp < .3333) { + double val = temp * 3; + int x = (int) (255 * val); + if (x < 0) + x = 0; + return new Color(x + (255 - x) * c.getRed() / 255, (255 - x) * c.getGreen() / 255, + (255 - x) * c.getBlue() / 255); } - public FuseElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - resistance = new Double(st.nextToken()).doubleValue(); - i2t = new Double(st.nextToken()).doubleValue(); - heat = new Double(st.nextToken()).doubleValue(); - blown = new Boolean(st.nextToken()).booleanValue(); + if (temp < .6667) { + int x = (int) ((temp - .3333) * 3 * 255); + if (x < 0) + x = 0; + return new Color(255, x, 0); } - String dump() { - return super.dump() + " " + resistance + " " + i2t + " " + heat + " " + blown; + if (temp < 1) { + int x = (int) ((temp - .6666) * 3 * 255); + if (x < 0) + x = 0; + return new Color(255, 255, x); } - int getDumpType() { return 404; } + return Color.white; + } - boolean isIECSymbol() { return (flags & FLAG_IEC_SYMBOL) != 0; } - - void reset() { - super.reset(); - heat = 0; - blown = false; - } - void setPoints() { - super.setPoints(); - int llen = isIECSymbol() ? 32 : 16; - calcLeads(llen); - } + void draw(Graphics g) { + int segments = 16; + int i; + int hs = 6; + setBbox(point1, point2, hs); + draw2Leads(g); - Color getTempColor(Graphics g) { - Color c = getVoltageColor(g, volts[0]); - double temp = heat/i2t; - if (temp < .3333) { - double val = temp*3; - int x = (int) (255*val); - if (x < 0) - x = 0; - return new Color(x+(255-x)*c.getRed()/255, (255-x)*c.getGreen()/255, (255-x)*c.getBlue()/255); - } - if (temp < .6667) { - int x = (int) ((temp-.3333)*3*255); - if (x < 0) - x = 0; - return new Color(255, x, 0); - } - if (temp < 1) { - int x = (int) ((temp-.6666)*3*255); - if (x < 0) - x = 0; - return new Color(255, 255, x); + // double segf = 1./segments; + double len = distance(lead1, lead2); + g.context.save(); + g.context.setLineWidth(3.0); + g.context.transform(((double) (lead2.x - lead1.x)) / len, ((double) (lead2.y - lead1.y)) / len, + -((double) (lead2.y - lead1.y)) / len, ((double) (lead2.x - lead1.x)) / len, lead1.x, lead1.y); + g.context.setStrokeStyle(getTempColor(g).getHexValue()); + if (!isIECSymbol()) { + if (!blown) { + g.context.beginPath(); + g.context.moveTo(0, 0); + for (i = 0; i <= segments; i++) + g.context.lineTo(i * len / segments, hs * Math.sin(i * Math.PI * 2 / segments)); + g.context.stroke(); } - return Color.white; - } - - void draw(Graphics g) { - int segments = 16; - int i; - int hs=6; - setBbox(point1, point2, hs); - draw2Leads(g); - - // double segf = 1./segments; - double len = distance(lead1, lead2); - g.context.save(); - g.context.setLineWidth(3.0); - g.context.transform(((double)(lead2.x-lead1.x))/len, ((double)(lead2.y-lead1.y))/len, -((double)(lead2.y-lead1.y))/len,((double)(lead2.x-lead1.x))/len,lead1.x,lead1.y); - g.context.setStrokeStyle(getTempColor(g).getHexValue()); - if (!isIECSymbol()) { - if (!blown) { - g.context.beginPath(); - g.context.moveTo(0,0); - for (i = 0; i <= segments; i++) - g.context.lineTo(i*len/segments, hs*Math.sin(i*Math.PI*2/segments)); - g.context.stroke(); - } - } else { - if (!blown) { - g.context.beginPath(); - g.context.moveTo(0, 0); - g.context.lineTo(len, 0); - g.context.stroke(); - g.context.strokeRect(0, -hs, len, 2.0*hs); - } + } else { + if (!blown) { + g.context.beginPath(); + g.context.moveTo(0, 0); + g.context.lineTo(len, 0); + g.context.stroke(); + g.context.strokeRect(0, -hs, len, 2.0 * hs); } - g.context.restore(); - doDots(g); - drawPosts(g); } + g.context.restore(); + doDots(g); + drawPosts(g); + } - void calculateCurrent() { - current = (volts[0]-volts[1])/(blown ? blownResistance : resistance); - } - void stamp() { - sim.stampNonLinear(nodes[0]); - sim.stampNonLinear(nodes[1]); - } - boolean nonLinear() { return true; } - void startIteration() { - double i = getCurrent(); - - // accumulate heat - heat += i*i*sim.timeStep; - - // dissipate heat. we assume the fuse can dissipate its entire i2t in 3 seconds - heat -= sim.timeStep*i2t/3; - - if (heat < 0) - heat = 0; - if (heat > i2t) - blown = true; - } - void doStep() { - sim.stampResistor(nodes[0], nodes[1], blown ? blownResistance : resistance); - } - void getInfo(String arr[]) { - arr[0] = blown ? "fuse (blown)" : "fuse"; - getBasicInfo(arr); - arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); - arr[4] = "I2t = " + i2t; - if (!blown) - arr[5] = ((int)(heat*100/i2t)) + "% " + Locale.LS("melted"); - } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("I2t", i2t, 0, 0); - if (n == 1) - return new EditInfo("Resistance", resistance, 0, 0); - if (n == 2) - return EditInfo.createCheckbox("IEC Symbol", isIECSymbol()); - return null; - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) - i2t = ei.value; - if (n == 1 && ei.value > 0) - resistance = ei.value; - if (n == 2) { - flags = ei.changeFlag(flags, FLAG_IEC_SYMBOL); - setPoints(); - } + void calculateCurrent() { + current = (volts[0] - volts[1]) / (blown ? blownResistance : resistance); + } + + void stamp() { + sim.stampNonLinear(nodes[0]); + sim.stampNonLinear(nodes[1]); + } + + boolean nonLinear() { + return true; + } + + void startIteration() { + double i = getCurrent(); + + // accumulate heat + heat += i * i * sim.timeStep; + + // dissipate heat. we assume the fuse can dissipate its entire i2t in 3 seconds + heat -= sim.timeStep * i2t / 3; + + if (heat < 0) + heat = 0; + if (heat > i2t) + blown = true; + } + + void doStep() { + sim.stampResistor(nodes[0], nodes[1], blown ? blownResistance : resistance); + } + + void getInfo(String arr[]) { + arr[0] = blown ? "fuse (blown)" : "fuse"; + getBasicInfo(arr); + arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); + arr[4] = "I2t = " + i2t; + if (!blown) + arr[5] = ((int) (heat * 100 / i2t)) + "% " + Locale.LS("melted"); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("I2t", i2t, 0, 0); + if (n == 1) + return new EditInfo("Resistance", resistance, 0, 0); + if (n == 2) + return EditInfo.createCheckbox("IEC Symbol", isIECSymbol()); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) + i2t = ei.value; + if (n == 1 && ei.value > 0) + resistance = ei.value; + if (n == 2) { + flags = ei.changeFlag(flags, FLAG_IEC_SYMBOL); + setPoints(); } } +} diff --git a/src/com/lushprojects/circuitjs1/client/GateElm.java b/src/com/lushprojects/circuitjs1/client/GateElm.java index 2c66ddf6..bfd3511f 100644 --- a/src/com/lushprojects/circuitjs1/client/GateElm.java +++ b/src/com/lushprojects/circuitjs1/client/GateElm.java @@ -19,239 +19,272 @@ package com.lushprojects.circuitjs1.client; - abstract class GateElm extends CircuitElm { - final int FLAG_SMALL = 1<<0; - final int FLAG_SCHMITT = 1<<1; - final int FLAG_INVERT_INPUTS = 1<<2; - int inputCount = 2; - boolean lastOutput; - double highVoltage; - public static double lastHighVoltage = 5; - static boolean lastSchmitt = false; - - public GateElm(int xx, int yy) { - super(xx, yy); - noDiagonal = true; - inputCount = 2; - - // copy defaults from last gate edited - highVoltage = lastHighVoltage; - if (lastSchmitt) - flags |= FLAG_SCHMITT; - - setSize(sim.smallGridCheckItem.getState() ? 1 : 2); - } - public GateElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - inputCount = new Integer(st.nextToken()).intValue(); - double lastOutputVoltage = new Double (st.nextToken()).doubleValue(); - noDiagonal = true; - highVoltage = 5; - try { - highVoltage = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { } - lastOutput = lastOutputVoltage > highVoltage*.5; - setSize((f & FLAG_SMALL) != 0 ? 1 : 2); - allocNodes(); - } - boolean isInverting() { return false; } - int gsize, gwidth, gwidth2, gheight, hs2; - void setSize(int s) { - gsize = s; - gwidth = 7*s; - gwidth2 = 14*s; - gheight = 8*s; - flags &= ~FLAG_SMALL; - flags |= (s == 1) ? FLAG_SMALL : 0; - } - String dump() { - return super.dump() + " " + inputCount + " " + volts[inputCount] + " " + highVoltage; - } - Point inPosts[], inGates[]; - boolean inputStates[]; - int ww; - void setPoints() { - super.setPoints(); - inputStates = new boolean[inputCount]; - if (dn > 150 && this == sim.dragElm) - setSize(2); - int hs = gheight; - int i; - ww = gwidth2; // was 24 - if (ww > dn/2) - ww = (int) (dn/2); - if (isInverting() && ww+8 > dn/2) - ww = (int) (dn/2-8); - calcLeads(ww*2); - inPosts = new Point[inputCount]; - inGates = new Point[inputCount]; - allocNodes(); - int i0 = -inputCount/2; - if (hasFlag(FLAG_INVERT_INPUTS)) - icircles = new Point[inputCount]; - else - icircles = null; - for (i = 0; i != inputCount; i++, i0++) { - if (i0 == 0 && (inputCount & 1) == 0) - i0++; - inPosts[i] = interpPoint(point1, point2, 0, hs*i0); - inGates[i] = interpPoint(lead1, lead2, icircles != null ? -8/(ww*2.) : 0, hs*i0); - if (icircles != null) - icircles[i] = interpPoint(lead1, lead2, -4/(ww*2.), hs*i0); - volts[i] = (lastOutput ^ isInverting()) ? 5 : 0; - } - hs2 = gwidth*(inputCount/2+1); - setBbox(point1, point2, hs2); - if (hasSchmittInputs()) - schmittPoly = getSchmittPolygon(gsize, .47f); - } - - void createEuroGatePolygon() { - Point pts[] = newPointArray(4); - interpPoint2(lead1, lead2, pts[0], pts[1], 0, hs2); - interpPoint2(lead1, lead2, pts[3], pts[2], 1, hs2); - gatePoly = createPolygon(pts); - } +abstract class GateElm extends CircuitElm { + final int FLAG_SMALL = 1 << 0; + final int FLAG_SCHMITT = 1 << 1; + final int FLAG_INVERT_INPUTS = 1 << 2; + int inputCount = 2; + boolean lastOutput; + double highVoltage; + public static double lastHighVoltage = 5; + static boolean lastSchmitt = false; - String getGateText() { return null; } - static boolean useEuroGates() { return sim.euroGatesCheckItem.getState(); } + public GateElm(int xx, int yy) { + super(xx, yy); + noDiagonal = true; + inputCount = 2; - void drawGatePolygon(Graphics g) { - drawThickPolygon(g, gatePoly); + // copy defaults from last gate edited + highVoltage = lastHighVoltage; + if (lastSchmitt) + flags |= FLAG_SCHMITT; + + setSize(sim.smallGridCheckItem.getState() ? 1 : 2); + } + + public GateElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + inputCount = Integer.valueOf(st.nextToken()).intValue(); + double lastOutputVoltage = Double.valueOf(st.nextToken()).doubleValue(); + noDiagonal = true; + highVoltage = 5; + try { + highVoltage = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } - - void draw(Graphics g) { - int i; - for (i = 0; i != inputCount; i++) { - setVoltageColor(g, volts[i]); - drawThickLine(g, inPosts[i], inGates[i]); - } - setVoltageColor(g, volts[inputCount]); - drawThickLine(g, lead2, point2); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - if (useEuroGates()) { - drawThickPolygon(g, gatePoly); - Point center = interpPoint(point1, point2, .5); - drawCenteredText(g, getGateText(), center.x, center.y-6*gsize, true); - } else - drawGatePolygon(g); - g.setLineWidth(2); - if (hasSchmittInputs()) - drawPolygon(g, schmittPoly); - g.setLineWidth(1); - if (linePoints != null) - for (i = 0; i != linePoints.length-1; i++) - drawThickLine(g, linePoints[i], linePoints[i+1]); - if (isInverting()) - drawThickCircle(g, pcircle.x, pcircle.y, 3); + lastOutput = lastOutputVoltage > highVoltage * .5; + setSize((f & FLAG_SMALL) != 0 ? 1 : 2); + allocNodes(); + } + + boolean isInverting() { + return false; + } + + int gsize, gwidth, gwidth2, gheight, hs2; + + void setSize(int s) { + gsize = s; + gwidth = 7 * s; + gwidth2 = 14 * s; + gheight = 8 * s; + flags &= ~FLAG_SMALL; + flags |= (s == 1) ? FLAG_SMALL : 0; + } + + String dump() { + return super.dump() + " " + inputCount + " " + volts[inputCount] + " " + highVoltage; + } + + Point inPosts[], inGates[]; + boolean inputStates[]; + int ww; + + void setPoints() { + super.setPoints(); + inputStates = new boolean[inputCount]; + if (dn > 150 && this == sim.dragElm) + setSize(2); + int hs = gheight; + int i; + ww = gwidth2; // was 24 + if (ww > dn / 2) + ww = (int) (dn / 2); + if (isInverting() && ww + 8 > dn / 2) + ww = (int) (dn / 2 - 8); + calcLeads(ww * 2); + inPosts = new Point[inputCount]; + inGates = new Point[inputCount]; + allocNodes(); + int i0 = -inputCount / 2; + if (hasFlag(FLAG_INVERT_INPUTS)) + icircles = new Point[inputCount]; + else + icircles = null; + for (i = 0; i != inputCount; i++, i0++) { + if (i0 == 0 && (inputCount & 1) == 0) + i0++; + inPosts[i] = interpPoint(point1, point2, 0, hs * i0); + inGates[i] = interpPoint(lead1, lead2, icircles != null ? -8 / (ww * 2.) : 0, hs * i0); if (icircles != null) - for (i = 0; i != inputCount; i++) - drawThickCircle(g, icircles[i].x, icircles[i].y, 3); - curcount = updateDotCount(current, curcount); - drawDots(g, lead2, point2, curcount); - drawPosts(g); + icircles[i] = interpPoint(lead1, lead2, -4 / (ww * 2.), hs * i0); + volts[i] = (lastOutput ^ isInverting()) ? 5 : 0; } - Polygon gatePoly, schmittPoly; - Point pcircle, linePoints[], icircles[]; - int getPostCount() { return inputCount+1; } - Point getPost(int n) { - if (n == inputCount) - return point2; - return inPosts[n]; - } - int getVoltageSourceCount() { return 1; } - abstract String getGateName(); - void getInfo(String arr[]) { - arr[0] = getGateName(); - arr[1] = "Vout = " + getVoltageText(volts[inputCount]); - arr[2] = "Iout = " + getCurrentText(getCurrent()); - } - void stamp() { - sim.stampVoltageSource(0, nodes[inputCount], voltSource); - } - boolean hasSchmittInputs() { return (flags & FLAG_SCHMITT) != 0; } - boolean getInput(int x) { - boolean high = !hasFlag(FLAG_INVERT_INPUTS); - if (!hasSchmittInputs()) - return (volts[x] > highVoltage*.5) ? high : !high; - boolean res = volts[x] > highVoltage*(inputStates[x] ? .35 : .55); - inputStates[x] = res ? high : !high; - return res; + hs2 = gwidth * (inputCount / 2 + 1); + setBbox(point1, point2, hs2); + if (hasSchmittInputs()) + schmittPoly = getSchmittPolygon(gsize, .47f); + } + + void createEuroGatePolygon() { + Point pts[] = newPointArray(4); + interpPoint2(lead1, lead2, pts[0], pts[1], 0, hs2); + interpPoint2(lead1, lead2, pts[3], pts[2], 1, hs2); + gatePoly = createPolygon(pts); + } + + String getGateText() { + return null; + } + + static boolean useEuroGates() { + return sim.euroGatesCheckItem.getState(); + } + + void drawGatePolygon(Graphics g) { + drawThickPolygon(g, gatePoly); + } + + void draw(Graphics g) { + int i; + for (i = 0; i != inputCount; i++) { + setVoltageColor(g, volts[i]); + drawThickLine(g, inPosts[i], inGates[i]); } - abstract boolean calcFunction(); - - int oscillationCount; - double lastTime; - - void doStep() { - boolean f = calcFunction(); - if (isInverting()) - f = !f; - - if (lastTime != sim.t) { - // detect oscillation (using same strategy as Atanua) - if (lastOutput == !f) { - if (oscillationCount++ > 50) { - // output is oscillating too much, randomly leave output the same - oscillationCount = 0; - if (sim.getrand(10) > 5) - f = lastOutput; - } - } else + setVoltageColor(g, volts[inputCount]); + drawThickLine(g, lead2, point2); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + if (useEuroGates()) { + drawThickPolygon(g, gatePoly); + Point center = interpPoint(point1, point2, .5); + drawCenteredText(g, getGateText(), center.x, center.y - 6 * gsize, true); + } else + drawGatePolygon(g); + g.setLineWidth(2); + if (hasSchmittInputs()) + drawPolygon(g, schmittPoly); + g.setLineWidth(1); + if (linePoints != null) + for (i = 0; i != linePoints.length - 1; i++) + drawThickLine(g, linePoints[i], linePoints[i + 1]); + if (isInverting()) + drawThickCircle(g, pcircle.x, pcircle.y, 3); + if (icircles != null) + for (i = 0; i != inputCount; i++) + drawThickCircle(g, icircles[i].x, icircles[i].y, 3); + curcount = updateDotCount(current, curcount); + drawDots(g, lead2, point2, curcount); + drawPosts(g); + } + + Polygon gatePoly, schmittPoly; + Point pcircle, linePoints[], icircles[]; + + int getPostCount() { + return inputCount + 1; + } + + Point getPost(int n) { + if (n == inputCount) + return point2; + return inPosts[n]; + } + + int getVoltageSourceCount() { + return 1; + } + + abstract String getGateName(); + + void getInfo(String arr[]) { + arr[0] = getGateName(); + arr[1] = "Vout = " + getVoltageText(volts[inputCount]); + arr[2] = "Iout = " + getCurrentText(getCurrent()); + } + + void stamp() { + sim.stampVoltageSource(0, nodes[inputCount], voltSource); + } + + boolean hasSchmittInputs() { + return (flags & FLAG_SCHMITT) != 0; + } + + boolean getInput(int x) { + boolean high = !hasFlag(FLAG_INVERT_INPUTS); + if (!hasSchmittInputs()) + return (volts[x] > highVoltage * .5) ? high : !high; + boolean res = volts[x] > highVoltage * (inputStates[x] ? .35 : .55); + inputStates[x] = res ? high : !high; + return res; + } + + abstract boolean calcFunction(); + + int oscillationCount; + double lastTime; + + void doStep() { + boolean f = calcFunction(); + if (isInverting()) + f = !f; + + if (lastTime != sim.t) { + // detect oscillation (using same strategy as Atanua) + if (lastOutput == !f) { + if (oscillationCount++ > 50) { + // output is oscillating too much, randomly leave output the same oscillationCount = 0; - - lastOutput = f; - lastTime = sim.t; - } - - double res = f ? highVoltage : 0; - sim.updateVoltageSource(0, nodes[inputCount], voltSource, res); - } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("# of Inputs", inputCount, 1, 8). - setDimensionless(); - if (n == 1) - return new EditInfo("High Logic Voltage", highVoltage, 1, 10); - if (n == 2) - return EditInfo.createCheckbox("Schmitt Inputs", hasSchmittInputs()); - if (n == 3) - return EditInfo.createCheckbox("Invert Inputs", hasFlag(FLAG_INVERT_INPUTS)); - return null; + if (sim.getrand(10) > 5) + f = lastOutput; + } + } else + oscillationCount = 0; + + lastOutput = f; + lastTime = sim.t; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value >= 1) { - inputCount = (int) ei.value; - setPoints(); - } - if (n == 1) - highVoltage = lastHighVoltage = ei.value; - if (n == 2) { - if (ei.checkbox.getState()) - flags |= FLAG_SCHMITT; - else - flags &= ~FLAG_SCHMITT; - lastSchmitt = hasSchmittInputs(); - setPoints(); - } - if (n == 3) { - flags = ei.changeFlag(flags, FLAG_INVERT_INPUTS); - setPoints(); - } + double res = f ? highVoltage : 0; + sim.updateVoltageSource(0, nodes[inputCount], voltSource, res); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("# of Inputs", inputCount, 1, 8).setDimensionless(); + if (n == 1) + return new EditInfo("High Logic Voltage", highVoltage, 1, 10); + if (n == 2) + return EditInfo.createCheckbox("Schmitt Inputs", hasSchmittInputs()); + if (n == 3) + return EditInfo.createCheckbox("Invert Inputs", hasFlag(FLAG_INVERT_INPUTS)); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value >= 1) { + inputCount = (int) ei.value; + setPoints(); } - // there is no current path through the gate inputs, but there - // is an indirect path through the output to ground. - boolean getConnection(int n1, int n2) { return false; } - boolean hasGroundConnection(int n1) { - return (n1 == inputCount); + if (n == 1) + highVoltage = lastHighVoltage = ei.value; + if (n == 2) { + if (ei.checkbox.getState()) + flags |= FLAG_SCHMITT; + else + flags &= ~FLAG_SCHMITT; + lastSchmitt = hasSchmittInputs(); + setPoints(); } - - double getCurrentIntoNode(int n) { - if (n == inputCount) - return current; - return 0; + if (n == 3) { + flags = ei.changeFlag(flags, FLAG_INVERT_INPUTS); + setPoints(); } } + // there is no current path through the gate inputs, but there + // is an indirect path through the output to ground. + boolean getConnection(int n1, int n2) { + return false; + } + + boolean hasGroundConnection(int n1) { + return (n1 == inputCount); + } + + double getCurrentIntoNode(int n) { + if (n == inputCount) + return current; + return 0; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/GraphicElm.java b/src/com/lushprojects/circuitjs1/client/GraphicElm.java index 591f5646..c811a34f 100644 --- a/src/com/lushprojects/circuitjs1/client/GraphicElm.java +++ b/src/com/lushprojects/circuitjs1/client/GraphicElm.java @@ -19,19 +19,17 @@ package com.lushprojects.circuitjs1.client; -class GraphicElm extends CircuitElm -{ +class GraphicElm extends CircuitElm { - public GraphicElm(int xx, int yy) - { - super(xx,yy); + public GraphicElm(int xx, int yy) { + super(xx, yy); } - public GraphicElm(int xa, int ya, int xb, int yb, int flags) - { + public GraphicElm(int xa, int ya, int xb, int yb, int flags) { super(xa, ya, xb, yb, flags); } - int getPostCount() { return 0; } + int getPostCount() { + return 0; + } } - diff --git a/src/com/lushprojects/circuitjs1/client/Graphics.java b/src/com/lushprojects/circuitjs1/client/Graphics.java index bae063d0..66f6ef73 100644 --- a/src/com/lushprojects/circuitjs1/client/Graphics.java +++ b/src/com/lushprojects/circuitjs1/client/Graphics.java @@ -22,166 +22,165 @@ import com.google.gwt.canvas.dom.client.Context2d; public class Graphics { - - Context2d context; - int currentFontSize; - Color lastColor; - int savedFontSize; - static boolean isFullScreen=false; - - public Graphics(Context2d context) { - this.context = context; - } - - public void setColor(Color color) { - if (color != null) { - String colorString = color.getHexValue(); - context.setStrokeStyle(colorString); - context.setFillStyle(colorString); - } else { - System.out.println("Ignoring null-Color"); - } - lastColor=color; - } - - public void setColor(String color) { - context.setStrokeStyle(color); - context.setFillStyle(color); - lastColor=null; - } - - public void clipRect(int x, int y, int width, int height) { - context.beginPath(); - context.rect(x, y, width, height); - context.clip(); - } - - public void restore() { - context.restore(); - currentFontSize = savedFontSize; - } - public void save() { - context.save(); - savedFontSize = currentFontSize; - } - - - public void fillRect(int x, int y, int width, int height) { - // context.beginPath(); - context.fillRect(x, y, width, height); - // context.closePath(); - } - - public void drawRect(int x, int y, int width, int height) { - // context.beginPath(); - context.strokeRect(x, y, width, height); - // context.closePath(); - } - - public void fillOval(int x, int y, int width, int height) { - context.beginPath(); - context.arc(x+width/2, y+width/2, width/2, 0, 2.0*3.14159); - context.closePath(); - context.fill(); - } - - public void drawString(String s, int x, int y){ - context.fillText(s, x, y); - } - - public double measureWidth(String s) { - return context.measureText(s).getWidth(); - } - - public void setLineWidth(double width){ - context.setLineWidth(width); - } - - public void drawLine(int x1, int y1, int x2, int y2) { - context.beginPath(); - context.moveTo(x1, y1); - context.lineTo(x2, y2); - context.stroke(); - // context.closePath(); - } - - public void drawPolyline(int[] xpoints, int[] ypoints, int n) { - int i; - context.beginPath(); - for (i=0; i", "\r"); - s=textArea.getText(); - sim.importCircuitFromText(s, subCheck.getState()); - } - }); - hp.add(cancelButton = new Button(Locale.LS("Cancel"))); - cancelButton.addClickHandler(new ClickHandler() { - public void onClick(ClickEvent event) { - closeDialog(); - } - }); - this.center(); - show(); - } + + VerticalPanel vp; + HorizontalPanel hp; + CirSim sim; + // RichTextArea textBox; + TextArea textArea; + + public ImportFromTextDialog(CirSim asim) { + super(); + sim = asim; + closeOnEnter = false; + Button okButton, cancelButton; + final Checkbox subCheck; + vp = new VerticalPanel(); + setWidget(vp); + setText(Locale.LS("Import from Text")); + vp.add(new Label(Locale.LS("Paste the text file for your circuit here..."))); + // vp.add(textBox = new RichTextArea()); + vp.add(textArea = new TextArea()); + textArea.setWidth("300px"); + textArea.setHeight("200px"); + vp.add(subCheck = new Checkbox(Locale.LS("Load Subcircuits Only"))); + hp = new HorizontalPanel(); + vp.add(hp); + hp.add(okButton = new Button(Locale.LS("OK"))); + okButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + String s; + sim.pushUndo(); + closeDialog(); + // s=textBox.getHTML(); + // s=s.replace("
", "\r"); + s = textArea.getText(); + sim.importCircuitFromText(s, subCheck.getState()); + } + }); + hp.add(cancelButton = new Button(Locale.LS("Cancel"))); + cancelButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + closeDialog(); + } + }); + this.center(); + show(); + } } diff --git a/src/com/lushprojects/circuitjs1/client/Inductor.java b/src/com/lushprojects/circuitjs1/client/Inductor.java index 6379aa15..e9a39e8b 100644 --- a/src/com/lushprojects/circuitjs1/client/Inductor.java +++ b/src/com/lushprojects/circuitjs1/client/Inductor.java @@ -24,60 +24,76 @@ class Inductor { int nodes[]; int flags; CirSim sim; - + double inductance; double compResistance, current; double curSourceValue; + Inductor(CirSim s) { sim = s; nodes = new int[2]; } + void setup(double ic, double cr, int f) { inductance = ic; current = cr; flags = f; } - boolean isTrapezoidal() { return (flags & FLAG_BACK_EULER) == 0; } - void reset() { resetTo(0); } + + boolean isTrapezoidal() { + return (flags & FLAG_BACK_EULER) == 0; + } + + void reset() { + resetTo(0); + } + void resetTo(double c) { - // need to set curSourceValue here in case one of inductor nodes is node 0. In that case - // calculateCurrent() may get called (from setNodeVoltage()) when analyzing circuit, before + // need to set curSourceValue here in case one of inductor nodes is node 0. In + // that case + // calculateCurrent() may get called (from setNodeVoltage()) when analyzing + // circuit, before // startIteration() gets called curSourceValue = current = c; } + void stamp(int n0, int n1) { // inductor companion model using trapezoidal or backward euler // approximations (Norton equivalent) consists of a current - // source in parallel with a resistor. Trapezoidal is more + // source in parallel with a resistor. Trapezoidal is more // accurate than backward euler but can cause oscillatory behavior. // The oscillation is a real problem in circuits with switches. nodes[0] = n0; nodes[1] = n1; if (isTrapezoidal()) - compResistance = 2*inductance/sim.timeStep; + compResistance = 2 * inductance / sim.timeStep; else // backward euler - compResistance = inductance/sim.timeStep; + compResistance = inductance / sim.timeStep; sim.stampResistor(nodes[0], nodes[1], compResistance); sim.stampRightSide(nodes[0]); sim.stampRightSide(nodes[1]); } - boolean nonLinear() { return false; } + + boolean nonLinear() { + return false; + } void startIteration(double voltdiff) { if (isTrapezoidal()) - curSourceValue = voltdiff/compResistance+current; + curSourceValue = voltdiff / compResistance + current; else // backward euler curSourceValue = current; } - + double calculateCurrent(double voltdiff) { // we check compResistance because this might get called // before stamp(), which sets compResistance, causing // infinite current if (compResistance > 0) - current = voltdiff/compResistance + curSourceValue; + current = voltdiff / compResistance + curSourceValue; return current; } + void doStep(double voltdiff) { sim.stampCurrentSource(nodes[0], nodes[1], curSourceValue); } diff --git a/src/com/lushprojects/circuitjs1/client/InductorElm.java b/src/com/lushprojects/circuitjs1/client/InductorElm.java index 28084225..2b1ebf13 100644 --- a/src/com/lushprojects/circuitjs1/client/InductorElm.java +++ b/src/com/lushprojects/circuitjs1/client/InductorElm.java @@ -19,107 +19,132 @@ package com.lushprojects.circuitjs1.client; - class InductorElm extends CircuitElm { - Inductor ind; - double inductance; - double initialCurrent; - public InductorElm(int xx, int yy) { - super(xx, yy); - ind = new Inductor(sim); - inductance = 1; - ind.setup(inductance, current, flags); - } - public InductorElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - ind = new Inductor(sim); - inductance = new Double(st.nextToken()).doubleValue(); - current = new Double(st.nextToken()).doubleValue(); - try { - initialCurrent = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) {} - ind.setup(inductance, current, flags); - } - int getDumpType() { return 'l'; } - String dump() { - return super.dump() + " " + inductance + " " + current + " " + initialCurrent; - } - void setPoints() { - super.setPoints(); - calcLeads(32); - } - void draw(Graphics g) { - double v1 = volts[0]; - double v2 = volts[1]; - int i; - int hs = 8; - setBbox(point1, point2, hs); - draw2Leads(g); - setPowerColor(g, false); - drawCoil(g, 8, lead1, lead2, v1, v2); - if (sim.showValuesCheckItem.getState()) { - String s = getShortUnitText(inductance, "H"); - drawValues(g, s, hs); - } - doDots(g); - drawPosts(g); - } - void reset() { - volts[0] = volts[1] = curcount = 0; - current = initialCurrent; - ind.resetTo(initialCurrent); - } - void stamp() { ind.stamp(nodes[0], nodes[1]); } - void startIteration() { - ind.startIteration(volts[0]-volts[1]); - } - boolean nonLinear() { return ind.nonLinear(); } - void calculateCurrent() { - double voltdiff = volts[0]-volts[1]; - current = ind.calculateCurrent(voltdiff); - } - void doStep() { - double voltdiff = volts[0]-volts[1]; - ind.doStep(voltdiff); - } - void getInfo(String arr[]) { - arr[0] = "inductor"; - getBasicInfo(arr); - arr[3] = "L = " + getUnitText(inductance, "H"); - arr[4] = "P = " + getUnitText(getPower(), "W"); +class InductorElm extends CircuitElm { + Inductor ind; + double inductance; + double initialCurrent; + + public InductorElm(int xx, int yy) { + super(xx, yy); + ind = new Inductor(sim); + inductance = 1; + ind.setup(inductance, current, flags); + } + + public InductorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + ind = new Inductor(sim); + inductance = Double.valueOf(st.nextToken()).doubleValue(); + current = Double.valueOf(st.nextToken()).doubleValue(); + try { + initialCurrent = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Inductance (H)", inductance, 1e-2, 10); - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Trapezoidal Approximation", - ind.isTrapezoidal()); - return ei; - } - if (n == 2) - return new EditInfo("Initial Current (on Reset) (A)", initialCurrent); - return null; + ind.setup(inductance, current, flags); + } + + int getDumpType() { + return 'l'; + } + + String dump() { + return super.dump() + " " + inductance + " " + current + " " + initialCurrent; + } + + void setPoints() { + super.setPoints(); + calcLeads(32); + } + + void draw(Graphics g) { + double v1 = volts[0]; + double v2 = volts[1]; + int i; + int hs = 8; + setBbox(point1, point2, hs); + draw2Leads(g); + setPowerColor(g, false); + drawCoil(g, 8, lead1, lead2, v1, v2); + if (sim.showValuesCheckItem.getState()) { + String s = getShortUnitText(inductance, "H"); + drawValues(g, s, hs); } - - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) - inductance = ei.value; - if (n == 1) { - if (ei.checkbox.getState()) - flags &= ~Inductor.FLAG_BACK_EULER; - else - flags |= Inductor.FLAG_BACK_EULER; - } - if (n == 2) - initialCurrent = ei.value; - ind.setup(inductance, current, flags); + doDots(g); + drawPosts(g); + } + + void reset() { + volts[0] = volts[1] = curcount = 0; + current = initialCurrent; + ind.resetTo(initialCurrent); + } + + void stamp() { + ind.stamp(nodes[0], nodes[1]); + } + + void startIteration() { + ind.startIteration(volts[0] - volts[1]); + } + + boolean nonLinear() { + return ind.nonLinear(); + } + + void calculateCurrent() { + double voltdiff = volts[0] - volts[1]; + current = ind.calculateCurrent(voltdiff); + } + + void doStep() { + double voltdiff = volts[0] - volts[1]; + ind.doStep(voltdiff); + } + + void getInfo(String arr[]) { + arr[0] = "inductor"; + getBasicInfo(arr); + arr[3] = "L = " + getUnitText(inductance, "H"); + arr[4] = "P = " + getUnitText(getPower(), "W"); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Inductance (H)", inductance, 1e-2, 10); + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Trapezoidal Approximation", ind.isTrapezoidal()); + return ei; } - - int getShortcut() { return 'L'; } - public double getInductance() { return inductance; } - void setInductance(double l) { - inductance = l; - ind.setup(inductance, current, flags); + if (n == 2) + return new EditInfo("Initial Current (on Reset) (A)", initialCurrent); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) + inductance = ei.value; + if (n == 1) { + if (ei.checkbox.getState()) + flags &= ~Inductor.FLAG_BACK_EULER; + else + flags |= Inductor.FLAG_BACK_EULER; } + if (n == 2) + initialCurrent = ei.value; + ind.setup(inductance, current, flags); + } + + int getShortcut() { + return 'L'; + } + + public double getInductance() { + return inductance; + } + + void setInductance(double l) { + inductance = l; + ind.setup(inductance, current, flags); } +} diff --git a/src/com/lushprojects/circuitjs1/client/InverterElm.java b/src/com/lushprojects/circuitjs1/client/InverterElm.java index 91ded4ee..6b5972c8 100644 --- a/src/com/lushprojects/circuitjs1/client/InverterElm.java +++ b/src/com/lushprojects/circuitjs1/client/InverterElm.java @@ -19,122 +19,147 @@ package com.lushprojects.circuitjs1.client; - class InverterElm extends CircuitElm { - double slewRate; // V/ns - double highVoltage; - public InverterElm(int xx, int yy) { - super(xx, yy); - noDiagonal = true; - slewRate = .5; - - // copy defaults from last gate edited - highVoltage = GateElm.lastHighVoltage; - } - public InverterElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - noDiagonal = true; - slewRate = .5; - highVoltage = 5; - try { - slewRate = new Double (st.nextToken()).doubleValue(); - highVoltage = new Double (st.nextToken()).doubleValue(); - } catch (Exception e) { - } - } - String dump() { - return super.dump() + " " + slewRate + " " + highVoltage; - } - - int getDumpType() { return 'I'; } - - Point center; - - void draw(Graphics g) { - drawPosts(g); - draw2Leads(g); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - drawThickPolygon(g, gatePoly); - if (GateElm.useEuroGates()) - drawCenteredText(g, "1", center.x, center.y-6, true); - drawThickCircle(g, pcircle.x, pcircle.y, 3); - curcount = updateDotCount(current, curcount); - drawDots(g, lead2, point2, curcount); - } - Polygon gatePoly; - Point pcircle; - void setPoints() { - super.setPoints(); - int hs = 16; - int ww = 16; - if (ww > dn/2) - ww = (int) (dn/2); - lead1 = interpPoint(point1, point2, .5-ww/dn); - lead2 = interpPoint(point1, point2, .5+(ww+2)/dn); - pcircle = interpPoint(point1, point2, .5+(ww-2)/dn); - - if (GateElm.useEuroGates()) { - Point pts[] = newPointArray(4); - Point l2 = interpPoint(point1, point2, .5+(ww-5)/dn); // make room for circle - interpPoint2(lead1, l2, pts[0], pts[1], 0, hs); - interpPoint2(lead1, l2, pts[3], pts[2], 1, hs); - gatePoly = createPolygon(pts); - center = interpPoint(lead1, l2, .5); - } else { - Point triPoints[] = newPointArray(3); - interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); - triPoints[2] = interpPoint(point1, point2, .5+(ww-5)/dn); - gatePoly = createPolygon(triPoints); - } - setBbox(point1, point2, hs); - } - int getVoltageSourceCount() { return 1; } - void stamp() { - sim.stampVoltageSource(0, nodes[1], voltSource); - } - - double lastOutputVoltage; - - void startIteration() { - lastOutputVoltage = volts[1]; - } - void doStep() { - double out = volts[0] > highVoltage*.5 ? 0 : highVoltage; - double maxStep = slewRate * sim.timeStep * 1e9; - out = Math.max(Math.min(lastOutputVoltage+maxStep, out), lastOutputVoltage-maxStep); - sim.updateVoltageSource(0, nodes[1], voltSource, out); - } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = "inverter"; - arr[1] = "Vi = " + getVoltageText(volts[0]); - arr[2] = "Vo = " + getVoltageText(volts[1]); - } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Slew Rate (V/ns)", slewRate, 0, 0); - if (n == 1) - return new EditInfo("High Logic Voltage", highVoltage, 1, 10); - return null; - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - slewRate = ei.value; - if (n == 1) - highVoltage = GateElm.lastHighVoltage = ei.value; - } - // there is no current path through the inverter input, but there - // is an indirect path through the output to ground. - boolean getConnection(int n1, int n2) { return false; } - boolean hasGroundConnection(int n1) { - return (n1 == 1); +class InverterElm extends CircuitElm { + double slewRate; // V/ns + double highVoltage; + + public InverterElm(int xx, int yy) { + super(xx, yy); + noDiagonal = true; + slewRate = .5; + + // copy defaults from last gate edited + highVoltage = GateElm.lastHighVoltage; + } + + public InverterElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + noDiagonal = true; + slewRate = .5; + highVoltage = 5; + try { + slewRate = Double.valueOf(st.nextToken()).doubleValue(); + highVoltage = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } - int getShortcut() { return '1'; } - - @Override double getCurrentIntoNode(int n) { - if (n == 1) - return current; - return 0; + } + + String dump() { + return super.dump() + " " + slewRate + " " + highVoltage; + } + + int getDumpType() { + return 'I'; + } + + Point center; + + void draw(Graphics g) { + drawPosts(g); + draw2Leads(g); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickPolygon(g, gatePoly); + if (GateElm.useEuroGates()) + drawCenteredText(g, "1", center.x, center.y - 6, true); + drawThickCircle(g, pcircle.x, pcircle.y, 3); + curcount = updateDotCount(current, curcount); + drawDots(g, lead2, point2, curcount); + } + + Polygon gatePoly; + Point pcircle; + + void setPoints() { + super.setPoints(); + int hs = 16; + int ww = 16; + if (ww > dn / 2) + ww = (int) (dn / 2); + lead1 = interpPoint(point1, point2, .5 - ww / dn); + lead2 = interpPoint(point1, point2, .5 + (ww + 2) / dn); + pcircle = interpPoint(point1, point2, .5 + (ww - 2) / dn); + + if (GateElm.useEuroGates()) { + Point pts[] = newPointArray(4); + Point l2 = interpPoint(point1, point2, .5 + (ww - 5) / dn); // make room for circle + interpPoint2(lead1, l2, pts[0], pts[1], 0, hs); + interpPoint2(lead1, l2, pts[3], pts[2], 1, hs); + gatePoly = createPolygon(pts); + center = interpPoint(lead1, l2, .5); + } else { + Point triPoints[] = newPointArray(3); + interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); + triPoints[2] = interpPoint(point1, point2, .5 + (ww - 5) / dn); + gatePoly = createPolygon(triPoints); } + setBbox(point1, point2, hs); + } + + int getVoltageSourceCount() { + return 1; + } + void stamp() { + sim.stampVoltageSource(0, nodes[1], voltSource); } + + double lastOutputVoltage; + + void startIteration() { + lastOutputVoltage = volts[1]; + } + + void doStep() { + double out = volts[0] > highVoltage * .5 ? 0 : highVoltage; + double maxStep = slewRate * sim.timeStep * 1e9; + out = Math.max(Math.min(lastOutputVoltage + maxStep, out), lastOutputVoltage - maxStep); + sim.updateVoltageSource(0, nodes[1], voltSource, out); + } + + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "inverter"; + arr[1] = "Vi = " + getVoltageText(volts[0]); + arr[2] = "Vo = " + getVoltageText(volts[1]); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Slew Rate (V/ns)", slewRate, 0, 0); + if (n == 1) + return new EditInfo("High Logic Voltage", highVoltage, 1, 10); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + slewRate = ei.value; + if (n == 1) + highVoltage = GateElm.lastHighVoltage = ei.value; + } + + // there is no current path through the inverter input, but there + // is an indirect path through the output to ground. + boolean getConnection(int n1, int n2) { + return false; + } + + boolean hasGroundConnection(int n1) { + return (n1 == 1); + } + + int getShortcut() { + return '1'; + } + + @Override + double getCurrentIntoNode(int n) { + if (n == 1) + return current; + return 0; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/InvertingSchmittElm.java b/src/com/lushprojects/circuitjs1/client/InvertingSchmittElm.java index 5b78dee1..6b51f0a2 100644 --- a/src/com/lushprojects/circuitjs1/client/InvertingSchmittElm.java +++ b/src/com/lushprojects/circuitjs1/client/InvertingSchmittElm.java @@ -21,183 +21,191 @@ // contributed by Edward Calver - class InvertingSchmittElm extends CircuitElm { - double slewRate; // V/ns - double lowerTrigger; - double upperTrigger; - boolean state; - double logicOnLevel; - double logicOffLevel; - - public InvertingSchmittElm(int xx, int yy) { - super(xx, yy); - noDiagonal = true; - slewRate = .5; - state=false; - lowerTrigger=1.66; - upperTrigger=3.33; - logicOnLevel = 5; - logicOffLevel = 0; +class InvertingSchmittElm extends CircuitElm { + double slewRate; // V/ns + double lowerTrigger; + double upperTrigger; + boolean state; + double logicOnLevel; + double logicOffLevel; + + public InvertingSchmittElm(int xx, int yy) { + super(xx, yy); + noDiagonal = true; + slewRate = .5; + state = false; + lowerTrigger = 1.66; + upperTrigger = 3.33; + logicOnLevel = 5; + logicOffLevel = 0; + } + + public InvertingSchmittElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + noDiagonal = true; + slewRate = .5; + lowerTrigger = 1.66; + upperTrigger = 3.33; + logicOnLevel = 5; + logicOffLevel = 0; + try { + slewRate = Double.valueOf(st.nextToken()).doubleValue(); + lowerTrigger = Double.valueOf(st.nextToken()).doubleValue(); + upperTrigger = Double.valueOf(st.nextToken()).doubleValue(); + logicOnLevel = Double.valueOf(st.nextToken()).doubleValue(); + logicOffLevel = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } + } + + String dump() { + return super.dump() + " " + slewRate + " " + lowerTrigger + " " + upperTrigger + " " + logicOnLevel + " " + + logicOffLevel; + } + + int getDumpType() { + return 183; + }// Trying to find unused type + + void draw(Graphics g) { + drawPosts(g); + draw2Leads(g); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickPolygon(g, gatePoly); + g.setLineWidth(2); + drawPolygon(g, symbolPoly); + g.setLineWidth(1); + ; + drawThickCircle(g, pcircle.x, pcircle.y, 3); + curcount = updateDotCount(current, curcount); + drawDots(g, lead2, point2, curcount); + } + + Polygon gatePoly; + Polygon symbolPoly; + Point pcircle; + + void setPoints() { + super.setPoints(); + int hs = 16; + int ww = 16; + if (ww > dn / 2) + ww = (int) (dn / 2); + lead1 = interpPoint(point1, point2, .5 - ww / dn); + lead2 = interpPoint(point1, point2, .5 + (ww + 2) / dn); + pcircle = interpPoint(point1, point2, .5 + (ww - 2) / dn); + Point triPoints[] = newPointArray(3); + interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); + triPoints[2] = interpPoint(point1, point2, .5 + (ww - 5) / dn); - public InvertingSchmittElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - noDiagonal = true; - slewRate = .5; - lowerTrigger=1.66; - upperTrigger=3.33; - logicOnLevel = 5; - logicOffLevel = 0; - try { - slewRate = new Double (st.nextToken()).doubleValue(); - lowerTrigger = new Double (st.nextToken()).doubleValue(); - upperTrigger = new Double (st.nextToken()).doubleValue(); - logicOnLevel = new Double (st.nextToken()).doubleValue(); - logicOffLevel = new Double (st.nextToken()).doubleValue(); - } catch (Exception e) { + gatePoly = createPolygon(triPoints); + symbolPoly = getSchmittPolygon(1, .3f); + setBbox(point1, point2, hs); + } + + int getVoltageSourceCount() { + return 1; + } + + void stamp() { + sim.stampVoltageSource(0, nodes[1], voltSource); + } + + void doStep() { + double v0 = volts[1]; + double out; + if (state) {// Output is high + if (volts[0] > upperTrigger)// Input voltage high enough to set output low + { + state = false; + out = logicOffLevel; + } else { + out = logicOnLevel; + } + } else {// Output is low + if (volts[0] < lowerTrigger)// Input voltage low enough to set output high + { + state = true; + out = logicOnLevel; + } else { + out = logicOffLevel; } } - String dump() { - return super.dump() + " " + slewRate+" "+lowerTrigger+" "+upperTrigger+" "+logicOnLevel+" "+logicOffLevel; - } - - int getDumpType() { return 183; }//Trying to find unused type - - void draw(Graphics g) { - drawPosts(g); - draw2Leads(g); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - drawThickPolygon(g, gatePoly); - g.setLineWidth(2); - drawPolygon(g, symbolPoly); - g.setLineWidth(1);; - drawThickCircle(g, pcircle.x, pcircle.y, 3); - curcount = updateDotCount(current, curcount); - drawDots(g, lead2, point2, curcount); - } - Polygon gatePoly; - Polygon symbolPoly; - Point pcircle; - void setPoints() { - super.setPoints(); - int hs = 16; - int ww = 16; - if (ww > dn/2) - ww = (int) (dn/2); - lead1 = interpPoint(point1, point2, .5-ww/dn); - lead2 = interpPoint(point1, point2, .5+(ww+2)/dn); - pcircle = interpPoint(point1, point2, .5+(ww-2)/dn); - Point triPoints[] = newPointArray(3); - interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); - triPoints[2] = interpPoint(point1, point2, .5+(ww-5)/dn); - - gatePoly = createPolygon(triPoints); - symbolPoly = getSchmittPolygon(1, .3f); - setBbox(point1, point2, hs); - } - int getVoltageSourceCount() { return 1; } - void stamp() { - sim.stampVoltageSource(0, nodes[1], voltSource); - } - void doStep() { - double v0 = volts[1]; - double out; - if(state) - {//Output is high - if(volts[0]>upperTrigger)//Input voltage high enough to set output low - { - state=false; - out=logicOffLevel; - } - else - { - out=logicOnLevel; - } - } - else - {//Output is low - if(volts[0]dut) - { - upperTrigger=dlt; - lowerTrigger=dut; - } - else - { - upperTrigger=dut; - lowerTrigger=dlt; - } + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "inverting Schmitt trigger"; + arr[1] = "Vi = " + getVoltageText(volts[0]); + arr[2] = "Vo = " + getVoltageText(volts[1]); + } + public EditInfo getEditInfo(int n) { + if (n == 0) { + dlt = lowerTrigger; + return new EditInfo("Lower threshold (V)", lowerTrigger, 0.01, 5); } - // there is no current path through the InvertingSchmitt input, but there - // is an indirect path through the output to ground. - boolean getConnection(int n1, int n2) { return false; } - boolean hasGroundConnection(int n1) { - return (n1 == 1); + if (n == 1) { + dut = upperTrigger; + return new EditInfo("Upper threshold (V)", upperTrigger, 0.01, 5); } - - @Override double getCurrentIntoNode(int n) { - if (n == 1) - return current; - return 0; + if (n == 2) + return new EditInfo("Slew Rate (V/ns)", slewRate, 0, 0); + if (n == 3) + return new EditInfo("High Logic Voltage", logicOnLevel, 0, 0); + if (n == 4) + return new EditInfo("Low Voltage (V)", logicOffLevel, 0, 0); + + return null; + } + + double dlt; + double dut; + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + dlt = ei.value; + if (n == 1) + dut = ei.value; + if (n == 2) + slewRate = ei.value; + if (n == 3) + logicOnLevel = ei.value; + if (n == 4) + logicOffLevel = ei.value; + + if (dlt > dut) { + upperTrigger = dlt; + lowerTrigger = dut; + } else { + upperTrigger = dut; + lowerTrigger = dlt; } } + + // there is no current path through the InvertingSchmitt input, but there + // is an indirect path through the output to ground. + boolean getConnection(int n1, int n2) { + return false; + } + + boolean hasGroundConnection(int n1) { + return (n1 == 1); + } + + @Override + double getCurrentIntoNode(int n) { + if (n == 1) + return current; + return 0; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/JKFlipFlopElm.java b/src/com/lushprojects/circuitjs1/client/JKFlipFlopElm.java index 4ba22ad5..110d0e17 100644 --- a/src/com/lushprojects/circuitjs1/client/JKFlipFlopElm.java +++ b/src/com/lushprojects/circuitjs1/client/JKFlipFlopElm.java @@ -19,125 +19,150 @@ package com.lushprojects.circuitjs1.client; - class JKFlipFlopElm extends ChipElm { - final int FLAG_RESET = 2; - final int FLAG_POSITIVE_EDGE = 4; - final int FLAG_INVERT_RESET = 8; - boolean hasReset(){return (flags & FLAG_RESET)!= 0;} - boolean positiveEdgeTriggered() { return (flags & FLAG_POSITIVE_EDGE) != 0; } - boolean invertReset() { return (flags & FLAG_INVERT_RESET) != 0; } - public JKFlipFlopElm(int xx, int yy) { super(xx, yy); } - public JKFlipFlopElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - pins[4].value = !pins[3].value; - justLoaded = true; +class JKFlipFlopElm extends ChipElm { + final int FLAG_RESET = 2; + final int FLAG_POSITIVE_EDGE = 4; + final int FLAG_INVERT_RESET = 8; + + boolean hasReset() { + return (flags & FLAG_RESET) != 0; + } + + boolean positiveEdgeTriggered() { + return (flags & FLAG_POSITIVE_EDGE) != 0; + } + + boolean invertReset() { + return (flags & FLAG_INVERT_RESET) != 0; + } + + public JKFlipFlopElm(int xx, int yy) { + super(xx, yy); + } + + public JKFlipFlopElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + pins[4].value = !pins[3].value; + justLoaded = true; + } + + String getChipName() { + return "JK flip-flop"; + } + + void setupPins() { + sizeX = 2; + sizeY = 3; + pins = new Pin[getPostCount()]; + pins[0] = new Pin(0, SIDE_W, "J"); + pins[1] = new Pin(1, SIDE_W, ""); + pins[1].clock = true; + pins[1].bubble = !positiveEdgeTriggered(); + pins[2] = new Pin(2, SIDE_W, "K"); + pins[3] = new Pin(0, SIDE_E, "Q"); + pins[3].output = pins[3].state = true; + pins[4] = new Pin(2, SIDE_E, "Q"); + pins[4].output = true; + pins[4].lineOver = true; + + if (hasReset()) { + pins[5] = new Pin(1, SIDE_E, "R"); + pins[5].bubble = invertReset(); } - String getChipName() { return "JK flip-flop"; } - void setupPins() { - sizeX = 2; - sizeY = 3; - pins = new Pin[getPostCount()]; - pins[0] = new Pin(0, SIDE_W, "J"); - pins[1] = new Pin(1, SIDE_W, ""); - pins[1].clock = true; - pins[1].bubble = !positiveEdgeTriggered(); - pins[2] = new Pin(2, SIDE_W, "K"); - pins[3] = new Pin(0, SIDE_E, "Q"); - pins[3].output = pins[3].state = true; - pins[4] = new Pin(2, SIDE_E, "Q"); - pins[4].output = true; - pins[4].lineOver = true; - - if(hasReset()){ - pins[5] = new Pin(1, SIDE_E, "R"); - pins[5].bubble = invertReset(); - } + } + + int getPostCount() { + return 5 + (hasReset() ? 1 : 0); + } + + int getVoltageSourceCount() { + return 2; + } + + boolean justLoaded; + + void execute() { + // if we just loaded then the volts[] array is likely to be all zeroes, which + // might force us to do a reset, so defer execution until the next iteration + if (justLoaded) { + justLoaded = false; + return; } - int getPostCount() { return 5 + (hasReset() ? 1:0); } - int getVoltageSourceCount() { return 2; } - - boolean justLoaded; - - void execute() { - // if we just loaded then the volts[] array is likely to be all zeroes, which might force us to do a reset, so defer execution until the next iteration - if (justLoaded) { - justLoaded = false; - return; - } - - boolean transition; - if (positiveEdgeTriggered()) - transition = pins[1].value && !lastClock; - else - transition = !pins[1].value && lastClock; - if (transition) { - boolean q = pins[3].value; - if (pins[0].value) { - if (pins[2].value) - q = !q; - else - q = true; - } else if (pins[2].value) - q = false; - writeOutput(3, q); - } - lastClock = pins[1].value; - - if(hasReset()){ - if(pins[5].value != invertReset()) - writeOutput(3, false); + + boolean transition; + if (positiveEdgeTriggered()) + transition = pins[1].value && !lastClock; + else + transition = !pins[1].value && lastClock; + if (transition) { + boolean q = pins[3].value; + if (pins[0].value) { + if (pins[2].value) + q = !q; + else + q = true; + } else if (pins[2].value) + q = false; + writeOutput(3, q); + } + lastClock = pins[1].value; + + if (hasReset()) { + if (pins[5].value != invertReset()) + writeOutput(3, false); + } + + writeOutput(4, !pins[3].value); + } + + int getDumpType() { + return 156; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Reset Pin", hasReset()); + return ei; + } + + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Positive Edge Triggered", positiveEdgeTriggered()); + return ei; + } + + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Invert Reset", invertReset()); + return ei; + } + + return super.getChipEditInfo(n); + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0) { + if (ei.checkbox.getState()) { + flags |= FLAG_RESET; + } else { + flags &= ~FLAG_RESET; } - - writeOutput(4, !pins[3].value); + + setupPins(); + allocNodes(); + setPoints(); } - int getDumpType() { return 156; } - - public EditInfo getChipEditInfo(int n){ - if (n == 0){ - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Reset Pin", hasReset()); - return ei; - } - - if (n == 1){ - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Positive Edge Triggered", positiveEdgeTriggered()); - return ei; - } - - if (n == 2){ - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Invert Reset", invertReset()); - return ei; - } - - - return super.getChipEditInfo(n); + if (n == 1) { + flags = ei.changeFlag(flags, FLAG_POSITIVE_EDGE); + pins[1].bubble = !positiveEdgeTriggered(); } - - public void setChipEditValue(int n, EditInfo ei){ - if (n == 0){ - if(ei.checkbox.getState()){ - flags |= FLAG_RESET; - } else { - flags &= ~FLAG_RESET; - } - - setupPins(); - allocNodes(); - setPoints(); - } - if (n == 1) { - flags = ei.changeFlag(flags, FLAG_POSITIVE_EDGE); - pins[1].bubble = !positiveEdgeTriggered(); - } - if (n == 2) { - flags = ei.changeFlag(flags, FLAG_INVERT_RESET); - setupPins(); - setPoints(); - } - - super.setChipEditValue(n, ei); + if (n == 2) { + flags = ei.changeFlag(flags, FLAG_INVERT_RESET); + setupPins(); + setPoints(); } + + super.setChipEditValue(n, ei); } +} diff --git a/src/com/lushprojects/circuitjs1/client/JfetElm.java b/src/com/lushprojects/circuitjs1/client/JfetElm.java index ebcb212c..1288addd 100644 --- a/src/com/lushprojects/circuitjs1/client/JfetElm.java +++ b/src/com/lushprojects/circuitjs1/client/JfetElm.java @@ -22,130 +22,146 @@ import com.lushprojects.circuitjs1.client.util.Locale; class JfetElm extends MosfetElm { - Diode diode; - double gateCurrent; - - JfetElm(int xx, int yy, boolean pnpflag) { - super(xx, yy, pnpflag); - noDiagonal = true; - diode = new Diode(sim); - diode.setupForDefaultModel(); - } - public JfetElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - noDiagonal = true; - diode = new Diode(sim); - diode.setupForDefaultModel(); - } - - void reset() { - super.reset(); - diode.reset(); - } - - Polygon gatePoly; - Polygon arrowPoly; - Point gatePt; - double curcountg, curcounts, curcountd; - - void draw(Graphics g) { - setBbox(point1, point2, hs); - setVoltageColor(g, volts[1]); - drawThickLine(g, src[0], src[1]); - drawThickLine(g, src[1], src[2]); - setVoltageColor(g, volts[2]); - drawThickLine(g, drn[0], drn[1]); - drawThickLine(g, drn[1], drn[2]); - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, gatePt); - g.fillPolygon(arrowPoly); - setPowerColor(g, true); - g.fillPolygon(gatePoly); - curcountd = updateDotCount(-ids, curcountd); - curcountg = updateDotCount(gateCurrent, curcountg); - curcounts = updateDotCount(-gateCurrent-ids, curcounts); - if (curcountd != 0 || curcounts != 0) { - drawDots(g, src[0], src[1], curcounts); - drawDots(g, src[1], src[2], curcounts+8); - drawDots(g, drn[0], drn[1], -curcountd); - drawDots(g, drn[1], drn[2], -(curcountd+8)); - drawDots(g, point1, gatePt, curcountg); - } - drawPosts(g); - } - - double getCurrentIntoNode(int n) { - if (n == 0) - return -gateCurrent; - if (n == 1) - return gateCurrent+ids; - return -ids; - } - - void setPoints() { - super.setPoints(); - - // find the coordinates of the various points we need to draw - // the JFET. - int hs2 = hs*dsign; - src = newPointArray(3); - drn = newPointArray(3); - interpPoint2(point1, point2, src[0], drn[0], 1, -hs2); - interpPoint2(point1, point2, src[1], drn[1], 1, -hs2/2); - interpPoint2(point1, point2, src[2], drn[2], 1-10/dn, -hs2/2); - - gatePt = interpPoint(point1, point2, 1-14/dn); - - Point ra[] = newPointArray(4); - interpPoint2(point1, point2, ra[0], ra[1], 1-13/dn, hs); - interpPoint2(point1, point2, ra[2], ra[3], 1-10/dn, hs); - gatePoly = createPolygon(ra[0], ra[1], ra[3], ra[2]); - if (pnp == -1) { - Point x = interpPoint(gatePt, point1, 18/dn); - arrowPoly = calcArrow(gatePt, x, 8, 3); - } else - arrowPoly = calcArrow(point1, gatePt, 8, 3); - } - - void stamp() { - super.stamp(); - if (pnp < 0) - diode.stamp(nodes[1], nodes[0]); - else - diode.stamp(nodes[0], nodes[1]); - } - - void doStep() { - super.doStep(); - diode.doStep(pnp*(volts[0]-volts[1])); - } - - void calculateCurrent() { - gateCurrent = pnp*diode.calculateCurrent(pnp*(volts[0]-volts[1])); - } + Diode diode; + double gateCurrent; - boolean showBulk() { return false; } + JfetElm(int xx, int yy, boolean pnpflag) { + super(xx, yy, pnpflag); + noDiagonal = true; + diode = new Diode(sim); + diode.setupForDefaultModel(); + } - int getDumpType() { return 'j'; } - // these values are taken from Hayes+Horowitz p155 - double getDefaultThreshold() { return -4; } - double getDefaultBeta() { return .00125; } - double getBackwardCompatibilityBeta() { return getDefaultBeta(); } - void getInfo(String arr[]) { - getFetInfo(arr, "JFET"); - } - public EditInfo getEditInfo(int n) { - if (n < 2) - return super.getEditInfo(n); - return null; - } - - boolean getConnection(int n1, int n2) { - return true; - } + public JfetElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + noDiagonal = true; + diode = new Diode(sim); + diode.setupForDefaultModel(); + } - @Override String getScopeText(int v) { - return Locale.LS(((pnp == -1) ? "p-" : "n-") + "JFET"); + void reset() { + super.reset(); + diode.reset(); + } + + Polygon gatePoly; + Polygon arrowPoly; + Point gatePt; + double curcountg, curcounts, curcountd; + + void draw(Graphics g) { + setBbox(point1, point2, hs); + setVoltageColor(g, volts[1]); + drawThickLine(g, src[0], src[1]); + drawThickLine(g, src[1], src[2]); + setVoltageColor(g, volts[2]); + drawThickLine(g, drn[0], drn[1]); + drawThickLine(g, drn[1], drn[2]); + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, gatePt); + g.fillPolygon(arrowPoly); + setPowerColor(g, true); + g.fillPolygon(gatePoly); + curcountd = updateDotCount(-ids, curcountd); + curcountg = updateDotCount(gateCurrent, curcountg); + curcounts = updateDotCount(-gateCurrent - ids, curcounts); + if (curcountd != 0 || curcounts != 0) { + drawDots(g, src[0], src[1], curcounts); + drawDots(g, src[1], src[2], curcounts + 8); + drawDots(g, drn[0], drn[1], -curcountd); + drawDots(g, drn[1], drn[2], -(curcountd + 8)); + drawDots(g, point1, gatePt, curcountg); } + drawPosts(g); + } + + double getCurrentIntoNode(int n) { + if (n == 0) + return -gateCurrent; + if (n == 1) + return gateCurrent + ids; + return -ids; + } + + void setPoints() { + super.setPoints(); + + // find the coordinates of the various points we need to draw + // the JFET. + int hs2 = hs * dsign; + src = newPointArray(3); + drn = newPointArray(3); + interpPoint2(point1, point2, src[0], drn[0], 1, -hs2); + interpPoint2(point1, point2, src[1], drn[1], 1, -hs2 / 2); + interpPoint2(point1, point2, src[2], drn[2], 1 - 10 / dn, -hs2 / 2); + + gatePt = interpPoint(point1, point2, 1 - 14 / dn); + + Point ra[] = newPointArray(4); + interpPoint2(point1, point2, ra[0], ra[1], 1 - 13 / dn, hs); + interpPoint2(point1, point2, ra[2], ra[3], 1 - 10 / dn, hs); + gatePoly = createPolygon(ra[0], ra[1], ra[3], ra[2]); + if (pnp == -1) { + Point x = interpPoint(gatePt, point1, 18 / dn); + arrowPoly = calcArrow(gatePt, x, 8, 3); + } else + arrowPoly = calcArrow(point1, gatePt, 8, 3); + } + + void stamp() { + super.stamp(); + if (pnp < 0) + diode.stamp(nodes[1], nodes[0]); + else + diode.stamp(nodes[0], nodes[1]); + } + + void doStep() { + super.doStep(); + diode.doStep(pnp * (volts[0] - volts[1])); + } + + void calculateCurrent() { + gateCurrent = pnp * diode.calculateCurrent(pnp * (volts[0] - volts[1])); + } + + boolean showBulk() { + return false; + } + + int getDumpType() { + return 'j'; + } + + // these values are taken from Hayes+Horowitz p155 + double getDefaultThreshold() { + return -4; + } + + double getDefaultBeta() { + return .00125; + } + + double getBackwardCompatibilityBeta() { + return getDefaultBeta(); + } + + void getInfo(String arr[]) { + getFetInfo(arr, "JFET"); + } + + public EditInfo getEditInfo(int n) { + if (n < 2) + return super.getEditInfo(n); + return null; + } + + boolean getConnection(int n1, int n2) { + return true; + } + + @Override + String getScopeText(int v) { + return Locale.LS(((pnp == -1) ? "p-" : "n-") + "JFET"); } +} diff --git a/src/com/lushprojects/circuitjs1/client/LDRElm.java b/src/com/lushprojects/circuitjs1/client/LDRElm.java index d0c9626a..b6b81146 100644 --- a/src/com/lushprojects/circuitjs1/client/LDRElm.java +++ b/src/com/lushprojects/circuitjs1/client/LDRElm.java @@ -10,57 +10,62 @@ /*Bill Collis - June 2015 */ class LDRElm extends CircuitElm implements Command, MouseWheelHandler { - double position; //of the slider 0.005 to 0.995 - double resistance; //based upon slider position + double position; // of the slider 0.005 to 0.995 + double resistance; // based upon slider position double minLux, maxLux; double lux; - Scrollbar slider; + Scrollbar slider; Label label; String sliderText; - //constructor - when initially created + // constructor - when initially created public LDRElm(int xx, int yy) { super(xx, yy); - //setup(); - minLux = 0.1; //dark + // setup(); + minLux = 0.1; // dark maxLux = 10000; // sunlight - position = .34; + position = .34; lux = LuxFromSliderPos(); - resistance = calcResistance(lux); + resistance = calcResistance(lux); sliderText = "Light Brightness"; createSlider(); } - //constructor - when read in from file - public LDRElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + // constructor - when read in from file + public LDRElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - minLux = 0.1; //dark + minLux = 0.1; // dark maxLux = 10000; // sunlight - position = new Double(st.nextToken()).doubleValue(); + position = Double.valueOf(st.nextToken()).doubleValue(); lux = LuxFromSliderPos(); - resistance = calcResistance(lux); + resistance = calcResistance(lux); sliderText = CustomLogicModel.unescape(st.nextToken()); - createSlider(); //uses position to set the slider + createSlider(); // uses position to set the slider } - //void setup() { - //} + // void setup() { + // } - int getPostCount() { return 2; } - int getDumpType() { return 374; } //LDR + int getPostCount() { + return 2; + } + + int getDumpType() { + return 374; + } // LDR - //data for file saving - make sure it matches order of items in file input constructor - String dump() { - return super.dump() + " " + position + " " + CustomLogicModel.escape(sliderText); + // data for file saving - make sure it matches order of items in file input + // constructor + String dump() { + return super.dump() + " " + position + " " + CustomLogicModel.escape(sliderText); } void createSlider() { sim.addWidgetToVerticalPanel(label = new Label(sliderText)); label.addStyleName("topSpace"); - int value = (int) (position*100); + int value = (int) (position * 100); sim.addWidgetToVerticalPanel(slider = new Scrollbar(Scrollbar.HORIZONTAL, value, 1, 0, 101, this, this)); } @@ -73,94 +78,100 @@ void delete() { sim.removeWidgetFromVerticalPanel(label); sim.removeWidgetFromVerticalPanel(slider); } - Point ps3, ps4; - //called straight after constructor when txt file is loaded + Point ps3, ps4; + + // called straight after constructor when txt file is loaded void setPoints() { super.setPoints(); calcLeads(32); - position = slider.getValue()*.0099+.0001; + position = slider.getValue() * .0099 + .0001; lux = LuxFromSliderPos(); - resistance = calcResistance(lux); + resistance = calcResistance(lux); ps3 = new Point(); ps4 = new Point(); } + Polygon arrowPoly; - void draw(Graphics g) { //used Resistor draw - //int segments = 16; + + void draw(Graphics g) { // used Resistor draw + // int segments = 16; int i; - //int ox = 0; - int hs=6; //width + // int ox = 0; + int hs = 6; // width double v1 = volts[0]; double v2 = volts[1]; - setBbox(point1, point2, hs); //the two points that are there when the device is being created - draw2Leads(g); //from point1 to lead1 and lead1 to point2 (lead1&2 are on the body) + setBbox(point1, point2, hs); // the two points that are there when the device is being created + draw2Leads(g); // from point1 to lead1 and lead1 to point2 (lead1&2 are on the body) setPowerColor(g, true); double len = distance(lead1, lead2); g.context.save(); g.context.setLineWidth(3.0); - g.context.transform(((double)(lead2.x-lead1.x))/len, ((double)(lead2.y-lead1.y))/len, -((double)(lead2.y-lead1.y))/len,((double)(lead2.x-lead1.x))/len,lead1.x,lead1.y); - CanvasGradient grad = g.context.createLinearGradient(0,0,len,0); - grad.addColorStop(0, getVoltageColor(g,v1).getHexValue()); - grad.addColorStop(1.0, getVoltageColor(g,v2).getHexValue()); + g.context.transform(((double) (lead2.x - lead1.x)) / len, ((double) (lead2.y - lead1.y)) / len, + -((double) (lead2.y - lead1.y)) / len, ((double) (lead2.x - lead1.x)) / len, lead1.x, lead1.y); + CanvasGradient grad = g.context.createLinearGradient(0, 0, len, 0); + grad.addColorStop(0, getVoltageColor(g, v1).getHexValue()); + grad.addColorStop(1.0, getVoltageColor(g, v2).getHexValue()); g.context.setStrokeStyle(grad); if (!sim.euroResistorCheckItem.getState()) { g.context.beginPath(); - g.context.moveTo(0,0); - for (i=0;i<4;i++){ - g.context.lineTo((1+4*i)*len/16, hs); - g.context.lineTo((3+4*i)*len/16, -hs); + g.context.moveTo(0, 0); + for (i = 0; i < 4; i++) { + g.context.lineTo((1 + 4 * i) * len / 16, hs); + g.context.lineTo((3 + 4 * i) * len / 16, -hs); } g.context.lineTo(len, 0); g.context.stroke(); - } else { - g.context.strokeRect(0, -hs, len, 2.0*hs); //draw the box for the euro resistor + } else { + g.context.strokeRect(0, -hs, len, 2.0 * hs); // draw the box for the euro resistor } - g.context.beginPath(); //thermistor symbol lines 0 is in the middle of the left handside of the resistor box - //upper arrow - g.context.moveTo(-8,26); //arrow1 start (y,x coordinates from center?) - g.context.lineTo(8,12); //arrow end point - g.context.moveTo(2,12); //arrow 1 head - g.context.lineTo(8,12); //arrow end point - g.context.lineTo(8,18); - g.context.moveTo(12,26); //arrow2 start (y,x coordinates from center?) - g.context.lineTo(26,12); //arrow end point - g.context.moveTo(20,12); //arrow 1 head - g.context.lineTo(26,12); //arrow end point - g.context.lineTo(26,18); + g.context.beginPath(); // thermistor symbol lines 0 is in the middle of the left handside of the + // resistor box + // upper arrow + g.context.moveTo(-8, 26); // arrow1 start (y,x coordinates from center?) + g.context.lineTo(8, 12); // arrow end point + g.context.moveTo(2, 12); // arrow 1 head + g.context.lineTo(8, 12); // arrow end point + g.context.lineTo(8, 18); + g.context.moveTo(12, 26); // arrow2 start (y,x coordinates from center?) + g.context.lineTo(26, 12); // arrow end point + g.context.moveTo(20, 12); // arrow 1 head + g.context.lineTo(26, 12); // arrow end point + g.context.lineTo(26, 18); g.context.stroke(); - g.context.restore(); if (sim.showValuesCheckItem.getState()) { lux = LuxFromSliderPos(); resistance = calcResistance(lux); String s = getShortUnitText(resistance, ""); - drawValues(g, s+"\u03A9", hs); + drawValues(g, s + "\u03A9", hs); } doDots(g); drawPosts(g); } void calculateCurrent() { - current = (volts[0]-volts[1])/resistance; + current = (volts[0] - volts[1]) / resistance; } + void stamp() { lux = LuxFromSliderPos(); - resistance = calcResistance(lux); - sim.stampResistor(nodes[0], nodes[1], resistance); + resistance = calcResistance(lux); + sim.stampResistor(nodes[0], nodes[1], resistance); } void getInfo(String arr[]) { arr[0] = "photoresistor"; - arr[1] = "I = "+ getCurrentDText(current); //getBasicInfo(arr); - arr[2] = "Vd = "+ getVoltageDText(getVoltageDiff()); + arr[1] = "I = " + getCurrentDText(current); // getBasicInfo(arr); + arr[2] = "Vd = " + getVoltageDText(getVoltageDiff()); arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); arr[4] = "P = " + getUnitText(getPower(), "W"); } + public EditInfo getEditInfo(int n) { if (n == 0) { EditInfo ei = new EditInfo("Slider Text", 0, -1, -1); @@ -169,7 +180,8 @@ public EditInfo getEditInfo(int n) { } return null; } - //component edited + + // component edited public void setEditValue(int n, EditInfo ei) { if (n == 0) { sliderText = ei.textf.getText(); @@ -177,36 +189,37 @@ public void setEditValue(int n, EditInfo ei) { sim.setiFrameHeight(); } lux = LuxFromSliderPos(); - resistance = calcResistance(lux); + resistance = calcResistance(lux); } + void setMouseElm(boolean v) { super.setMouseElm(v); - if (slider!=null) + if (slider != null) slider.draw(); } public void onMouseWheel(MouseWheelEvent e) { - if (slider!=null) + if (slider != null) slider.onMouseWheel(e); } - double calcResistance(double lux) //knowing the lux + double calcResistance(double lux) // knowing the lux { - //double loglux = Math.log10(lux); - //double slope = -1.4; - //double intercept = 7.1; - //double logR = (loglux-intercept)/slope; + // double loglux = Math.log10(lux); + // double slope = -1.4; + // double intercept = 7.1; + // double logR = (loglux-intercept)/slope; - //return Math.round(Math.pow(10, logR)); - double r = (maxLux-lux+1)*10; + // return Math.round(Math.pow(10, logR)); + double r = (maxLux - lux + 1) * 10; r = Math.round(r); return r; } - double LuxFromSliderPos() //knowing slider position etc + + double LuxFromSliderPos() // knowing slider position etc { - return maxLux * position + minLux ; + return maxLux * position + minLux; } } - diff --git a/src/com/lushprojects/circuitjs1/client/LEDArrayElm.java b/src/com/lushprojects/circuitjs1/client/LEDArrayElm.java index bb3adc20..58ff1596 100644 --- a/src/com/lushprojects/circuitjs1/client/LEDArrayElm.java +++ b/src/com/lushprojects/circuitjs1/client/LEDArrayElm.java @@ -19,168 +19,192 @@ package com.lushprojects.circuitjs1.client; - class LEDArrayElm extends ChipElm { - public LEDArrayElm(int xx, int yy) { - super(xx, yy); +class LEDArrayElm extends ChipElm { + public LEDArrayElm(int xx, int yy) { + super(xx, yy); + } + + public LEDArrayElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + try { + sizeX = Integer.parseInt(st.nextToken()); + sizeY = Integer.parseInt(st.nextToken()); + } catch (Exception e) { } - public LEDArrayElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - try { - sizeX = Integer.parseInt(st.nextToken()); - sizeY = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + allocNodes(); + setupPins(); + setPoints(); + } + + String dump() { + return super.dump() + " " + sizeX + " " + sizeY; + } + + String getChipName() { + return "LED array"; + } + + void setupPins() { + if (sizeX == 0 || sizeY == 0) { + sizeX = sizeY = 8; allocNodes(); - setupPins(); - setPoints(); - } - - String dump() { return super.dump() + " " + sizeX + " " + sizeY ; } - - String getChipName() { return "LED array"; } - - void setupPins() { - if (sizeX == 0 || sizeY == 0) { - sizeX = sizeY = 8; - allocNodes(); - } - pins = new Pin[sizeX+sizeY]; - int i; - for (i = 0; i != sizeX; i++) - pins[i] = new Pin(i, SIDE_S, ""); - for (i = 0; i != sizeY; i++) - pins[i+sizeX] = new Pin(i, SIDE_W, ""); - brightness = new double[sizeX*sizeY]; } - - Diode diodes[]; - double currents[]; - double brightness[]; - - void stamp() { - super.stamp(); - - // create grid of diodes - diodes = new Diode[sizeX*sizeY]; - int i; - DiodeModel model = DiodeModel.getModelWithName("default-led"); - for (i = 0; i != diodes.length; i++) { - diodes[i] = new Diode(sim); - diodes[i].setup(model); - diodes[i].stamp(nodes[sizeX+(i / sizeX)], nodes[i % sizeX]); - } - currents = new double[diodes.length]; - } - void doStep() { - super.doStep(); - - int ix, iy, i = 0; - for (iy = 0; iy != sizeY; iy++) - for (ix = 0; ix != sizeX; ix++, i++) - diodes[i].doStep(volts[sizeX+iy]-volts[ix]); - } - boolean nonLinear() { return true; } - @Override boolean isDigitalChip() { return false; } - - void draw(Graphics g) { - drawChip(g); - int ix, iy; - for (ix = 0; ix != sizeX; ix++) - for (iy = 0; iy != sizeY; iy++) { - int i = ix+iy*sizeX; - setColor(g, i); - if (isFlippedXY()) - g.fillOval(pins[iy+sizeX].post.x-cspc/2, pins[ix].post.y-cspc/2, cspc, cspc); - else - g.fillOval(pins[ix].post.x-cspc/2, pins[iy+sizeX].post.y-cspc/2, cspc, cspc); - } + pins = new Pin[sizeX + sizeY]; + int i; + for (i = 0; i != sizeX; i++) + pins[i] = new Pin(i, SIDE_S, ""); + for (i = 0; i != sizeY; i++) + pins[i + sizeX] = new Pin(i, SIDE_W, ""); + brightness = new double[sizeX * sizeY]; + } + + Diode diodes[]; + double currents[]; + double brightness[]; + + void stamp() { + super.stamp(); + + // create grid of diodes + diodes = new Diode[sizeX * sizeY]; + int i; + DiodeModel model = DiodeModel.getModelWithName("default-led"); + for (i = 0; i != diodes.length; i++) { + diodes[i] = new Diode(sim); + diodes[i].setup(model); + diodes[i].stamp(nodes[sizeX + (i / sizeX)], nodes[i % sizeX]); } - - void calculateCurrent() { - // calculate diode currents - int ix, iy, i = 0; - for (ix = 0; ix != sizeX; ix++) - pins[ix].current = 0; - - // avoid exception if this is called before stamp() - if (diodes == null) - return; - + currents = new double[diodes.length]; + } + + void doStep() { + super.doStep(); + + int ix, iy, i = 0; + for (iy = 0; iy != sizeY; iy++) + for (ix = 0; ix != sizeX; ix++, i++) + diodes[i].doStep(volts[sizeX + iy] - volts[ix]); + } + + boolean nonLinear() { + return true; + } + + @Override + boolean isDigitalChip() { + return false; + } + + void draw(Graphics g) { + drawChip(g); + int ix, iy; + for (ix = 0; ix != sizeX; ix++) for (iy = 0; iy != sizeY; iy++) { - double cur = 0; - for (ix = 0; ix != sizeX; ix++, i++) { - currents[i] = diodes[i].calculateCurrent(volts[sizeX+iy]-volts[ix]); - cur += currents[i]; - pins[ix].current += currents[i]; - } - pins[iy+sizeX].current = -cur; + int i = ix + iy * sizeX; + setColor(g, i); + if (isFlippedXY()) + g.fillOval(pins[iy + sizeX].post.x - cspc / 2, pins[ix].post.y - cspc / 2, cspc, cspc); + else + g.fillOval(pins[ix].post.x - cspc / 2, pins[iy + sizeX].post.y - cspc / 2, cspc, cspc); } - } + } - void stepFinished() { - // stop for huge currents that make simulator act weird - int i; - for (i = 0; i != currents.length; i++) - if (Math.abs(currents[i]) > 1e12) - sim.stop("max current exceeded", this); - } + void calculateCurrent() { + // calculate diode currents + int ix, iy, i = 0; + for (ix = 0; ix != sizeX; ix++) + pins[ix].current = 0; + + // avoid exception if this is called before stamp() + if (diodes == null) + return; - void setColor(Graphics g, int p) { - // 10mA current = max brightness - if (currents == null) { - g.setColor(new Color(20, 0, 0)); - return; + for (iy = 0; iy != sizeY; iy++) { + double cur = 0; + for (ix = 0; ix != sizeX; ix++, i++) { + currents[i] = diodes[i].calculateCurrent(volts[sizeX + iy] - volts[ix]); + cur += currents[i]; + pins[ix].current += currents[i]; } - double w = currents[p] / .01; - if (w > 0) - w = 255*(1+.2*Math.log(w)); - if (w > 255) - w = 255; - if (w < 20) - w = 20; - - // when diode turns off, made it fade gradually to simulate persistence of vision - w = Math.max(w, brightness[p]); - brightness[p] = w*.99; - - Color cc = new Color((int) w, 0, 0); - g.setColor(cc); + pins[iy + sizeX].current = -cur; } - int getPostCount() { return sizeX+sizeY; } - int getVoltageSourceCount() { return 0; } - int getDumpType() { return 405; } - - // this is true but it causes strange behavior with unconnected pins so we don't do it -// boolean getConnection(int n1, int n2) { return true; } - - public EditInfo getChipEditInfo(int n) { - if (n == 0) - return new EditInfo("Grid Width", sizeX).setDimensionless(); - if (n == 1) - return new EditInfo("Grid Height", sizeY).setDimensionless(); - return null; + } + + void stepFinished() { + // stop for huge currents that make simulator act weird + int i; + for (i = 0; i != currents.length; i++) + if (Math.abs(currents[i]) > 1e12) + sim.stop("max current exceeded", this); + } + + void setColor(Graphics g, int p) { + // 10mA current = max brightness + if (currents == null) { + g.setColor(new Color(20, 0, 0)); + return; } - - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value >= 2 && ei.value <= 16) { - sizeX = (int)ei.value; - allocNodes(); - setupPins(); - setPoints(); - return; - } - if (n == 1 && ei.value >= 2 && ei.value <= 16) { - sizeY = (int)ei.value; - allocNodes(); - setupPins(); - setPoints(); - return; - } + double w = currents[p] / .01; + if (w > 0) + w = 255 * (1 + .2 * Math.log(w)); + if (w > 255) + w = 255; + if (w < 20) + w = 20; + + // when diode turns off, made it fade gradually to simulate persistence of + // vision + w = Math.max(w, brightness[p]); + brightness[p] = w * .99; + + Color cc = new Color((int) w, 0, 0); + g.setColor(cc); + } + + int getPostCount() { + return sizeX + sizeY; + } + + int getVoltageSourceCount() { + return 0; + } + + int getDumpType() { + return 405; + } + + // this is true but it causes strange behavior with unconnected pins so we don't + // do it + // boolean getConnection(int n1, int n2) { return true; } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) + return new EditInfo("Grid Width", sizeX).setDimensionless(); + if (n == 1) + return new EditInfo("Grid Height", sizeY).setDimensionless(); + return null; + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value >= 2 && ei.value <= 16) { + sizeX = (int) ei.value; + allocNodes(); + setupPins(); + setPoints(); + return; } - - // default getInfo doesn't work because the pins are unlabeled - void getInfo(String arr[]) { - arr[0] = getChipName(); + if (n == 1 && ei.value >= 2 && ei.value <= 16) { + sizeY = (int) ei.value; + allocNodes(); + setupPins(); + setPoints(); return; } } + + // default getInfo doesn't work because the pins are unlabeled + void getInfo(String arr[]) { + arr[0] = getChipName(); + return; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/LEDElm.java b/src/com/lushprojects/circuitjs1/client/LEDElm.java index 51b672f8..d8305dfc 100644 --- a/src/com/lushprojects/circuitjs1/client/LEDElm.java +++ b/src/com/lushprojects/circuitjs1/client/LEDElm.java @@ -22,117 +22,123 @@ import com.lushprojects.circuitjs1.client.util.Locale; class LEDElm extends DiodeElm { - double colorR, colorG, colorB, maxBrightnessCurrent; - static String lastLEDModelName = "default-led"; - - public LEDElm(int xx, int yy) { - super(xx, yy); - modelName = lastLEDModelName; + double colorR, colorG, colorB, maxBrightnessCurrent; + static String lastLEDModelName = "default-led"; + + public LEDElm(int xx, int yy) { + super(xx, yy); + modelName = lastLEDModelName; + setup(); + maxBrightnessCurrent = .01; + colorR = 1; + colorG = colorB = 0; + } + + public LEDElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + if ((f & (FLAG_MODEL | FLAG_FWDROP)) == 0) { + final double fwdrop = 2.1024259; + model = DiodeModel.getModelWithParameters(fwdrop, 0); + modelName = model.name; + CirSim.console("model name wparams = " + modelName); setup(); - maxBrightnessCurrent = .01; - colorR = 1; colorG = colorB = 0; - } - public LEDElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - if ((f & (FLAG_MODEL|FLAG_FWDROP)) == 0) { - final double fwdrop = 2.1024259; - model = DiodeModel.getModelWithParameters(fwdrop, 0); - modelName = model.name; - CirSim.console("model name wparams = " + modelName); - setup(); - } - colorR = new Double(st.nextToken()).doubleValue(); - colorG = new Double(st.nextToken()).doubleValue(); - colorB = new Double(st.nextToken()).doubleValue(); - maxBrightnessCurrent = .01; - try { - maxBrightnessCurrent = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { } } - int getDumpType() { return 162; } - String dump() { - return super.dump() + " " + colorR + " " + colorG + " " + colorB + " " + - maxBrightnessCurrent; + colorR = Double.valueOf(st.nextToken()).doubleValue(); + colorG = Double.valueOf(st.nextToken()).doubleValue(); + colorB = Double.valueOf(st.nextToken()).doubleValue(); + maxBrightnessCurrent = .01; + try { + maxBrightnessCurrent = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } + } - Point ledLead1, ledLead2, ledCenter; - void setPoints() { - super.setPoints(); - int cr = 12; - ledLead1 = interpPoint(point1, point2, .5-cr/dn); - ledLead2 = interpPoint(point1, point2, .5+cr/dn); - ledCenter = interpPoint(point1, point2, .5); - } - - void draw(Graphics g) { - if (needsHighlight() || this == sim.dragElm) { - super.draw(g); - return; - } - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, ledLead1); - setVoltageColor(g, volts[1]); - drawThickLine(g, ledLead2, point2); - - g.setColor(Color.gray); - int cr = 12; - drawThickCircle(g, ledCenter.x, ledCenter.y, cr); - cr -= 4; - double w = current/maxBrightnessCurrent; - if (w > 0) - w = 255*(1+.2*Math.log(w)); - if (w > 255) - w = 255; - if (w < 0) - w = 0; - Color cc = new Color((int) (colorR*w), (int) (colorG*w), - (int) (colorB*w)); - g.setColor(cc); - g.fillOval(ledCenter.x-cr, ledCenter.y-cr, cr*2, cr*2); - setBbox(point1, point2, cr); - updateDotCount(); - drawDots(g, point1, ledLead1, curcount); - drawDots(g, point2, ledLead2, -curcount); - drawPosts(g); - } + int getDumpType() { + return 162; + } - void getInfo(String arr[]) { - super.getInfo(arr); - if (model.oldStyle) - arr[0] = "LED"; - else - arr[0] = Locale.LS("LED") + " (" + modelName + ")"; - } + String dump() { + return super.dump() + " " + colorR + " " + colorG + " " + colorB + " " + maxBrightnessCurrent; + } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Red Value (0-1)", colorR, 0, 1). - setDimensionless(); - if (n == 1) - return new EditInfo("Green Value (0-1)", colorG, 0, 1). - setDimensionless(); - if (n == 2) - return new EditInfo("Blue Value (0-1)", colorB, 0, 1). - setDimensionless(); - if (n == 3) - return new EditInfo("Max Brightness Current (A)", maxBrightnessCurrent, 0, .1); - return super.getEditInfo(n-4); - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - colorR = ei.value; - if (n == 1) - colorG = ei.value; - if (n == 2) - colorB = ei.value; - if (n == 3) - maxBrightnessCurrent = ei.value; - super.setEditValue(n-4, ei); - } - int getShortcut() { return 'l'; } - - void setLastModelName(String n) { - lastLEDModelName = n; + Point ledLead1, ledLead2, ledCenter; + + void setPoints() { + super.setPoints(); + int cr = 12; + ledLead1 = interpPoint(point1, point2, .5 - cr / dn); + ledLead2 = interpPoint(point1, point2, .5 + cr / dn); + ledCenter = interpPoint(point1, point2, .5); + } + + void draw(Graphics g) { + if (needsHighlight() || this == sim.dragElm) { + super.draw(g); + return; } + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, ledLead1); + setVoltageColor(g, volts[1]); + drawThickLine(g, ledLead2, point2); + + g.setColor(Color.gray); + int cr = 12; + drawThickCircle(g, ledCenter.x, ledCenter.y, cr); + cr -= 4; + double w = current / maxBrightnessCurrent; + if (w > 0) + w = 255 * (1 + .2 * Math.log(w)); + if (w > 255) + w = 255; + if (w < 0) + w = 0; + Color cc = new Color((int) (colorR * w), (int) (colorG * w), (int) (colorB * w)); + g.setColor(cc); + g.fillOval(ledCenter.x - cr, ledCenter.y - cr, cr * 2, cr * 2); + setBbox(point1, point2, cr); + updateDotCount(); + drawDots(g, point1, ledLead1, curcount); + drawDots(g, point2, ledLead2, -curcount); + drawPosts(g); + } + + void getInfo(String arr[]) { + super.getInfo(arr); + if (model.oldStyle) + arr[0] = "LED"; + else + arr[0] = Locale.LS("LED") + " (" + modelName + ")"; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Red Value (0-1)", colorR, 0, 1).setDimensionless(); + if (n == 1) + return new EditInfo("Green Value (0-1)", colorG, 0, 1).setDimensionless(); + if (n == 2) + return new EditInfo("Blue Value (0-1)", colorB, 0, 1).setDimensionless(); + if (n == 3) + return new EditInfo("Max Brightness Current (A)", maxBrightnessCurrent, 0, .1); + return super.getEditInfo(n - 4); + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + colorR = ei.value; + if (n == 1) + colorG = ei.value; + if (n == 2) + colorB = ei.value; + if (n == 3) + maxBrightnessCurrent = ei.value; + super.setEditValue(n - 4, ei); + } + + int getShortcut() { + return 'l'; + } + + void setLastModelName(String n) { + lastLEDModelName = n; } +} diff --git a/src/com/lushprojects/circuitjs1/client/LabeledNodeElm.java b/src/com/lushprojects/circuitjs1/client/LabeledNodeElm.java index 2f6d561d..13120724 100644 --- a/src/com/lushprojects/circuitjs1/client/LabeledNodeElm.java +++ b/src/com/lushprojects/circuitjs1/client/LabeledNodeElm.java @@ -25,13 +25,13 @@ class LabeledNodeElm extends CircuitElm { final int FLAG_ESCAPE = 4; final int FLAG_INTERNAL = 1; - + public LabeledNodeElm(int xx, int yy) { super(xx, yy); text = "label"; } - public LabeledNodeElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public LabeledNodeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); text = st.nextToken(); if ((flags & FLAG_ESCAPE) == 0) { @@ -40,69 +40,87 @@ public LabeledNodeElm(int xa, int ya, int xb, int yb, int f, text += ' ' + st.nextToken(); } else { // new-style dump - text = CustomLogicModel.unescape(text); + text = CustomLogicModel.unescape(text); } } + String dump() { flags |= FLAG_ESCAPE; return super.dump() + " " + CustomLogicModel.escape(text); } String text; - + class LabelEntry { Point point; int node; } - - static HashMap labelList; - boolean isInternal() { return (flags & FLAG_INTERNAL) != 0; } + + static HashMap labelList; + + boolean isInternal() { + return (flags & FLAG_INTERNAL) != 0; + } public static native void console(String text) /*-{ - console.log(text); - }-*/; + console.log(text); + }-*/; static void resetNodeList() { - labelList = new HashMap(); + labelList = new HashMap(); } + final int circleSize = 17; + void setPoints() { super.setPoints(); - lead1 = interpPoint(point1, point2, 1-circleSize/dn); + lead1 = interpPoint(point1, point2, 1 - circleSize / dn); } - + // get post we're connected to Point getConnectedPost() { LabelEntry le = labelList.get(text); if (le != null) return le.point; - - // this is the first time calcWireClosure() encountered this label. so save point1 and - // return null for now, but return point1 the next time we see this label so that all nodes + + // this is the first time calcWireClosure() encountered this label. so save + // point1 and + // return null for now, but return point1 the next time we see this label so + // that all nodes // with the same label are connected le = new LabelEntry(); le.point = point1; labelList.put(text, le); return null; } - + void setNode(int p, int n) { super.setNode(p, n); - + // save node number so we can return it in getByName() LabelEntry le = labelList.get(text); if (le != null) // should never happen le.node = n; } - - int getDumpType() { return 207; } - int getPostCount() { return 1; } - + + int getDumpType() { + return 207; + } + + int getPostCount() { + return 1; + } + // this is basically a wire, since it just connects two or more nodes together - boolean isWireEquivalent() { return true; } - boolean isRemovableWire() { return true; } - + boolean isWireEquivalent() { + return true; + } + + boolean isRemovableWire() { + return true; + } + static Integer getByName(String n) { if (labelList == null) return null; @@ -111,13 +129,13 @@ static Integer getByName(String n) { return null; return le.node; } - + void draw(Graphics g) { setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); g.setColor(needsHighlight() ? selectColor : whiteColor); setPowerColor(g, false); - interpPoint(point1, point2, ps2, 1+11./dn); + interpPoint(point1, point2, ps2, 1 + 11. / dn); setBbox(point1, ps2, circleSize); drawLabeledNode(g, text, point1, lead1); @@ -125,9 +143,19 @@ void draw(Graphics g) { drawDots(g, point1, lead1, curcount); drawPosts(g); } - double getCurrentIntoNode(int n) { return -current; } - void setCurrent(int x, double c) { current = c; } - double getVoltageDiff() { return volts[0]; } + + double getCurrentIntoNode(int n) { + return -current; + } + + void setCurrent(int x, double c) { + current = c; + } + + double getVoltageDiff() { + return volts[0]; + } + void getInfo(String arr[]) { arr[0] = Locale.LS(text) + " (" + Locale.LS("Labeled Node") + ")"; arr[1] = "I = " + getCurrentText(getCurrent()); @@ -140,22 +168,27 @@ public EditInfo getEditInfo(int n) { ei.text = text; return ei; } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Internal Node", isInternal()); - return ei; - } + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Internal Node", isInternal()); + return ei; + } return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) text = ei.textf.getText(); if (n == 1) flags = ei.changeFlag(flags, FLAG_INTERNAL); } - @Override String getScopeText(int v) { + + @Override + String getScopeText(int v) { + return text; + } + + String getName() { return text; } - - String getName() { return text; } } diff --git a/src/com/lushprojects/circuitjs1/client/LampElm.java b/src/com/lushprojects/circuitjs1/client/LampElm.java index c101a6ba..00d6b37c 100644 --- a/src/com/lushprojects/circuitjs1/client/LampElm.java +++ b/src/com/lushprojects/circuitjs1/client/LampElm.java @@ -22,186 +22,201 @@ import com.lushprojects.circuitjs1.client.util.Locale; class LampElm extends CircuitElm { - double resistance; - final double roomTemp = 300; - double temp, nom_pow, nom_v, warmTime, coolTime; - public LampElm(int xx, int yy) { - super(xx, yy); - temp = roomTemp; - nom_pow = 100; - nom_v = 120; - warmTime = .4; - coolTime = .4; - } - public LampElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - temp = new Double(st.nextToken()).doubleValue(); - if (Double.isNaN(temp)) - temp = roomTemp; - nom_pow = new Double(st.nextToken()).doubleValue(); - nom_v = new Double(st.nextToken()).doubleValue(); - warmTime = new Double(st.nextToken()).doubleValue(); - coolTime = new Double(st.nextToken()).doubleValue(); - } - String dump() { - return super.dump() + " " + temp + " " + nom_pow + " " + nom_v + - " " + warmTime + " " + coolTime; - } - int getDumpType() { return 181; } + double resistance; + final double roomTemp = 300; + double temp, nom_pow, nom_v, warmTime, coolTime; - Point bulbLead[], filament[], bulb; - int bulbR; + public LampElm(int xx, int yy) { + super(xx, yy); + temp = roomTemp; + nom_pow = 100; + nom_v = 120; + warmTime = .4; + coolTime = .4; + } - void reset() { - super.reset(); + public LampElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + temp = Double.valueOf(st.nextToken()).doubleValue(); + if (Double.isNaN(temp)) temp = roomTemp; - - // make sure resistance is not 0 or NaN or current will be NaN before we have a chance - // to call startIteration() - resistance = 100; - } - final int filament_len = 24; - void setPoints() { - super.setPoints(); - int llen = 16; - calcLeads(llen); - bulbLead = newPointArray(2); - filament = newPointArray(2); - bulbR = 20; - filament[0] = interpPoint(lead1, lead2, 0, filament_len); - filament[1] = interpPoint(lead1, lead2, 1, filament_len); - double br = filament_len-Math.sqrt(bulbR*bulbR-llen*llen); - bulbLead[0] = interpPoint(lead1, lead2, 0, br); - bulbLead[1] = interpPoint(lead1, lead2, 1, br); - bulb = interpPoint(filament[0], filament[1], .5); - } + nom_pow = Double.valueOf(st.nextToken()).doubleValue(); + nom_v = Double.valueOf(st.nextToken()).doubleValue(); + warmTime = Double.valueOf(st.nextToken()).doubleValue(); + coolTime = Double.valueOf(st.nextToken()).doubleValue(); + } - Color getTempColor() { - if (temp < 1200) { - int x = (int) (255*(temp-800)/400); - if (x < 0) - x = 0; - return new Color(x, 0, 0); - } - if (temp < 1700) { - int x = (int) (255*(temp-1200)/500); - if (x < 0) - x = 0; - return new Color(255, x, 0); - } - if (temp < 2400) { - int x = (int) (255*(temp-1700)/700); - if (x < 0) - x = 0; - return new Color(255, 255, x); - } - return Color.white; - } - - void draw(Graphics g) { - double v1 = volts[0]; - double v2 = volts[1]; - setBbox(point1, point2, 4); - adjustBbox(bulb.x-bulbR, bulb.y-bulbR, - bulb.x+bulbR, bulb.y+bulbR); - // adjustbbox - draw2Leads(g); - setPowerColor(g, true); - g.setColor(getTempColor()); - g.fillOval(bulb.x-bulbR, bulb.y-bulbR, bulbR*2, bulbR*2); - g.setColor(whiteColor); - drawThickCircle(g, bulb.x, bulb.y, bulbR); - setVoltageColor(g, v1); - drawThickLine(g, lead1, filament[0]); - setVoltageColor(g, v2); - drawThickLine(g, lead2, filament[1]); - setVoltageColor(g, (v1+v2)*.5); - drawThickLine(g, filament[0], filament[1]); - updateDotCount(); - if (sim.dragElm != this) { - drawDots(g, point1, lead1, curcount); - double cc = addCurCount(curcount, (dn-16)/2); - drawDots(g, lead1, filament[0], cc); - cc = addCurCount(cc, filament_len); - drawDots(g, filament[0], filament[1], cc); - cc = addCurCount(cc, 16); - drawDots(g, filament[1], lead2, cc); - cc = addCurCount(cc, filament_len); - drawDots(g, lead2, point2, curcount); - } - drawPosts(g); - } + String dump() { + return super.dump() + " " + temp + " " + nom_pow + " " + nom_v + " " + warmTime + " " + coolTime; + } - void calculateCurrent() { - current = (volts[0]-volts[1])/resistance; - if (resistance == 0) - current = 0; -// sim.console("lampcc " + current + " " + resistance); - } - void stamp() { - sim.stampNonLinear(nodes[0]); - sim.stampNonLinear(nodes[1]); - } - boolean nonLinear() { return true; } - void startIteration() { - // based on http://www.intusoft.com/nlpdf/nl11.pdf - double nom_r = nom_v*nom_v/nom_pow; - // this formula doesn't work for values over 5390 - double tp = (temp > 5390) ? 5390 : temp; - resistance = nom_r*(1.26104 - - 4.90662*Math.sqrt(17.1839/tp - 0.00318794) - - 7.8569/(tp - 187.56)); - double cap = 1.57e-4*nom_pow; - double capw = cap * warmTime/.4; - double capc = cap * coolTime/.4; - //System.out.println(nom_r + " " + (resistance/nom_r)); - temp += getPower()*sim.timeStep/capw; - double cr = 2600/nom_pow; - temp -= sim.timeStep*(temp-roomTemp)/(capc*cr); -// sim.console("lampsi " + temp + " " + capc + " " + nom_pow); - } - void doStep() { - sim.stampResistor(nodes[0], nodes[1], resistance); - } - void getInfo(String arr[]) { - arr[0] = "lamp"; - getBasicInfo(arr); - arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); - arr[4] = "P = " + getUnitText(getPower(), "W"); - arr[5] = "T = " + ((int) temp) + " K"; - } - public EditInfo getEditInfo(int n) { - // ohmString doesn't work here on linux - if (n == 0) - return new EditInfo("Nominal Power", nom_pow, 0, 0); - if (n == 1) - return new EditInfo("Nominal Voltage", nom_v, 0, 0); - if (n == 2) - return new EditInfo("Warmup Time (s)", warmTime, 0, 0); - if (n == 3) - return new EditInfo("Cooldown Time (s)", coolTime, 0, 0); - return null; - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0 && ei.value > 0) - nom_pow = ei.value; - if (n == 1 && ei.value > 0) - nom_v = ei.value; - if (n == 2 && ei.value > 0) - warmTime = ei.value; - if (n == 3 && ei.value > 0) - coolTime = ei.value; - } - - double getScopeValue(int x) { - return (x == Scope.VAL_R) ? resistance : super.getScopeValue(x); - } - int getScopeUnits(int x) { - return (x == Scope.VAL_R) ? Scope.UNITS_OHMS : super.getScopeUnits(x); - } - boolean canShowValueInScope(int x) { - return x == Scope.VAL_R; - } + int getDumpType() { + return 181; + } + + Point bulbLead[], filament[], bulb; + int bulbR; + + void reset() { + super.reset(); + temp = roomTemp; + + // make sure resistance is not 0 or NaN or current will be NaN before we have a + // chance + // to call startIteration() + resistance = 100; + } + + final int filament_len = 24; + void setPoints() { + super.setPoints(); + int llen = 16; + calcLeads(llen); + bulbLead = newPointArray(2); + filament = newPointArray(2); + bulbR = 20; + filament[0] = interpPoint(lead1, lead2, 0, filament_len); + filament[1] = interpPoint(lead1, lead2, 1, filament_len); + double br = filament_len - Math.sqrt(bulbR * bulbR - llen * llen); + bulbLead[0] = interpPoint(lead1, lead2, 0, br); + bulbLead[1] = interpPoint(lead1, lead2, 1, br); + bulb = interpPoint(filament[0], filament[1], .5); } + + Color getTempColor() { + if (temp < 1200) { + int x = (int) (255 * (temp - 800) / 400); + if (x < 0) + x = 0; + return new Color(x, 0, 0); + } + if (temp < 1700) { + int x = (int) (255 * (temp - 1200) / 500); + if (x < 0) + x = 0; + return new Color(255, x, 0); + } + if (temp < 2400) { + int x = (int) (255 * (temp - 1700) / 700); + if (x < 0) + x = 0; + return new Color(255, 255, x); + } + return Color.white; + } + + void draw(Graphics g) { + double v1 = volts[0]; + double v2 = volts[1]; + setBbox(point1, point2, 4); + adjustBbox(bulb.x - bulbR, bulb.y - bulbR, bulb.x + bulbR, bulb.y + bulbR); + // adjustbbox + draw2Leads(g); + setPowerColor(g, true); + g.setColor(getTempColor()); + g.fillOval(bulb.x - bulbR, bulb.y - bulbR, bulbR * 2, bulbR * 2); + g.setColor(whiteColor); + drawThickCircle(g, bulb.x, bulb.y, bulbR); + setVoltageColor(g, v1); + drawThickLine(g, lead1, filament[0]); + setVoltageColor(g, v2); + drawThickLine(g, lead2, filament[1]); + setVoltageColor(g, (v1 + v2) * .5); + drawThickLine(g, filament[0], filament[1]); + updateDotCount(); + if (sim.dragElm != this) { + drawDots(g, point1, lead1, curcount); + double cc = addCurCount(curcount, (dn - 16) / 2); + drawDots(g, lead1, filament[0], cc); + cc = addCurCount(cc, filament_len); + drawDots(g, filament[0], filament[1], cc); + cc = addCurCount(cc, 16); + drawDots(g, filament[1], lead2, cc); + cc = addCurCount(cc, filament_len); + drawDots(g, lead2, point2, curcount); + } + drawPosts(g); + } + + void calculateCurrent() { + current = (volts[0] - volts[1]) / resistance; + if (resistance == 0) + current = 0; + // sim.console("lampcc " + current + " " + resistance); + } + + void stamp() { + sim.stampNonLinear(nodes[0]); + sim.stampNonLinear(nodes[1]); + } + + boolean nonLinear() { + return true; + } + + void startIteration() { + // based on http://www.intusoft.com/nlpdf/nl11.pdf + double nom_r = nom_v * nom_v / nom_pow; + // this formula doesn't work for values over 5390 + double tp = (temp > 5390) ? 5390 : temp; + resistance = nom_r * (1.26104 - 4.90662 * Math.sqrt(17.1839 / tp - 0.00318794) - 7.8569 / (tp - 187.56)); + double cap = 1.57e-4 * nom_pow; + double capw = cap * warmTime / .4; + double capc = cap * coolTime / .4; + // System.out.println(nom_r + " " + (resistance/nom_r)); + temp += getPower() * sim.timeStep / capw; + double cr = 2600 / nom_pow; + temp -= sim.timeStep * (temp - roomTemp) / (capc * cr); + // sim.console("lampsi " + temp + " " + capc + " " + nom_pow); + } + + void doStep() { + sim.stampResistor(nodes[0], nodes[1], resistance); + } + + void getInfo(String arr[]) { + arr[0] = "lamp"; + getBasicInfo(arr); + arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); + arr[4] = "P = " + getUnitText(getPower(), "W"); + arr[5] = "T = " + ((int) temp) + " K"; + } + + public EditInfo getEditInfo(int n) { + // ohmString doesn't work here on linux + if (n == 0) + return new EditInfo("Nominal Power", nom_pow, 0, 0); + if (n == 1) + return new EditInfo("Nominal Voltage", nom_v, 0, 0); + if (n == 2) + return new EditInfo("Warmup Time (s)", warmTime, 0, 0); + if (n == 3) + return new EditInfo("Cooldown Time (s)", coolTime, 0, 0); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value > 0) + nom_pow = ei.value; + if (n == 1 && ei.value > 0) + nom_v = ei.value; + if (n == 2 && ei.value > 0) + warmTime = ei.value; + if (n == 3 && ei.value > 0) + coolTime = ei.value; + } + + double getScopeValue(int x) { + return (x == Scope.VAL_R) ? resistance : super.getScopeValue(x); + } + + int getScopeUnits(int x) { + return (x == Scope.VAL_R) ? Scope.UNITS_OHMS : super.getScopeUnits(x); + } + + boolean canShowValueInScope(int x) { + return x == Scope.VAL_R; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/LatchElm.java b/src/com/lushprojects/circuitjs1/client/LatchElm.java index 4640bb92..f42d32df 100644 --- a/src/com/lushprojects/circuitjs1/client/LatchElm.java +++ b/src/com/lushprojects/circuitjs1/client/LatchElm.java @@ -21,13 +21,14 @@ class LatchElm extends ChipElm { final int FLAG_STATE = 2; + public LatchElm(int xx, int yy) { super(xx, yy); flags |= FLAG_STATE; setupPins(); } - public LatchElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public LatchElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); // add FLAG_STATE flag to old latches so their state gets saved @@ -36,47 +37,67 @@ public LatchElm(int xa, int ya, int xb, int yb, int f, setupPins(); } } - String getChipName() { return "Latch"; } - boolean needsBits() { return true; } + + String getChipName() { + return "Latch"; + } + + boolean needsBits() { + return true; + } + int loadPin; + void setupPins() { sizeX = 2; - sizeY = bits+1; + sizeY = bits + 1; pins = new Pin[getPostCount()]; int i; for (i = 0; i != bits; i++) - pins[i] = new Pin(bits-1-i, SIDE_W, "I" + i); + pins[i] = new Pin(bits - 1 - i, SIDE_W, "I" + i); for (i = 0; i != bits; i++) { - pins[i+bits] = new Pin(bits-1-i, SIDE_E, "O"); - pins[i+bits].output = true; - pins[i+bits].state = (flags & FLAG_STATE) != 0; + pins[i + bits] = new Pin(bits - 1 - i, SIDE_E, "O"); + pins[i + bits].output = true; + pins[i + bits].state = (flags & FLAG_STATE) != 0; } - pins[loadPin = bits*2] = new Pin(bits, SIDE_W, "Ld"); + pins[loadPin = bits * 2] = new Pin(bits, SIDE_W, "Ld"); allocNodes(); } + boolean lastLoad = false; + void execute() { int i; if (pins[loadPin].value && !lastLoad) for (i = 0; i != bits; i++) - pins[i+bits].value = pins[i].value; + pins[i + bits].value = pins[i].value; lastLoad = pins[loadPin].value; } - int getVoltageSourceCount() { return bits; } - int getPostCount() { return bits*2+1; } - int getDumpType() { return 168; } + + int getVoltageSourceCount() { + return bits; + } + + int getPostCount() { + return bits * 2 + 1; + } + + int getDumpType() { + return 168; + } + public EditInfo getChipEditInfo(int n) { if (n == 0) return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); return null; } + public void setChipEditValue(int n, EditInfo ei) { if (n == 0 && ei.value >= 2) { - bits = (int)ei.value; + bits = (int) ei.value; setupPins(); setPoints(); } } - + } - diff --git a/src/com/lushprojects/circuitjs1/client/LineElm.java b/src/com/lushprojects/circuitjs1/client/LineElm.java index 9fec0f9b..9ed44eb8 100644 --- a/src/com/lushprojects/circuitjs1/client/LineElm.java +++ b/src/com/lushprojects/circuitjs1/client/LineElm.java @@ -28,8 +28,7 @@ public LineElm(int xx, int yy) { setBbox(x, y, x2, y2); } - public LineElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + public LineElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); x2 = xb; y2 = yb; @@ -40,7 +39,9 @@ String dump() { return super.dump(); } - int getDumpType() { return 423; } + int getDumpType() { + return 423; + } void drag(int xx, int yy) { x2 = xx; @@ -48,11 +49,11 @@ void drag(int xx, int yy) { } boolean creationFailed() { - return Math.hypot(x-x2, y-y2) < 16; + return Math.hypot(x - x2, y - y2) < 16; } - + void draw(Graphics g) { - //g.setColor(needsHighlight() ? selectColor : lightGrayColor); + // g.setColor(needsHighlight() ? selectColor : lightGrayColor); g.setColor(needsHighlight() ? selectColor : Color.GRAY); setBbox(x, y, x2, y2); g.drawLine(x, y, x2, y2); @@ -69,6 +70,7 @@ void getInfo(String arr[]) { } @Override - int getShortcut() { return 0; } + int getShortcut() { + return 0; + } } - diff --git a/src/com/lushprojects/circuitjs1/client/LoadFile.java b/src/com/lushprojects/circuitjs1/client/LoadFile.java index 729643c9..34e48069 100644 --- a/src/com/lushprojects/circuitjs1/client/LoadFile.java +++ b/src/com/lushprojects/circuitjs1/client/LoadFile.java @@ -23,62 +23,59 @@ import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; -public class LoadFile extends FileUpload implements ChangeHandler { - - static CirSim sim; - - static public final native boolean isSupported() - /*-{ - return !!($wnd.File && $wnd.FileReader); - }-*/; - - static public void doLoadCallback(String s, String t) { - sim.pushUndo(); - sim.readCircuit(s); - sim.createNewLoadFile(); - sim.setCircuitTitle(t); - ExportAsLocalFileDialog.setLastFileName(t); - sim.unsavedChanges = false; - } - - LoadFile(CirSim s) { - super(); - sim=s; - this.setName("Import"); - this.getElement().setId("LoadFileElement"); - this.addChangeHandler(this); - this.addStyleName("offScreen"); - } - - - - public void onChange(ChangeEvent e) { - doLoad(); - } - - - public final native void click() - /*-{ - $doc.getElementById("LoadFileElement").click(); - }-*/; - - static public final native void doLoad() - /*-{ - var oFiles = $doc.getElementById("LoadFileElement").files, - nFiles = oFiles.length; - if (nFiles>=1) { - if (oFiles[0].size >= 128000) - alert("File too large!"); - else { - var reader = new FileReader(); - reader.onload = function(e) { - var text = reader.result; - @com.lushprojects.circuitjs1.client.LoadFile::doLoadCallback(Ljava/lang/String;Ljava/lang/String;)(text, oFiles[0].name); - }; +public class LoadFile extends FileUpload implements ChangeHandler { + + static CirSim sim; + + static public final native boolean isSupported() + /*-{ + return !!($wnd.File && $wnd.FileReader); + }-*/; + + static public void doLoadCallback(String s, String t) { + sim.pushUndo(); + sim.readCircuit(s); + sim.createNewLoadFile(); + sim.setCircuitTitle(t); + ExportAsLocalFileDialog.setLastFileName(t); + sim.unsavedChanges = false; + } + + LoadFile(CirSim s) { + super(); + sim = s; + this.setName("Import"); + this.getElement().setId("LoadFileElement"); + this.addChangeHandler(this); + this.addStyleName("offScreen"); + } + + public void onChange(ChangeEvent e) { + doLoad(); + } + + public final native void click() + /*-{ + $doc.getElementById("LoadFileElement").click(); + }-*/; + + static public final native void doLoad() + /*-{ + var oFiles = $doc.getElementById("LoadFileElement").files, + nFiles = oFiles.length; + if (nFiles>=1) { + if (oFiles[0].size >= 128000) + alert("File too large!"); + else { + var reader = new FileReader(); + reader.onload = function(e) { + var text = reader.result; + @com.lushprojects.circuitjs1.client.LoadFile::doLoadCallback(Ljava/lang/String;Ljava/lang/String;)(text, oFiles[0].name); + }; + + reader.readAsText(oFiles[0]); + } + } + }-*/; - reader.readAsText(oFiles[0]); - } - } - }-*/; - } diff --git a/src/com/lushprojects/circuitjs1/client/LogicInputElm.java b/src/com/lushprojects/circuitjs1/client/LogicInputElm.java index d4fb0cc7..762925e1 100644 --- a/src/com/lushprojects/circuitjs1/client/LogicInputElm.java +++ b/src/com/lushprojects/circuitjs1/client/LogicInputElm.java @@ -19,134 +19,175 @@ package com.lushprojects.circuitjs1.client; - class LogicInputElm extends SwitchElm { - final int FLAG_TERNARY = 1; - final int FLAG_NUMERIC = 2; - double hiV, loV; - public LogicInputElm(int xx, int yy) { - super(xx, yy, false); +class LogicInputElm extends SwitchElm { + final int FLAG_TERNARY = 1; + final int FLAG_NUMERIC = 2; + double hiV, loV; + + public LogicInputElm(int xx, int yy) { + super(xx, yy, false); + hiV = 5; + loV = 0; + + } + + public LogicInputElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + try { + hiV = Double.valueOf(st.nextToken()).doubleValue(); + loV = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { hiV = 5; loV = 0; - - } - public LogicInputElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - try { - hiV = new Double(st.nextToken()).doubleValue(); - loV = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { - hiV = 5; - loV = 0; - } - if (isTernary()) - posCount = 3; - } - boolean isTernary() { return (flags & FLAG_TERNARY) != 0; } - boolean isNumeric() { return (flags & (FLAG_TERNARY|FLAG_NUMERIC)) != 0; } - int getDumpType() { return 'L'; } - String dump() { - return super.dump() + " " + hiV + " " + loV; - } - int getPostCount() { return 1; } - void setPoints() { - super.setPoints(); - lead1 = interpPoint(point1, point2, 1-12/dn); } - void draw(Graphics g) { - g.save(); - Font f = new Font("SansSerif", Font.BOLD, 20); - g.setFont(f); - g.setColor(needsHighlight() ? selectColor : whiteColor); - String s = position == 0 ? "L" : "H"; - if (isNumeric()) - s = "" + position; - setBbox(point1, lead1, 0); - drawCenteredText(g, s, x2, y2, true); - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, lead1); - updateDotCount(); - drawDots(g, point1, lead1, -curcount); - drawPosts(g); - g.restore(); - } - - Rectangle getSwitchRect() { - return new Rectangle(x2-10, y2-10, 20, 20); - } - - void setCurrent(int vs, double c) { current = c; } - void calculateCurrent() {} - void stamp() { - sim.stampVoltageSource(0, nodes[0], voltSource); + if (isTernary()) + posCount = 3; + } + + boolean isTernary() { + return (flags & FLAG_TERNARY) != 0; + } + + boolean isNumeric() { + return (flags & (FLAG_TERNARY | FLAG_NUMERIC)) != 0; + } + + int getDumpType() { + return 'L'; + } + + String dump() { + return super.dump() + " " + hiV + " " + loV; + } + + int getPostCount() { + return 1; + } + + void setPoints() { + super.setPoints(); + lead1 = interpPoint(point1, point2, 1 - 12 / dn); + } + + void draw(Graphics g) { + g.save(); + Font f = new Font("SansSerif", Font.BOLD, 20); + g.setFont(f); + g.setColor(needsHighlight() ? selectColor : whiteColor); + String s = position == 0 ? "L" : "H"; + if (isNumeric()) + s = "" + position; + setBbox(point1, lead1, 0); + drawCenteredText(g, s, x2, y2, true); + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, lead1); + updateDotCount(); + drawDots(g, point1, lead1, -curcount); + drawPosts(g); + g.restore(); + } + + Rectangle getSwitchRect() { + return new Rectangle(x2 - 10, y2 - 10, 20, 20); + } + + void setCurrent(int vs, double c) { + current = c; + } + + void calculateCurrent() { + } + + void stamp() { + sim.stampVoltageSource(0, nodes[0], voltSource); + } + + boolean isWireEquivalent() { + return false; + } + + boolean isRemovableWire() { + return false; + } + + void doStep() { + double v = (position == 0) ? loV : hiV; + if (isTernary()) + v = loV + position * (hiV - loV) * .5; + sim.updateVoltageSource(0, nodes[0], voltSource, v); + } + + int getVoltageSourceCount() { + return 1; + } + + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "logic input"; + arr[1] = (position == 0) ? "low" : "high"; + if (isNumeric()) + arr[1] = "" + position; + arr[1] += " (" + getVoltageText(volts[0]) + ")"; + arr[2] = "I = " + getCurrentText(getCurrent()); + } + + boolean hasGroundConnection(int n1) { + return true; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, 0, 0); + ei.checkbox = new Checkbox("Momentary Switch", momentary); + return ei; } - - boolean isWireEquivalent() { return false; } - boolean isRemovableWire() { return false; } - - void doStep() { - double v = (position == 0) ? loV : hiV; - if (isTernary()) - v = loV + position * (hiV-loV) * .5; - sim.updateVoltageSource(0, nodes[0], voltSource, v); + if (n == 1) + return new EditInfo("High Logic Voltage", hiV, 10, -10); + if (n == 2) + return new EditInfo("Low Voltage", loV, 10, -10); + if (n == 3) { + EditInfo ei = new EditInfo("", 0, 0, 0); + ei.checkbox = new Checkbox("Numeric", isNumeric()); + return ei; } - int getVoltageSourceCount() { return 1; } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = "logic input"; - arr[1] = (position == 0) ? "low" : "high"; - if (isNumeric()) - arr[1] = "" + position; - arr[1] += " (" + getVoltageText(volts[0]) + ")"; - arr[2] = "I = " + getCurrentText(getCurrent()); - } - boolean hasGroundConnection(int n1) { return true; } - public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, 0, 0); - ei.checkbox = new Checkbox("Momentary Switch", momentary); - return ei; - } - if (n == 1) - return new EditInfo("High Logic Voltage", hiV, 10, -10); - if (n == 2) - return new EditInfo("Low Voltage", loV, 10, -10); - if (n == 3) { - EditInfo ei = new EditInfo("", 0, 0, 0); - ei.checkbox = new Checkbox("Numeric", isNumeric()); - return ei; - } - if (n == 4) { - EditInfo ei = new EditInfo("", 0, 0, 0); - ei.checkbox = new Checkbox("Ternary", isTernary()); - return ei; - } - return null; + if (n == 4) { + EditInfo ei = new EditInfo("", 0, 0, 0); + ei.checkbox = new Checkbox("Ternary", isTernary()); + return ei; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - momentary = ei.checkbox.getState(); - if (n == 1) - hiV = ei.value; - if (n == 2) - loV = ei.value; - if (n == 3) { - if (ei.checkbox.getState()) - flags |= FLAG_NUMERIC; - else - flags &= ~FLAG_NUMERIC; - } - if (n == 4) { - if (ei.checkbox.getState()) - flags |= FLAG_TERNARY; - else - flags &= ~FLAG_TERNARY; - posCount = (isTernary()) ? 3 : 2; - } + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + momentary = ei.checkbox.getState(); + if (n == 1) + hiV = ei.value; + if (n == 2) + loV = ei.value; + if (n == 3) { + if (ei.checkbox.getState()) + flags |= FLAG_NUMERIC; + else + flags &= ~FLAG_NUMERIC; } - int getShortcut() { return 'i'; } - - double getCurrentIntoNode(int n) { - return current; + if (n == 4) { + if (ei.checkbox.getState()) + flags |= FLAG_TERNARY; + else + flags &= ~FLAG_TERNARY; + posCount = (isTernary()) ? 3 : 2; } } + + int getShortcut() { + return 'i'; + } + + double getCurrentIntoNode(int n) { + return current; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/LogicOutputElm.java b/src/com/lushprojects/circuitjs1/client/LogicOutputElm.java index 573080e4..e408da32 100644 --- a/src/com/lushprojects/circuitjs1/client/LogicOutputElm.java +++ b/src/com/lushprojects/circuitjs1/client/LogicOutputElm.java @@ -19,121 +19,150 @@ package com.lushprojects.circuitjs1.client; - class LogicOutputElm extends CircuitElm { - final int FLAG_TERNARY = 1; - final int FLAG_NUMERIC = 2; - final int FLAG_PULLDOWN = 4; - double threshold; - String value; - public LogicOutputElm(int xx, int yy) { - super(xx, yy); +class LogicOutputElm extends CircuitElm { + final int FLAG_TERNARY = 1; + final int FLAG_NUMERIC = 2; + final int FLAG_PULLDOWN = 4; + double threshold; + String value; + + public LogicOutputElm(int xx, int yy) { + super(xx, yy); + threshold = 2.5; + } + + public LogicOutputElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + try { + threshold = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { threshold = 2.5; } - public LogicOutputElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - try { - threshold = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { - threshold = 2.5; - } - } - String dump() { - return super.dump() + " " + threshold; - } - int getDumpType() { return 'M'; } - int getPostCount() { return 1; } - boolean isTernary() { return (flags & FLAG_TERNARY) != 0; } - boolean isNumeric() { return (flags & (FLAG_TERNARY|FLAG_NUMERIC)) != 0; } - boolean needsPullDown() { return (flags & FLAG_PULLDOWN) != 0; } - void setPoints() { - super.setPoints(); - lead1 = interpPoint(point1, point2, 1-12/dn); + } + + String dump() { + return super.dump() + " " + threshold; + } + + int getDumpType() { + return 'M'; + } + + int getPostCount() { + return 1; + } + + boolean isTernary() { + return (flags & FLAG_TERNARY) != 0; + } + + boolean isNumeric() { + return (flags & (FLAG_TERNARY | FLAG_NUMERIC)) != 0; + } + + boolean needsPullDown() { + return (flags & FLAG_PULLDOWN) != 0; + } + + void setPoints() { + super.setPoints(); + lead1 = interpPoint(point1, point2, 1 - 12 / dn); + } + + void draw(Graphics g) { + g.save(); + Font f = new Font("SansSerif", Font.BOLD, 20); + g.setFont(f); + // g.setColor(needsHighlight() ? selectColor : lightGrayColor); + g.setColor(lightGrayColor); + String s = (volts[0] < threshold) ? "L" : "H"; + if (isTernary()) { + // we don't have 2 separate thresholds for ternary inputs so we do this instead + if (volts[0] > threshold * 1.5) // 3.75 V + s = "2"; + else if (volts[0] > threshold * .5) // 1.25 V + s = "1"; + else + s = "0"; + } else if (isNumeric()) + s = (volts[0] < threshold) ? "0" : "1"; + value = s; + setBbox(point1, lead1, 0); + drawCenteredText(g, s, x2, y2, true); + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, lead1); + drawPosts(g); + g.restore(); + } + + void stamp() { + if (needsPullDown()) + sim.stampResistor(nodes[0], 0, 1e6); + } + + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "logic output"; + arr[1] = (volts[0] < threshold) ? "low" : "high"; + if (isNumeric()) + arr[1] = value; + arr[2] = "V = " + getVoltageText(volts[0]); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Threshold", threshold, 10, -10); + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Current Required", needsPullDown()); + return ei; } - void draw(Graphics g) { - g.save(); - Font f = new Font("SansSerif", Font.BOLD, 20); - g.setFont(f); - //g.setColor(needsHighlight() ? selectColor : lightGrayColor); - g.setColor(lightGrayColor); - String s = (volts[0] < threshold) ? "L" : "H"; - if (isTernary()) { - // we don't have 2 separate thresholds for ternary inputs so we do this instead - if (volts[0] > threshold * 1.5) // 3.75 V - s = "2"; - else if (volts[0] > threshold * .5) // 1.25 V - s = "1"; - else - s = "0"; - } else if (isNumeric()) - s = (volts[0] < threshold) ? "0" : "1"; - value = s; - setBbox(point1, lead1, 0); - drawCenteredText(g, s, x2, y2, true); - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, lead1); - drawPosts(g); - g.restore(); + if (n == 2) { + EditInfo ei = new EditInfo("", 0, 0, 0); + ei.checkbox = new Checkbox("Numeric", isNumeric()); + return ei; } - void stamp() { - if (needsPullDown()) - sim.stampResistor(nodes[0], 0, 1e6); + if (n == 3) { + EditInfo ei = new EditInfo("", 0, 0, 0); + ei.checkbox = new Checkbox("Ternary", isTernary()); + return ei; } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = "logic output"; - arr[1] = (volts[0] < threshold) ? "low" : "high"; - if (isNumeric()) - arr[1] = value; - arr[2] = "V = " + getVoltageText(volts[0]); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + threshold = ei.value; + if (n == 1) { + if (ei.checkbox.getState()) + flags |= FLAG_PULLDOWN; + else + flags &= ~FLAG_PULLDOWN; } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Threshold", threshold, 10, -10); - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Current Required", needsPullDown()); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("", 0, 0, 0); - ei.checkbox = new Checkbox("Numeric", isNumeric()); - return ei; - } - if (n == 3) { - EditInfo ei = new EditInfo("", 0, 0, 0); - ei.checkbox = new Checkbox("Ternary", isTernary()); - return ei; - } - return null; + if (n == 2) { + if (ei.checkbox.getState()) + flags |= FLAG_NUMERIC; + else + flags &= ~FLAG_NUMERIC; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - threshold = ei.value; - if (n == 1) { - if (ei.checkbox.getState()) - flags |= FLAG_PULLDOWN; - else - flags &= ~FLAG_PULLDOWN; - } - if (n == 2) { - if (ei.checkbox.getState()) - flags |= FLAG_NUMERIC; - else - flags &= ~FLAG_NUMERIC; - } - if (n == 3) { - if (ei.checkbox.getState()) - flags |= FLAG_TERNARY; - else - flags &= ~FLAG_TERNARY; - } + if (n == 3) { + if (ei.checkbox.getState()) + flags |= FLAG_TERNARY; + else + flags &= ~FLAG_TERNARY; } - int getShortcut() { return 'o'; } - -// void drawHandles(Graphics g, Color c) { -// g.setColor(c); -// g.fillRect(x-3, y-3, 7, 7); -// } - } + + int getShortcut() { + return 'o'; + } + + // void drawHandles(Graphics g, Color c) { + // g.setColor(c); + // g.fillRect(x-3, y-3, 7, 7); + // } + +} diff --git a/src/com/lushprojects/circuitjs1/client/MBBSwitchElm.java b/src/com/lushprojects/circuitjs1/client/MBBSwitchElm.java index e529a15b..4d099fbf 100644 --- a/src/com/lushprojects/circuitjs1/client/MBBSwitchElm.java +++ b/src/com/lushprojects/circuitjs1/client/MBBSwitchElm.java @@ -19,175 +19,196 @@ package com.lushprojects.circuitjs1.client; - class MBBSwitchElm extends SwitchElm { - int link; - int voltSources[]; - double currents[]; - double curcounts[]; - boolean both; - - public MBBSwitchElm(int xx, int yy) { - super(xx, yy, false); - setup(); - } - - void setup() { - noDiagonal = true; - voltSources = new int[2]; - currents = new double[2]; - curcounts = new double[3]; - } - - public MBBSwitchElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - link = new Integer(st.nextToken()).intValue(); - setup(); - } - - int getDumpType() { return 416; } - String dump() { - return super.dump() + " " + link; - } +class MBBSwitchElm extends SwitchElm { + int link; + int voltSources[]; + double currents[]; + double curcounts[]; + boolean both; - final int openhs = 16; - Point swposts[], swpoles[]; - void setPoints() { - super.setPoints(); - calcLeads(32); - swposts = newPointArray(2); - swpoles = newPointArray(2+2); - int i; - for (i = 0; i != 2; i++) { - int hs = -openhs*(i-(2-1)/2); - if (i == 0) - hs = openhs; - interpPoint(lead1, lead2, swpoles[i], 1, hs); - interpPoint(point1, point2, swposts[i], 1, hs); - } - - // 4 positions (pole 1, both, pole 2, both) - posCount = 4; - } - - void draw(Graphics g) { - - setBbox(point1, point2, openhs); - adjustBbox(swposts[0], swposts[1]); + public MBBSwitchElm(int xx, int yy) { + super(xx, yy, false); + setup(); + } - // draw first lead - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, lead1); + void setup() { + noDiagonal = true; + voltSources = new int[2]; + currents = new double[2]; + curcounts = new double[3]; + } - // draw other leads - int i; - for (i = 0; i != 2; i++) { - setVoltageColor(g, volts[i+1]); - drawThickLine(g, swpoles[i], swposts[i]); - } - - // draw switch - if (!needsHighlight()) - g.setColor(whiteColor); - if (both || position == 0) - drawThickLine(g, lead1, swpoles[0]); - if (both || position == 2) - drawThickLine(g, lead1, swpoles[1]); - - // draw current - for (i = 0; i != 2; i++) { - curcounts[i] = updateDotCount(currents[i], curcounts[i]); - drawDots(g, swpoles[i], swposts[i], curcounts[i]); - } - curcounts[2] = updateDotCount(currents[0]+currents[1], curcounts[2]); - drawDots(g, point1, lead1, curcounts[2]); - drawPosts(g); - } - - double getCurrentIntoNode(int n) { - if (n == 0) - return -currents[0]-currents[1]; - return currents[n-1]; - } + public MBBSwitchElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + link = Integer.valueOf(st.nextToken()).intValue(); + setup(); + } - Rectangle getSwitchRect() { - return new Rectangle(lead1).union(new Rectangle(swpoles[0])).union(new Rectangle(swpoles[1])); - } + int getDumpType() { + return 416; + } - Point getPost(int n) { - return (n == 0) ? point1 : swposts[n-1]; - } - - int getPostCount() { return 3; } - - void setCurrent(int vn, double c) { - // set current for voltage source vn to c - if (vn == voltSources[0]) - currents[both ? 0 : position/2] = c; - else if (vn == voltSources[1]) - currents[1] = c; - } - void calculateCurrent() { - // make sure current of unconnected pole is zero - if (!both) - currents[1-(position/2)] = 0; - } - void setVoltageSource(int n, int v) { - voltSources[n] = v; - } - void stamp() { - int vs = 0; - if (both || position == 0) - sim.stampVoltageSource(nodes[0], nodes[1], voltSources[vs++], 0); - if (both || position == 2) - sim.stampVoltageSource(nodes[0], nodes[2], voltSources[vs++], 0); + String dump() { + return super.dump() + " " + link; + } + + final int openhs = 16; + Point swposts[], swpoles[]; + + void setPoints() { + super.setPoints(); + calcLeads(32); + swposts = newPointArray(2); + swpoles = newPointArray(2 + 2); + int i; + for (i = 0; i != 2; i++) { + int hs = -openhs * (i - (2 - 1) / 2); + if (i == 0) + hs = openhs; + interpPoint(lead1, lead2, swpoles[i], 1, hs); + interpPoint(point1, point2, swposts[i], 1, hs); } - - // connection is implemented by voltage source with voltage = 0. - // need two for both loads connected, otherwise one. - int getVoltageSourceCount() { - both = (position == 1 || position == 3); - return (both) ? 2 : 1; + + // 4 positions (pole 1, both, pole 2, both) + posCount = 4; + } + + void draw(Graphics g) { + + setBbox(point1, point2, openhs); + adjustBbox(swposts[0], swposts[1]); + + // draw first lead + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, lead1); + + // draw other leads + int i; + for (i = 0; i != 2; i++) { + setVoltageColor(g, volts[i + 1]); + drawThickLine(g, swpoles[i], swposts[i]); } - void toggle() { - super.toggle(); - if (link != 0) { - int i; - for (i = 0; i != sim.elmList.size(); i++) { - Object o = sim.elmList.elementAt(i); - if (o instanceof MBBSwitchElm) { - MBBSwitchElm s2 = (MBBSwitchElm) o; - if (s2.link == link) - s2.position = position; - } + + // draw switch + if (!needsHighlight()) + g.setColor(whiteColor); + if (both || position == 0) + drawThickLine(g, lead1, swpoles[0]); + if (both || position == 2) + drawThickLine(g, lead1, swpoles[1]); + + // draw current + for (i = 0; i != 2; i++) { + curcounts[i] = updateDotCount(currents[i], curcounts[i]); + drawDots(g, swpoles[i], swposts[i], curcounts[i]); + } + curcounts[2] = updateDotCount(currents[0] + currents[1], curcounts[2]); + drawDots(g, point1, lead1, curcounts[2]); + drawPosts(g); + } + + double getCurrentIntoNode(int n) { + if (n == 0) + return -currents[0] - currents[1]; + return currents[n - 1]; + } + + Rectangle getSwitchRect() { + return new Rectangle(lead1).union(new Rectangle(swpoles[0])).union(new Rectangle(swpoles[1])); + } + + Point getPost(int n) { + return (n == 0) ? point1 : swposts[n - 1]; + } + + int getPostCount() { + return 3; + } + + void setCurrent(int vn, double c) { + // set current for voltage source vn to c + if (vn == voltSources[0]) + currents[both ? 0 : position / 2] = c; + else if (vn == voltSources[1]) + currents[1] = c; + } + + void calculateCurrent() { + // make sure current of unconnected pole is zero + if (!both) + currents[1 - (position / 2)] = 0; + } + + void setVoltageSource(int n, int v) { + voltSources[n] = v; + } + + void stamp() { + int vs = 0; + if (both || position == 0) + sim.stampVoltageSource(nodes[0], nodes[1], voltSources[vs++], 0); + if (both || position == 2) + sim.stampVoltageSource(nodes[0], nodes[2], voltSources[vs++], 0); + } + + // connection is implemented by voltage source with voltage = 0. + // need two for both loads connected, otherwise one. + int getVoltageSourceCount() { + both = (position == 1 || position == 3); + return (both) ? 2 : 1; + } + + void toggle() { + super.toggle(); + if (link != 0) { + int i; + for (i = 0; i != sim.elmList.size(); i++) { + Object o = sim.elmList.elementAt(i); + if (o instanceof MBBSwitchElm) { + MBBSwitchElm s2 = (MBBSwitchElm) o; + if (s2.link == link) + s2.position = position; } } } - boolean getConnection(int n1, int n2) { - if (both) - return true; - return comparePair(n1, n2, 0, 1+position/2); - } - - // do not optimize out, even though isWireEquivalent() is true (because it may have 3 nodes to merge - // and calcWireClosure() doesn't handle that case) - boolean isRemovableWire() { return false; } - boolean isWireEquivalent() { return true; } - - void getInfo(String arr[]) { - arr[0] = "switch (" + (link == 0 ? "S" : "D") + "PDT, MBB)"; - arr[1] = "I = " + getCurrentDText(getCurrent()); - } - public EditInfo getEditInfo(int n) { - if (n == 1) - return new EditInfo("Switch Group", link, 0, 100).setDimensionless(); - return super.getEditInfo(n); - } - public void setEditValue(int n, EditInfo ei) { - if (n == 1) { - link = (int) ei.value; - } else - super.setEditValue(n, ei); - } - int getShortcut() { return 0; } } + + boolean getConnection(int n1, int n2) { + if (both) + return true; + return comparePair(n1, n2, 0, 1 + position / 2); + } + + // do not optimize out, even though isWireEquivalent() is true (because it may + // have 3 nodes to merge + // and calcWireClosure() doesn't handle that case) + boolean isRemovableWire() { + return false; + } + + boolean isWireEquivalent() { + return true; + } + + void getInfo(String arr[]) { + arr[0] = "switch (" + (link == 0 ? "S" : "D") + "PDT, MBB)"; + arr[1] = "I = " + getCurrentDText(getCurrent()); + } + + public EditInfo getEditInfo(int n) { + if (n == 1) + return new EditInfo("Switch Group", link, 0, 100).setDimensionless(); + return super.getEditInfo(n); + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 1) { + link = (int) ei.value; + } else + super.setEditValue(n, ei); + } + + int getShortcut() { + return 0; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/MemristorElm.java b/src/com/lushprojects/circuitjs1/client/MemristorElm.java index fbc8964e..65008b80 100644 --- a/src/com/lushprojects/circuitjs1/client/MemristorElm.java +++ b/src/com/lushprojects/circuitjs1/client/MemristorElm.java @@ -23,137 +23,156 @@ class MemristorElm extends CircuitElm { double r_on, r_off, dopeWidth, totalWidth, mobility, resistance; + public MemristorElm(int xx, int yy) { super(xx, yy); r_on = 100; - r_off = 160*r_on; + r_off = 160 * r_on; dopeWidth = 0; totalWidth = 10e-9; // meters - mobility = 1e-10; // m^2/sV + mobility = 1e-10; // m^2/sV resistance = 100; } - public MemristorElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public MemristorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - r_on = new Double(st.nextToken()).doubleValue(); - r_off = new Double(st.nextToken()).doubleValue(); - dopeWidth = new Double(st.nextToken()).doubleValue(); - totalWidth = new Double(st.nextToken()).doubleValue(); - mobility = new Double(st.nextToken()).doubleValue(); + r_on = Double.valueOf(st.nextToken()).doubleValue(); + r_off = Double.valueOf(st.nextToken()).doubleValue(); + dopeWidth = Double.valueOf(st.nextToken()).doubleValue(); + totalWidth = Double.valueOf(st.nextToken()).doubleValue(); + mobility = Double.valueOf(st.nextToken()).doubleValue(); try { current = Double.parseDouble(st.nextToken()); - } catch (Exception e) {} + } catch (Exception e) { + } resistance = 100; } - int getDumpType() { return 'm'; } + + int getDumpType() { + return 'm'; + } + String dump() { - return super.dump() + " " + r_on + " " + r_off + " " + dopeWidth + " " + - totalWidth + " " + mobility + " " + current; + return super.dump() + " " + r_on + " " + r_off + " " + dopeWidth + " " + totalWidth + " " + mobility + " " + + current; } Point ps3, ps4; + void setPoints() { super.setPoints(); calcLeads(32); ps3 = new Point(); ps4 = new Point(); } - + void draw(Graphics g) { int segments = 6; int i; int ox = 0; double v1 = volts[0]; double v2 = volts[1]; - int hs = 2+(int) (8*(1-dopeWidth/totalWidth)); + int hs = 2 + (int) (8 * (1 - dopeWidth / totalWidth)); setBbox(point1, point2, hs); draw2Leads(g); setPowerColor(g, true); - double segf = 1./segments; + double segf = 1. / segments; // draw zigzag for (i = 0; i <= segments; i++) { int nx = (i & 1) == 0 ? 1 : -1; if (i == segments) nx = 0; - double v = v1+(v2-v1)*i/segments; + double v = v1 + (v2 - v1) * i / segments; setVoltageColor(g, v); - interpPoint(lead1, lead2, ps1, i*segf, hs*ox); - interpPoint(lead1, lead2, ps2, i*segf, hs*nx); + interpPoint(lead1, lead2, ps1, i * segf, hs * ox); + interpPoint(lead1, lead2, ps2, i * segf, hs * nx); drawThickLine(g, ps1, ps2); if (i == segments) break; - interpPoint(lead1, lead2, ps1, (i+1)*segf, hs*nx); + interpPoint(lead1, lead2, ps1, (i + 1) * segf, hs * nx); drawThickLine(g, ps1, ps2); ox = nx; } - + doDots(g); drawPosts(g); } - - boolean nonLinear() { return true; } + + boolean nonLinear() { + return true; + } + void calculateCurrent() { - current = (volts[0]-volts[1])/resistance; + current = (volts[0] - volts[1]) / resistance; } + void reset() { dopeWidth = 0; } + void startIteration() { - double wd = dopeWidth/totalWidth; - dopeWidth += sim.timeStep*mobility*r_on*current/totalWidth; + double wd = dopeWidth / totalWidth; + dopeWidth += sim.timeStep * mobility * r_on * current / totalWidth; if (dopeWidth < 0) dopeWidth = 0; if (dopeWidth > totalWidth) dopeWidth = totalWidth; - resistance = r_on * wd + r_off * (1-wd); + resistance = r_on * wd + r_off * (1 - wd); } + void stamp() { sim.stampNonLinear(nodes[0]); sim.stampNonLinear(nodes[1]); } + void doStep() { sim.stampResistor(nodes[0], nodes[1], resistance); } + void getInfo(String arr[]) { arr[0] = "memristor"; getBasicInfo(arr); arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); arr[4] = "P = " + getUnitText(getPower(), "W"); } + double getScopeValue(int x) { return (x == Scope.VAL_R) ? resistance : super.getScopeValue(x); } + int getScopeUnits(int x) { return (x == Scope.VAL_R) ? Scope.UNITS_OHMS : super.getScopeUnits(x); } + boolean canShowValueInScope(int x) { return x == Scope.VAL_R; } + public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Min Resistance (ohms)", r_on, 0, 0); if (n == 1) return new EditInfo("Max Resistance (ohms)", r_off, 0, 0); if (n == 2) - return new EditInfo("Width of Doped Region (nm)", dopeWidth*1e9, 0, 0); + return new EditInfo("Width of Doped Region (nm)", dopeWidth * 1e9, 0, 0); if (n == 3) - return new EditInfo("Total Width (nm)", totalWidth*1e9, 0, 0); + return new EditInfo("Total Width (nm)", totalWidth * 1e9, 0, 0); if (n == 4) - return new EditInfo("Mobility (um^2/(s*V))", mobility*1e12, 0, 0); + return new EditInfo("Mobility (um^2/(s*V))", mobility * 1e12, 0, 0); return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) r_on = ei.value; if (n == 1) r_off = ei.value; if (n == 2) - dopeWidth = ei.value*1e-9; + dopeWidth = ei.value * 1e-9; if (n == 3) - totalWidth = ei.value*1e-9; + totalWidth = ei.value * 1e-9; if (n == 4) - mobility = ei.value*1e-12; + mobility = ei.value * 1e-12; } } - diff --git a/src/com/lushprojects/circuitjs1/client/MonostableElm.java b/src/com/lushprojects/circuitjs1/client/MonostableElm.java index 5c4a1b89..9519c481 100644 --- a/src/com/lushprojects/circuitjs1/client/MonostableElm.java +++ b/src/com/lushprojects/circuitjs1/client/MonostableElm.java @@ -19,90 +19,103 @@ package com.lushprojects.circuitjs1.client; - class MonostableElm extends ChipElm { - - //Used to detect rising edge - private boolean prevInputValue=false; - private boolean retriggerable=false; - private boolean triggered=false; - private double lastRisingEdge=0; - private double delay=0.01; - - public MonostableElm(int xx, int yy) { - super(xx, yy); - reset(); - } - public MonostableElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - retriggerable=new Boolean(st.nextToken()).booleanValue(); - delay=new Double(st.nextToken()).doubleValue(); - reset(); - } - String getChipName() { return "Monostable"; } - void setupPins() { - sizeX = 2; - sizeY = 2; - pins = new Pin[getPostCount()]; - pins[0] = new Pin(0, SIDE_W, ""); - pins[0].clock = true; - pins[1] = new Pin(0, SIDE_E, "Q"); - pins[1].output=true; - pins[2] = new Pin(1, SIDE_E, "Q"); - pins[2].output=true; - pins[2].lineOver=true; +class MonostableElm extends ChipElm { + + // Used to detect rising edge + private boolean prevInputValue = false; + private boolean retriggerable = false; + private boolean triggered = false; + private double lastRisingEdge = 0; + private double delay = 0.01; + + public MonostableElm(int xx, int yy) { + super(xx, yy); + reset(); + } + + public MonostableElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + retriggerable = Boolean.valueOf(st.nextToken()).booleanValue(); + delay = Double.valueOf(st.nextToken()).doubleValue(); + reset(); + } + + String getChipName() { + return "Monostable"; + } + + void setupPins() { + sizeX = 2; + sizeY = 2; + pins = new Pin[getPostCount()]; + pins[0] = new Pin(0, SIDE_W, ""); + pins[0].clock = true; + pins[1] = new Pin(0, SIDE_E, "Q"); + pins[1].output = true; + pins[2] = new Pin(1, SIDE_E, "Q"); + pins[2].output = true; + pins[2].lineOver = true; + } + + void reset() { + super.reset(); + pins[2].value = true; + triggered = prevInputValue = false; + } + + int getPostCount() { + return 3; + } + + int getVoltageSourceCount() { + return 2; + } + + void execute() { + + if (pins[0].value && prevInputValue != pins[0].value && (retriggerable || !triggered)) { + lastRisingEdge = sim.t; + pins[1].value = true; + pins[2].value = false; + triggered = true; } - - void reset() { - super.reset(); + + if (triggered && sim.t > lastRisingEdge + delay) { + pins[1].value = false; pins[2].value = true; - triggered = prevInputValue = false; + triggered = false; } - int getPostCount() { - return 3; + prevInputValue = pins[0].value; + } + + String dump() { + return super.dump() + " " + retriggerable + " " + delay; + } + + int getDumpType() { + return 194; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Retriggerable", retriggerable); + return ei; } - int getVoltageSourceCount() { return 2; } - - void execute() { - - if(pins[0].value&&prevInputValue!=pins[0].value&&(retriggerable||!triggered)){ - lastRisingEdge=sim.t; - pins[1].value=true; - pins[2].value=false; - triggered=true; - } - - if(triggered&&sim.t>lastRisingEdge+delay) - { - pins[1].value=false; - pins[2].value=true; - triggered=false; - } - prevInputValue=pins[0].value; - } - String dump(){ - return super.dump() + " " + retriggerable + " " + delay; + if (n == 1) { + EditInfo ei = new EditInfo("Period (s)", delay, 0.001, 0.1); + return ei; } - int getDumpType() { return 194; } - public EditInfo getChipEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox=new Checkbox("Retriggerable",retriggerable); - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("Period (s)",delay, 0.001,0.1); - return ei; - } - return super.getChipEditInfo(n); + return super.getChipEditInfo(n); + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0) { + retriggerable = ei.checkbox.getState(); } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0) { - retriggerable=ei.checkbox.getState(); - } - if (n == 1) { - delay=ei.value; - } - super.setChipEditValue(n, ei); + if (n == 1) { + delay = ei.value; } + super.setChipEditValue(n, ei); } +} diff --git a/src/com/lushprojects/circuitjs1/client/MosfetElm.java b/src/com/lushprojects/circuitjs1/client/MosfetElm.java index 7302259d..5d52b5f2 100644 --- a/src/com/lushprojects/circuitjs1/client/MosfetElm.java +++ b/src/com/lushprojects/circuitjs1/client/MosfetElm.java @@ -22,517 +22,567 @@ import com.lushprojects.circuitjs1.client.util.Locale; class MosfetElm extends CircuitElm { - int pnp; - int FLAG_PNP = 1; - int FLAG_SHOWVT = 2; - int FLAG_DIGITAL = 4; - int FLAG_FLIP = 8; - int FLAG_HIDE_BULK = 16; - int FLAG_BODY_DIODE = 32; - int FLAG_BODY_TERMINAL = 64; - int FLAGS_GLOBAL = (FLAG_HIDE_BULK|FLAG_DIGITAL); - int bodyTerminal; - - double vt; - // beta = 1/(RdsON*(Vgs-Vt)) - double beta; - static int globalFlags; - Diode diodeB1, diodeB2; - double diodeCurrent1, diodeCurrent2, bodyCurrent; - double curcount_body1, curcount_body2; - static double lastBeta; - - MosfetElm(int xx, int yy, boolean pnpflag) { - super(xx, yy); - pnp = (pnpflag) ? -1 : 1; - flags = (pnpflag) ? FLAG_PNP : 0; - flags |= FLAG_BODY_DIODE; - noDiagonal = true; - setupDiodes(); - beta = getDefaultBeta(); - vt = getDefaultThreshold(); + int pnp; + int FLAG_PNP = 1; + int FLAG_SHOWVT = 2; + int FLAG_DIGITAL = 4; + int FLAG_FLIP = 8; + int FLAG_HIDE_BULK = 16; + int FLAG_BODY_DIODE = 32; + int FLAG_BODY_TERMINAL = 64; + int FLAGS_GLOBAL = (FLAG_HIDE_BULK | FLAG_DIGITAL); + int bodyTerminal; + + double vt; + // beta = 1/(RdsON*(Vgs-Vt)) + double beta; + static int globalFlags; + Diode diodeB1, diodeB2; + double diodeCurrent1, diodeCurrent2, bodyCurrent; + double curcount_body1, curcount_body2; + static double lastBeta; + + MosfetElm(int xx, int yy, boolean pnpflag) { + super(xx, yy); + pnp = (pnpflag) ? -1 : 1; + flags = (pnpflag) ? FLAG_PNP : 0; + flags |= FLAG_BODY_DIODE; + noDiagonal = true; + setupDiodes(); + beta = getDefaultBeta(); + vt = getDefaultThreshold(); + } + + public MosfetElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + pnp = ((f & FLAG_PNP) != 0) ? -1 : 1; + noDiagonal = true; + setupDiodes(); + vt = getDefaultThreshold(); + beta = getBackwardCompatibilityBeta(); + try { + vt = Double.valueOf(st.nextToken()).doubleValue(); + beta = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } - - public MosfetElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - pnp = ((f & FLAG_PNP) != 0) ? -1 : 1; - noDiagonal = true; - setupDiodes(); - vt = getDefaultThreshold(); - beta = getBackwardCompatibilityBeta(); - try { - vt = new Double(st.nextToken()).doubleValue(); - beta = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) {} - globalFlags = flags & (FLAGS_GLOBAL); - allocNodes(); // make sure volts[] has the right number of elements when hasBodyTerminal() is true + globalFlags = flags & (FLAGS_GLOBAL); + allocNodes(); // make sure volts[] has the right number of elements when hasBodyTerminal() is + // true + } + + // set up body diodes + void setupDiodes() { + // diode from node 1 to body terminal + diodeB1 = new Diode(sim); + diodeB1.setupForDefaultModel(); + // diode from node 2 to body terminal + diodeB2 = new Diode(sim); + diodeB2.setupForDefaultModel(); + } + + double getDefaultThreshold() { + return 1.5; + } + + // default beta for new elements + double getDefaultBeta() { + return lastBeta == 0 ? getBackwardCompatibilityBeta() : lastBeta; + } + + // default for elements in old files with no configurable beta. JfetElm + // overrides this. + // Not sure where this value came from, but the ZVP3306A has a beta of about + // .027. Power MOSFETs have much higher betas (like 80 or more) + double getBackwardCompatibilityBeta() { + return .02; + } + + boolean nonLinear() { + return true; + } + + boolean drawDigital() { + return (flags & FLAG_DIGITAL) != 0; + } + + boolean showBulk() { + return (flags & (FLAG_DIGITAL | FLAG_HIDE_BULK)) == 0; + } + + boolean hasBodyTerminal() { + return (flags & FLAG_BODY_TERMINAL) != 0 && doBodyDiode(); + } + + boolean doBodyDiode() { + return (flags & FLAG_BODY_DIODE) != 0 && showBulk(); + } + + void reset() { + lastv1 = lastv2 = volts[0] = volts[1] = volts[2] = curcount = 0; + curcount_body1 = curcount_body2 = 0; + diodeB1.reset(); + diodeB2.reset(); + if (doBodyDiode()) + volts[bodyTerminal] = 0; + } + + String dump() { + return super.dump() + " " + vt + " " + beta; + } + + int getDumpType() { + return 'f'; + } + + final int hs = 16; + + void draw(Graphics g) { + // pick up global flags changes + if ((flags & FLAGS_GLOBAL) != globalFlags) + setPoints(); + + setBbox(point1, point2, hs); + + // draw source/drain terminals + setVoltageColor(g, volts[1]); + drawThickLine(g, src[0], src[1]); + setVoltageColor(g, volts[2]); + drawThickLine(g, drn[0], drn[1]); + + // draw line connecting source and drain + int segments = 6; + int i; + setPowerColor(g, true); + boolean power = sim.powerCheckItem.getState(); + double segf = 1. / segments; + boolean enhancement = vt > 0 && showBulk(); + for (i = 0; i != segments; i++) { + if ((i == 1 || i == 4) && enhancement) + continue; + double v = volts[1] + (volts[2] - volts[1]) * i / segments; + if (!power) + setVoltageColor(g, v); + interpPoint(src[1], drn[1], ps1, i * segf); + interpPoint(src[1], drn[1], ps2, (i + 1) * segf); + drawThickLine(g, ps1, ps2); } - // set up body diodes - void setupDiodes() { - // diode from node 1 to body terminal - diodeB1 = new Diode(sim); - diodeB1.setupForDefaultModel(); - // diode from node 2 to body terminal - diodeB2 = new Diode(sim); - diodeB2.setupForDefaultModel(); + // draw little extensions of that line + if (!power) + setVoltageColor(g, volts[1]); + drawThickLine(g, src[1], src[2]); + if (!power) + setVoltageColor(g, volts[2]); + drawThickLine(g, drn[1], drn[2]); + + // draw bulk connection + if (showBulk()) { + setVoltageColor(g, volts[bodyTerminal]); + if (!hasBodyTerminal()) + drawThickLine(g, pnp == -1 ? drn[0] : src[0], body[0]); + drawThickLine(g, body[0], body[1]); } - - double getDefaultThreshold() { return 1.5; } - - // default beta for new elements - double getDefaultBeta() { return lastBeta == 0 ? getBackwardCompatibilityBeta() : lastBeta; } - - // default for elements in old files with no configurable beta. JfetElm overrides this. - // Not sure where this value came from, but the ZVP3306A has a beta of about .027. Power MOSFETs have much higher betas (like 80 or more) - double getBackwardCompatibilityBeta() { return .02; } - - boolean nonLinear() { return true; } - boolean drawDigital() { return (flags & FLAG_DIGITAL) != 0; } - boolean showBulk() { return (flags & (FLAG_DIGITAL|FLAG_HIDE_BULK)) == 0; } - boolean hasBodyTerminal() { return (flags & FLAG_BODY_TERMINAL) != 0 && doBodyDiode(); } - boolean doBodyDiode() { return (flags & FLAG_BODY_DIODE) != 0 && showBulk(); } - void reset() { - lastv1 = lastv2 = volts[0] = volts[1] = volts[2] = curcount = 0; - curcount_body1 = curcount_body2 = 0; - diodeB1.reset(); - diodeB2.reset(); - if (doBodyDiode()) - volts[bodyTerminal] = 0; + + // draw arrow + if (!drawDigital()) { + setVoltageColor(g, volts[bodyTerminal]); + g.fillPolygon(arrowPoly); } - String dump() { - return super.dump() + " " + vt + " " + beta; + if (power) + g.setColor(Color.gray); + + // draw gate + setVoltageColor(g, volts[0]); + drawThickLine(g, point1, gate[1]); + drawThickLine(g, gate[0], gate[2]); + if (drawDigital() && pnp == -1) + drawThickCircle(g, pcircle.x, pcircle.y, pcircler); + + if ((flags & FLAG_SHOWVT) != 0) { + String s = "" + (vt * pnp); + g.setColor(whiteColor); + g.setFont(unitsFont); + drawCenteredText(g, s, x2 + 2, y2, false); } - int getDumpType() { return 'f'; } - final int hs = 16; - - void draw(Graphics g) { - // pick up global flags changes - if ((flags & FLAGS_GLOBAL) != globalFlags) - setPoints(); - - setBbox(point1, point2, hs); - - // draw source/drain terminals - setVoltageColor(g, volts[1]); - drawThickLine(g, src[0], src[1]); - setVoltageColor(g, volts[2]); - drawThickLine(g, drn[0], drn[1]); - - // draw line connecting source and drain - int segments = 6; - int i; - setPowerColor(g, true); - boolean power = sim.powerCheckItem.getState(); - double segf = 1./segments; - boolean enhancement = vt > 0 && showBulk(); - for (i = 0; i != segments; i++) { - if ((i == 1 || i == 4) && enhancement) continue; - double v = volts[1]+(volts[2]-volts[1])*i/segments; - if (!power) - setVoltageColor(g, v); - interpPoint(src[1], drn[1], ps1, i*segf); - interpPoint(src[1], drn[1], ps2, (i+1)*segf); - drawThickLine(g, ps1, ps2); - } - - // draw little extensions of that line - if (!power) - setVoltageColor(g, volts[1]); - drawThickLine(g, src[1], src[2]); - if (!power) - setVoltageColor(g, volts[2]); - drawThickLine(g, drn[1], drn[2]); - - // draw bulk connection - if (showBulk()) { - setVoltageColor(g, volts[bodyTerminal]); - if (!hasBodyTerminal()) - drawThickLine(g, pnp == -1 ? drn[0] : src[0], body[0]); - drawThickLine(g, body[0], body[1]); - } - - // draw arrow - if (!drawDigital()) { - setVoltageColor(g, volts[bodyTerminal]); - g.fillPolygon(arrowPoly); - } - if (power) - g.setColor(Color.gray); - - // draw gate - setVoltageColor(g, volts[0]); - drawThickLine(g, point1, gate[1]); - drawThickLine(g, gate[0], gate[2]); - if (drawDigital() && pnp == -1) - drawThickCircle(g, pcircle.x, pcircle.y, pcircler); - - if ((flags & FLAG_SHOWVT) != 0) { - String s = "" + (vt*pnp); - g.setColor(whiteColor); - g.setFont(unitsFont); - drawCenteredText(g, s, x2+2, y2, false); - } - curcount = updateDotCount(-ids, curcount); - drawDots(g, src[0], src[1], curcount); - drawDots(g, src[1], drn[1], curcount); - drawDots(g, drn[1], drn[0], curcount); - - if (showBulk()) { - curcount_body1 = updateDotCount(diodeCurrent1, curcount_body1); - curcount_body2 = updateDotCount(diodeCurrent2, curcount_body2); - drawDots(g, src [0], body[0], -curcount_body1); - drawDots(g, body[0], drn [0], curcount_body2); - } - - // label pins when highlighted - if (needsHighlight() || sim.dragElm == this) { - g.setColor(whiteColor); - g.setFont(unitsFont); - - // make fiddly adjustments to pin label locations depending on orientation - int dsx = sign(dx); - int dsy = sign(dy); - int dsyn = dy == 0 ? 0 : 1; - - g.drawString("G", gate[1].x - (dx < 0 ? -2 : 12), gate[1].y + ((dy > 0) ? -5 : 12)); - g.drawString(pnp == -1 ? "D" : "S", src[0].x-3+9*(dsx-dsyn*pnp), src[0].y+4); - g.drawString(pnp == -1 ? "S" : "D", drn[0].x-3+9*(dsx-dsyn*pnp), drn[0].y+4); - if (hasBodyTerminal()) - g.drawString("B", body[0].x-3+9*(dsx-dsyn*pnp), body[0].y+4); - } - - drawPosts(g); + curcount = updateDotCount(-ids, curcount); + drawDots(g, src[0], src[1], curcount); + drawDots(g, src[1], drn[1], curcount); + drawDots(g, drn[1], drn[0], curcount); + + if (showBulk()) { + curcount_body1 = updateDotCount(diodeCurrent1, curcount_body1); + curcount_body2 = updateDotCount(diodeCurrent2, curcount_body2); + drawDots(g, src[0], body[0], -curcount_body1); + drawDots(g, body[0], drn[0], curcount_body2); } - - // post 0 = gate, 1 = source for NPN, 2 = drain for NPN, 3 = body (if present) - // for PNP, 1 is drain, 2 is source - Point getPost(int n) { - return (n == 0) ? point1 : (n == 1) ? src[0] : - (n == 2) ? drn[0] : body[0]; + + // label pins when highlighted + if (needsHighlight() || sim.dragElm == this) { + g.setColor(whiteColor); + g.setFont(unitsFont); + + // make fiddly adjustments to pin label locations depending on orientation + int dsx = sign(dx); + int dsy = sign(dy); + int dsyn = dy == 0 ? 0 : 1; + + g.drawString("G", gate[1].x - (dx < 0 ? -2 : 12), gate[1].y + ((dy > 0) ? -5 : 12)); + g.drawString(pnp == -1 ? "D" : "S", src[0].x - 3 + 9 * (dsx - dsyn * pnp), src[0].y + 4); + g.drawString(pnp == -1 ? "S" : "D", drn[0].x - 3 + 9 * (dsx - dsyn * pnp), drn[0].y + 4); + if (hasBodyTerminal()) + g.drawString("B", body[0].x - 3 + 9 * (dsx - dsyn * pnp), body[0].y + 4); } - - double getCurrent() { return ids; } - double getPower() { - return ids*(volts[2]-volts[1]) - diodeCurrent1*(volts[1]-volts[bodyTerminal]) - diodeCurrent2*(volts[2]-volts[bodyTerminal]); - } - int getPostCount() { return hasBodyTerminal() ? 4 : 3; } - - int pcircler; - - // points for source and drain (these are swapped on PNP mosfets) - Point src[], drn[]; - - // points for gate, body, and the little circle on PNP mosfets - Point gate[], body[], pcircle; - Polygon arrowPoly; - - void setPoints() { - super.setPoints(); - - // these two flags apply to all mosfets - flags &= ~FLAGS_GLOBAL; - flags |= globalFlags; - - // find the coordinates of the various points we need to draw - // the MOSFET. - int hs2 = hs*dsign; - if ((flags & FLAG_FLIP) != 0) - hs2 = -hs2; - src = newPointArray(3); - drn = newPointArray(3); - interpPoint2(point1, point2, src[0], drn[0], 1, -hs2); - interpPoint2(point1, point2, src[1], drn[1], 1-22/dn, -hs2); - interpPoint2(point1, point2, src[2], drn[2], 1-22/dn, -hs2*4/3); - - gate = newPointArray(3); - interpPoint2(point1, point2, gate[0], gate[2], 1-28/dn, hs2/2); // was 1-20/dn - interpPoint(gate[0], gate[2], gate[1], .5); - - if (showBulk()) { - body = newPointArray(2); - interpPoint(src[0], drn[0], body[0], .5); - interpPoint(src[1], drn[1], body[1], .5); - } - - if (!drawDigital()) { - if (pnp == 1) { - if (!showBulk()) - arrowPoly = calcArrow(src[1], src[0], 10, 4); - else - arrowPoly = calcArrow(body[0], body[1], 12, 5); - } else { - if (!showBulk()) - arrowPoly = calcArrow(drn[0], drn[1], 12, 5); - else - arrowPoly = calcArrow(body[1], body[0], 12, 5); - } - } else if (pnp == -1) { - interpPoint(point1, point2, gate[1], 1-36/dn); - int dist = (dsign < 0) ? 32 : 31; - pcircle = interpPoint(point1, point2, 1-dist/dn); - pcircler = 3; + + drawPosts(g); + } + + // post 0 = gate, 1 = source for NPN, 2 = drain for NPN, 3 = body (if present) + // for PNP, 1 is drain, 2 is source + Point getPost(int n) { + return (n == 0) ? point1 : (n == 1) ? src[0] : (n == 2) ? drn[0] : body[0]; + } + + double getCurrent() { + return ids; + } + + double getPower() { + return ids * (volts[2] - volts[1]) - diodeCurrent1 * (volts[1] - volts[bodyTerminal]) + - diodeCurrent2 * (volts[2] - volts[bodyTerminal]); + } + + int getPostCount() { + return hasBodyTerminal() ? 4 : 3; + } + + int pcircler; + + // points for source and drain (these are swapped on PNP mosfets) + Point src[], drn[]; + + // points for gate, body, and the little circle on PNP mosfets + Point gate[], body[], pcircle; + Polygon arrowPoly; + + void setPoints() { + super.setPoints(); + + // these two flags apply to all mosfets + flags &= ~FLAGS_GLOBAL; + flags |= globalFlags; + + // find the coordinates of the various points we need to draw + // the MOSFET. + int hs2 = hs * dsign; + if ((flags & FLAG_FLIP) != 0) + hs2 = -hs2; + src = newPointArray(3); + drn = newPointArray(3); + interpPoint2(point1, point2, src[0], drn[0], 1, -hs2); + interpPoint2(point1, point2, src[1], drn[1], 1 - 22 / dn, -hs2); + interpPoint2(point1, point2, src[2], drn[2], 1 - 22 / dn, -hs2 * 4 / 3); + + gate = newPointArray(3); + interpPoint2(point1, point2, gate[0], gate[2], 1 - 28 / dn, hs2 / 2); // was 1-20/dn + interpPoint(gate[0], gate[2], gate[1], .5); + + if (showBulk()) { + body = newPointArray(2); + interpPoint(src[0], drn[0], body[0], .5); + interpPoint(src[1], drn[1], body[1], .5); + } + + if (!drawDigital()) { + if (pnp == 1) { + if (!showBulk()) + arrowPoly = calcArrow(src[1], src[0], 10, 4); + else + arrowPoly = calcArrow(body[0], body[1], 12, 5); + } else { + if (!showBulk()) + arrowPoly = calcArrow(drn[0], drn[1], 12, 5); + else + arrowPoly = calcArrow(body[1], body[0], 12, 5); } + } else if (pnp == -1) { + interpPoint(point1, point2, gate[1], 1 - 36 / dn); + int dist = (dsign < 0) ? 32 : 31; + pcircle = interpPoint(point1, point2, 1 - dist / dn); + pcircler = 3; } + } - double lastv1, lastv2; - double ids; - int mode = 0; - double gm = 0; - - void stamp() { - sim.stampNonLinear(nodes[1]); - sim.stampNonLinear(nodes[2]); - - if (hasBodyTerminal()) - bodyTerminal = 3; - else - bodyTerminal = (pnp == -1) ? 2 : 1; - - if (doBodyDiode()) { - if (pnp == -1) { - // pnp: diodes conduct when S or D are higher than body - diodeB1.stamp(nodes[1], nodes[bodyTerminal]); - diodeB2.stamp(nodes[2], nodes[bodyTerminal]); - } else { - // npn: diodes conduct when body is higher than S or D - diodeB1.stamp(nodes[bodyTerminal], nodes[1]); - diodeB2.stamp(nodes[bodyTerminal], nodes[2]); - } + double lastv1, lastv2; + double ids; + int mode = 0; + double gm = 0; + + void stamp() { + sim.stampNonLinear(nodes[1]); + sim.stampNonLinear(nodes[2]); + + if (hasBodyTerminal()) + bodyTerminal = 3; + else + bodyTerminal = (pnp == -1) ? 2 : 1; + + if (doBodyDiode()) { + if (pnp == -1) { + // pnp: diodes conduct when S or D are higher than body + diodeB1.stamp(nodes[1], nodes[bodyTerminal]); + diodeB2.stamp(nodes[2], nodes[bodyTerminal]); + } else { + // npn: diodes conduct when body is higher than S or D + diodeB1.stamp(nodes[bodyTerminal], nodes[1]); + diodeB2.stamp(nodes[bodyTerminal], nodes[2]); } } - - boolean nonConvergence(double last, double now) { - double diff = Math.abs(last-now); - - // high beta MOSFETs are more sensitive to small differences, so we are more strict about convergence testing - if (beta > 1) - diff *= 100; - - // difference of less than 10mV is fine - if (diff < .01) - return false; - // larger differences are fine if value is large - if (sim.subIterations > 10 && diff < Math.abs(now)*.001) - return false; - // if we're having trouble converging, get more lenient - if (sim.subIterations > 100 && diff < .01+(sim.subIterations-100)*.0001) - return false; - return true; + } + + boolean nonConvergence(double last, double now) { + double diff = Math.abs(last - now); + + // high beta MOSFETs are more sensitive to small differences, so we are more + // strict about convergence testing + if (beta > 1) + diff *= 100; + + // difference of less than 10mV is fine + if (diff < .01) + return false; + // larger differences are fine if value is large + if (sim.subIterations > 10 && diff < Math.abs(now) * .001) + return false; + // if we're having trouble converging, get more lenient + if (sim.subIterations > 100 && diff < .01 + (sim.subIterations - 100) * .0001) + return false; + return true; + } + + void stepFinished() { + calculate(true); + + // fix current if body is connected to source or drain + if (bodyTerminal == 1) + diodeCurrent1 = -diodeCurrent2; + if (bodyTerminal == 2) + diodeCurrent2 = -diodeCurrent1; + } + + void doStep() { + calculate(false); + } + + double lastv0; + + // this is called in doStep to stamp the matrix, and also called in + // stepFinished() to calculate the current + void calculate(boolean finished) { + double vs[]; + if (finished) + vs = volts; + else { + // limit voltage changes to .5V + vs = new double[3]; + vs[0] = volts[0]; + vs[1] = volts[1]; + vs[2] = volts[2]; + if (vs[1] > lastv1 + .5) + vs[1] = lastv1 + .5; + if (vs[1] < lastv1 - .5) + vs[1] = lastv1 - .5; + if (vs[2] > lastv2 + .5) + vs[2] = lastv2 + .5; + if (vs[2] < lastv2 - .5) + vs[2] = lastv2 - .5; + } + + int source = 1; + int drain = 2; + + // if source voltage > drain (for NPN), swap source and drain + // (opposite for PNP) + if (pnp * vs[1] > pnp * vs[2]) { + source = 2; + drain = 1; } - - void stepFinished() { - calculate(true); - - // fix current if body is connected to source or drain - if (bodyTerminal == 1) - diodeCurrent1 = -diodeCurrent2; - if (bodyTerminal == 2) - diodeCurrent2 = -diodeCurrent1; + int gate = 0; + double vgs = vs[gate] - vs[source]; + double vds = vs[drain] - vs[source]; + if (!finished + && (nonConvergence(lastv1, vs[1]) || nonConvergence(lastv2, vs[2]) || nonConvergence(lastv0, vs[0]))) + sim.converged = false; + lastv0 = vs[0]; + lastv1 = vs[1]; + lastv2 = vs[2]; + double realvgs = vgs; + double realvds = vds; + vgs *= pnp; + vds *= pnp; + ids = 0; + gm = 0; + double Gds = 0; + if (vgs < vt) { + // should be all zero, but that causes a singular matrix, + // so instead we treat it as a large resistor + Gds = 1e-8; + ids = vds * Gds; + mode = 0; + } else if (vds < vgs - vt) { + // linear + ids = beta * ((vgs - vt) * vds - vds * vds * .5); + gm = beta * vds; + Gds = beta * (vgs - vds - vt); + mode = 1; + } else { + // saturation; Gds = 0 + gm = beta * (vgs - vt); + // use very small Gds to avoid nonconvergence + Gds = 1e-8; + ids = .5 * beta * (vgs - vt) * (vgs - vt) + (vds - (vgs - vt)) * Gds; + mode = 2; } - void doStep() { - calculate(false); + if (doBodyDiode()) { + diodeB1.doStep(pnp * (volts[bodyTerminal] - volts[1])); + diodeCurrent1 = diodeB1.calculateCurrent(pnp * (volts[bodyTerminal] - volts[1])) * pnp; + diodeB2.doStep(pnp * (volts[bodyTerminal] - volts[2])); + diodeCurrent2 = diodeB2.calculateCurrent(pnp * (volts[bodyTerminal] - volts[2])) * pnp; + } else + diodeCurrent1 = diodeCurrent2 = 0; + + double ids0 = ids; + + // flip ids if we swapped source and drain above + if (source == 2 && pnp == 1 || source == 1 && pnp == -1) + ids = -ids; + + if (finished) + return; + + double rs = -pnp * ids0 + Gds * realvds + gm * realvgs; + sim.stampMatrix(nodes[drain], nodes[drain], Gds); + sim.stampMatrix(nodes[drain], nodes[source], -Gds - gm); + sim.stampMatrix(nodes[drain], nodes[gate], gm); + + sim.stampMatrix(nodes[source], nodes[drain], -Gds); + sim.stampMatrix(nodes[source], nodes[source], Gds + gm); + sim.stampMatrix(nodes[source], nodes[gate], -gm); + + sim.stampRightSide(nodes[drain], rs); + sim.stampRightSide(nodes[source], -rs); + } + + void getFetInfo(String arr[], String n) { + arr[0] = Locale.LS(((pnp == -1) ? "p-" : "n-") + n); + arr[0] += " (Vt=" + getVoltageText(pnp * vt); + arr[0] += ", \u03b2=" + beta + ")"; + arr[1] = ((pnp == 1) ? "Ids = " : "Isd = ") + getCurrentText(ids); + arr[2] = "Vgs = " + getVoltageText(volts[0] - volts[pnp == -1 ? 2 : 1]); + arr[3] = ((pnp == 1) ? "Vds = " : "Vsd = ") + getVoltageText(volts[2] - volts[1]); + arr[4] = Locale.LS((mode == 0) ? "off" : (mode == 1) ? "linear" : "saturation"); + arr[5] = "gm = " + getUnitText(gm, "A/V"); + arr[6] = "P = " + getUnitText(getPower(), "W"); + if (showBulk()) + arr[7] = "Ib = " + getUnitText(bodyTerminal == 1 ? -diodeCurrent1 + : bodyTerminal == 2 ? diodeCurrent2 : -pnp * (diodeCurrent1 + diodeCurrent2), "A"); + } + + void getInfo(String arr[]) { + getFetInfo(arr, "MOSFET"); + } + + @Override + String getScopeText(int v) { + return Locale.LS(((pnp == -1) ? "p-" : "n-") + "MOSFET"); + } + + boolean canViewInScope() { + return true; + } + + double getVoltageDiff() { + return volts[2] - volts[1]; + } + + boolean getConnection(int n1, int n2) { + return !(n1 == 0 || n2 == 0); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Threshold Voltage", pnp * vt, .01, 5); + if (n == 1) + return new EditInfo(EditInfo.makeLink("mosfet-beta.html", "Beta"), beta, .01, 5); + if (n == 2) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Show Bulk", showBulk()); + return ei; } - - double lastv0; - - // this is called in doStep to stamp the matrix, and also called in stepFinished() to calculate the current - void calculate(boolean finished) { - double vs[]; - if (finished) - vs = volts; - else { - // limit voltage changes to .5V - vs = new double[3]; - vs[0] = volts[0]; - vs[1] = volts[1]; - vs[2] = volts[2]; - if (vs[1] > lastv1 + .5) - vs[1] = lastv1 + .5; - if (vs[1] < lastv1 - .5) - vs[1] = lastv1 - .5; - if (vs[2] > lastv2 + .5) - vs[2] = lastv2 + .5; - if (vs[2] < lastv2 - .5) - vs[2] = lastv2 - .5; - } - - int source = 1; - int drain = 2; - - // if source voltage > drain (for NPN), swap source and drain - // (opposite for PNP) - if (pnp*vs[1] > pnp*vs[2]) { - source = 2; - drain = 1; - } - int gate = 0; - double vgs = vs[gate ]-vs[source]; - double vds = vs[drain]-vs[source]; - if (!finished && (nonConvergence(lastv1, vs[1]) || nonConvergence(lastv2, vs[2]) || nonConvergence(lastv0, vs[0]))) - sim.converged = false; - lastv0 = vs[0]; - lastv1 = vs[1]; - lastv2 = vs[2]; - double realvgs = vgs; - double realvds = vds; - vgs *= pnp; - vds *= pnp; - ids = 0; - gm = 0; - double Gds = 0; - if (vgs < vt) { - // should be all zero, but that causes a singular matrix, - // so instead we treat it as a large resistor - Gds = 1e-8; - ids = vds*Gds; - mode = 0; - } else if (vds < vgs-vt) { - // linear - ids = beta*((vgs-vt)*vds - vds*vds*.5); - gm = beta*vds; - Gds = beta*(vgs-vds-vt); - mode = 1; - } else { - // saturation; Gds = 0 - gm = beta*(vgs-vt); - // use very small Gds to avoid nonconvergence - Gds = 1e-8; - ids = .5*beta*(vgs-vt)*(vgs-vt) + (vds-(vgs-vt))*Gds; - mode = 2; - } - - if (doBodyDiode()) { - diodeB1.doStep(pnp*(volts[bodyTerminal]-volts[1])); - diodeCurrent1 = diodeB1.calculateCurrent(pnp*(volts[bodyTerminal]-volts[1]))*pnp; - diodeB2.doStep(pnp*(volts[bodyTerminal]-volts[2])); - diodeCurrent2 = diodeB2.calculateCurrent(pnp*(volts[bodyTerminal]-volts[2]))*pnp; - } else - diodeCurrent1 = diodeCurrent2 = 0; - - double ids0 = ids; - - // flip ids if we swapped source and drain above - if (source == 2 && pnp == 1 || - source == 1 && pnp == -1) - ids = -ids; - - if (finished) - return; - - double rs = -pnp*ids0 + Gds*realvds + gm*realvgs; - sim.stampMatrix(nodes[drain], nodes[drain], Gds); - sim.stampMatrix(nodes[drain], nodes[source], -Gds-gm); - sim.stampMatrix(nodes[drain], nodes[gate], gm); - - sim.stampMatrix(nodes[source], nodes[drain], -Gds); - sim.stampMatrix(nodes[source], nodes[source], Gds+gm); - sim.stampMatrix(nodes[source], nodes[gate], -gm); - - sim.stampRightSide(nodes[drain], rs); - sim.stampRightSide(nodes[source], -rs); + if (n == 3) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Swap D/S", (flags & FLAG_FLIP) != 0); + return ei; } - - void getFetInfo(String arr[], String n) { - arr[0] = Locale.LS(((pnp == -1) ? "p-" : "n-") + n); - arr[0] += " (Vt=" + getVoltageText(pnp*vt); - arr[0] += ", \u03b2=" + beta + ")"; - arr[1] = ((pnp == 1) ? "Ids = " : "Isd = ") + getCurrentText(ids); - arr[2] = "Vgs = " + getVoltageText(volts[0]-volts[pnp == -1 ? 2 : 1]); - arr[3] = ((pnp == 1) ? "Vds = " : "Vsd = ") + getVoltageText(volts[2]-volts[1]); - arr[4] = Locale.LS((mode == 0) ? "off" : - (mode == 1) ? "linear" : "saturation"); - arr[5] = "gm = " + getUnitText(gm, "A/V"); - arr[6] = "P = " + getUnitText(getPower(), "W"); - if (showBulk()) - arr[7] = "Ib = " + getUnitText(bodyTerminal == 1 ? -diodeCurrent1 : bodyTerminal == 2 ? diodeCurrent2 : -pnp*(diodeCurrent1+diodeCurrent2), "A"); + if (n == 4 && !showBulk()) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Digital Symbol", drawDigital()); + return ei; } - void getInfo(String arr[]) { - getFetInfo(arr, "MOSFET"); + if (n == 4 && showBulk()) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Simulate Body Diode", (flags & FLAG_BODY_DIODE) != 0); + return ei; } - @Override String getScopeText(int v) { - return Locale.LS(((pnp == -1) ? "p-" : "n-") + "MOSFET"); + if (n == 5 && doBodyDiode()) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Body Terminal", (flags & FLAG_BODY_TERMINAL) != 0); + return ei; } - boolean canViewInScope() { return true; } - double getVoltageDiff() { return volts[2] - volts[1]; } - boolean getConnection(int n1, int n2) { - return !(n1 == 0 || n2 == 0); + + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + vt = pnp * ei.value; + if (n == 1 && ei.value > 0) + beta = lastBeta = ei.value; + if (n == 2) { + globalFlags = (!ei.checkbox.getState()) ? (globalFlags | FLAG_HIDE_BULK) + : (globalFlags & ~(FLAG_HIDE_BULK | FLAG_DIGITAL)); + // setPoints(); + ei.newDialog = true; + } + if (n == 3) { + flags = (ei.checkbox.getState()) ? (flags | FLAG_FLIP) : (flags & ~FLAG_FLIP); + // setPoints(); } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Threshold Voltage", pnp*vt, .01, 5); - if (n == 1) - return new EditInfo(EditInfo.makeLink("mosfet-beta.html", "Beta"), beta, .01, 5); - if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Show Bulk", showBulk()); - return ei; - } - if (n == 3) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Swap D/S", (flags & FLAG_FLIP) != 0); - return ei; - } - if (n == 4 && !showBulk()) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Digital Symbol", drawDigital()); - return ei; - } - if (n == 4 && showBulk()) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Simulate Body Diode", (flags & FLAG_BODY_DIODE) != 0); - return ei; - } - if (n == 5 && doBodyDiode()) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Body Terminal", (flags & FLAG_BODY_TERMINAL) != 0); - return ei; - } - - return null; + if (n == 4 && !showBulk()) { + globalFlags = (ei.checkbox.getState()) ? (globalFlags | FLAG_DIGITAL) : (globalFlags & ~FLAG_DIGITAL); + // setPoints(); } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - vt = pnp*ei.value; - if (n == 1 && ei.value > 0) - beta = lastBeta = ei.value; - if (n == 2) { - globalFlags = (!ei.checkbox.getState()) ? (globalFlags|FLAG_HIDE_BULK) : - (globalFlags & ~(FLAG_HIDE_BULK|FLAG_DIGITAL)); -// setPoints(); - ei.newDialog = true; - } - if (n == 3) { - flags = (ei.checkbox.getState()) ? (flags | FLAG_FLIP) : - (flags & ~FLAG_FLIP); -// setPoints(); - } - if (n == 4 && !showBulk()) { - globalFlags = (ei.checkbox.getState()) ? (globalFlags|FLAG_DIGITAL) : - (globalFlags & ~FLAG_DIGITAL); -// setPoints(); - } - if (n == 4 && showBulk()) { - flags = ei.changeFlag(flags, FLAG_BODY_DIODE); - ei.newDialog = true; - } - if (n == 5) { - flags = ei.changeFlag(flags, FLAG_BODY_TERMINAL); - } - - // lots of different cases where the body terminal might have gotten removed/added so just do this all the time - allocNodes(); - setPoints(); + if (n == 4 && showBulk()) { + flags = ei.changeFlag(flags, FLAG_BODY_DIODE); + ei.newDialog = true; } - double getCurrentIntoNode(int n) { - if (n == 0) - return 0; - if (n == 3) - return -diodeCurrent1 - diodeCurrent2; - if (n == 1) - return ids + diodeCurrent1; - return -ids + diodeCurrent2; + if (n == 5) { + flags = ei.changeFlag(flags, FLAG_BODY_TERMINAL); } + + // lots of different cases where the body terminal might have gotten + // removed/added so just do this all the time + allocNodes(); + setPoints(); + } + + double getCurrentIntoNode(int n) { + if (n == 0) + return 0; + if (n == 3) + return -diodeCurrent1 - diodeCurrent2; + if (n == 1) + return ids + diodeCurrent1; + return -ids + diodeCurrent2; } +} diff --git a/src/com/lushprojects/circuitjs1/client/MultiplexerElm.java b/src/com/lushprojects/circuitjs1/client/MultiplexerElm.java index 31bfa759..ca1401e4 100644 --- a/src/com/lushprojects/circuitjs1/client/MultiplexerElm.java +++ b/src/com/lushprojects/circuitjs1/client/MultiplexerElm.java @@ -21,121 +21,138 @@ // contributed by Edward Calver - class MultiplexerElm extends ChipElm { - final int FLAG_INVERTED_OUTPUT = 1<<1; - final int FLAG_STROBE = 1<<2; - int selectBitCount; - int outputCount; - int strobe; - int outputPin; - - boolean hasReset() {return false;} - public MultiplexerElm(int xx, int yy) { - super(xx, yy); - selectBitCount = 2; - setupPins(); +class MultiplexerElm extends ChipElm { + final int FLAG_INVERTED_OUTPUT = 1 << 1; + final int FLAG_STROBE = 1 << 2; + int selectBitCount; + int outputCount; + int strobe; + int outputPin; + + boolean hasReset() { + return false; + } + + public MultiplexerElm(int xx, int yy) { + super(xx, yy); + selectBitCount = 2; + setupPins(); + } + + public MultiplexerElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + selectBitCount = 2; + try { + selectBitCount = Integer.parseInt(st.nextToken()); + } catch (Exception e) { } - public MultiplexerElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - selectBitCount = 2; - try { - selectBitCount = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} - setupPins(); + setupPins(); + } + + String getChipName() { + return "Multiplexer"; + } + + String dump() { + return super.dump() + " " + selectBitCount; + } + + void setupPins() { + sizeX = selectBitCount + 1; + outputCount = 1; + int i; + for (i = 0; i != selectBitCount; i++) + outputCount <<= 1; + sizeY = outputCount + 1; + + pins = new Pin[getPostCount()]; + + for (i = 0; i != outputCount; i++) + pins[i] = new Pin(i, SIDE_W, "I" + i); + + int n = outputCount; + for (i = 0; i != selectBitCount; i++, n++) + pins[n] = new Pin(i + 1, SIDE_S, "S" + i); + + pins[n] = new Pin(0, SIDE_E, "Q"); + pins[n].output = true; + outputPin = n; + if (hasFlag(FLAG_INVERTED_OUTPUT)) { + n++; + pins[n] = new Pin(1, SIDE_E, "Q"); + pins[n].lineOver = true; + pins[n].output = true; + pins[n].bubble = true; } - String getChipName() { return "Multiplexer"; } - String dump() { return super.dump() + " " + selectBitCount; } - void setupPins() { - sizeX = selectBitCount+1; - outputCount = 1; - int i; - for (i = 0; i != selectBitCount; i++) - outputCount <<= 1; - sizeY = outputCount+1; - - pins = new Pin[getPostCount()]; - - for (i = 0; i != outputCount; i++) - pins[i] = new Pin(i, SIDE_W, "I" + i); - - int n = outputCount; - for (i = 0; i != selectBitCount; i++, n++) - pins[n] = new Pin(i+1, SIDE_S, "S" + i); - - pins[n] = new Pin(0, SIDE_E, "Q"); - pins[n].output=true; - outputPin = n; - if (hasFlag(FLAG_INVERTED_OUTPUT)) { - n++; - pins[n] = new Pin(1, SIDE_E, "Q"); - pins[n].lineOver = true; - pins[n].output=true; - pins[n].bubble = true; - } - if (hasFlag(FLAG_STROBE)) { - n++; - pins[n] = new Pin(0, SIDE_S, "STR"); - strobe = n; - } else - strobe = -1; - - allocNodes(); + if (hasFlag(FLAG_STROBE)) { + n++; + pins[n] = new Pin(0, SIDE_S, "STR"); + strobe = n; + } else + strobe = -1; + + allocNodes(); + } + + int getPostCount() { + return outputCount + selectBitCount + 1 + (hasFlag(FLAG_INVERTED_OUTPUT) ? 1 : 0) + + (hasFlag(FLAG_STROBE) ? 1 : 0); + } + + int getVoltageSourceCount() { + return hasFlag(FLAG_INVERTED_OUTPUT) ? 2 : 1; + } + + void execute() { + int selectedValue = 0; + int i; + for (i = 0; i != selectBitCount; i++) + if (pins[outputCount + i].value) + selectedValue |= 1 << i; + boolean val = pins[selectedValue].value; + if (strobe != -1 && pins[strobe].value) + val = false; + pins[outputPin].value = val; + if (hasFlag(FLAG_INVERTED_OUTPUT)) + pins[outputPin + 1].value = !val; + } + + int getDumpType() { + return 184; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) + return new EditInfo("# of Select Bits", selectBitCount, 1, 8).setDimensionless(); + if (n == 1) + return EditInfo.createCheckbox("Inverted Output", hasFlag(FLAG_INVERTED_OUTPUT)); + if (n == 2) + return EditInfo.createCheckbox("Strobe Pin", hasFlag(FLAG_STROBE)); + + return super.getChipEditInfo(n); + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value >= 1 && ei.value <= 6) { + selectBitCount = (int) ei.value; + setupPins(); + setPoints(); + return; } - int getPostCount() { - return outputCount + selectBitCount + 1 + (hasFlag(FLAG_INVERTED_OUTPUT) ? 1 : 0) + (hasFlag(FLAG_STROBE) ? 1 : 0); + if (n == 1) { + flags = ei.changeFlag(flags, FLAG_INVERTED_OUTPUT); + setupPins(); + setPoints(); + return; } - int getVoltageSourceCount() {return hasFlag(FLAG_INVERTED_OUTPUT) ? 2 : 1;} - - void execute() { - int selectedValue=0; - int i; - for (i = 0; i != selectBitCount; i++) - if (pins[outputCount+i].value) - selectedValue |= 1<= 1 && ei.value <= 6) { - selectBitCount = (int) ei.value; - setupPins(); - setPoints(); - return; - } - if (n == 1) { - flags = ei.changeFlag(flags, FLAG_INVERTED_OUTPUT); - setupPins(); - setPoints(); - return; - } - if (n == 2) { - flags = ei.changeFlag(flags, FLAG_STROBE); - setupPins(); - setPoints(); - return; - } - super.setChipEditValue(n, ei); - } - + super.setChipEditValue(n, ei); } + +} diff --git a/src/com/lushprojects/circuitjs1/client/MyCommand.java b/src/com/lushprojects/circuitjs1/client/MyCommand.java index b286536d..2ff3374d 100644 --- a/src/com/lushprojects/circuitjs1/client/MyCommand.java +++ b/src/com/lushprojects/circuitjs1/client/MyCommand.java @@ -22,16 +22,16 @@ import com.google.gwt.user.client.Command; public class MyCommand implements Command { - private final String menuName; - private final String itemName; - - public MyCommand(String name, String item){ - menuName=name; - itemName=item; - } - - public void execute() { - circuitjs1.mysim.menuPerformed(menuName, itemName); - } + private final String menuName; + private final String itemName; + + public MyCommand(String name, String item) { + menuName = name; + itemName = item; + } + + public void execute() { + circuitjs1.mysim.menuPerformed(menuName, itemName); + } } diff --git a/src/com/lushprojects/circuitjs1/client/NDarlingtonElm.java b/src/com/lushprojects/circuitjs1/client/NDarlingtonElm.java index 5c807585..0559faf2 100644 --- a/src/com/lushprojects/circuitjs1/client/NDarlingtonElm.java +++ b/src/com/lushprojects/circuitjs1/client/NDarlingtonElm.java @@ -2,14 +2,11 @@ public class NDarlingtonElm extends DarlingtonElm { - - public NDarlingtonElm(int xx, int yy) { super(xx, yy, false); } - - Class getDumpClass() { + Class getDumpClass() { return DarlingtonElm.class; } } diff --git a/src/com/lushprojects/circuitjs1/client/NJfetElm.java b/src/com/lushprojects/circuitjs1/client/NJfetElm.java index 3109f498..c1277f78 100644 --- a/src/com/lushprojects/circuitjs1/client/NJfetElm.java +++ b/src/com/lushprojects/circuitjs1/client/NJfetElm.java @@ -20,12 +20,21 @@ package com.lushprojects.circuitjs1.client; class NJfetElm extends JfetElm { - public NJfetElm(int xx, int yy) { super(xx, yy, false); } - Class getDumpClass() { return JfetElm.class; } + public NJfetElm(int xx, int yy) { + super(xx, yy, false); } - class PJfetElm extends JfetElm { - public PJfetElm(int xx, int yy) { super(xx, yy, true); } - Class getDumpClass() { return JfetElm.class; } + Class getDumpClass() { + return JfetElm.class; } +} +class PJfetElm extends JfetElm { + public PJfetElm(int xx, int yy) { + super(xx, yy, true); + } + + Class getDumpClass() { + return JfetElm.class; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/NMosfetElm.java b/src/com/lushprojects/circuitjs1/client/NMosfetElm.java index 22acfc93..a89afe6d 100644 --- a/src/com/lushprojects/circuitjs1/client/NMosfetElm.java +++ b/src/com/lushprojects/circuitjs1/client/NMosfetElm.java @@ -20,7 +20,15 @@ package com.lushprojects.circuitjs1.client; class NMosfetElm extends MosfetElm { - public NMosfetElm(int xx, int yy) { super(xx, yy, false); } - Class getDumpClass() { return MosfetElm.class; } - int getShortcut() { return 'N'; } + public NMosfetElm(int xx, int yy) { + super(xx, yy, false); } + + Class getDumpClass() { + return MosfetElm.class; + } + + int getShortcut() { + return 'N'; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/NTransistorElm.java b/src/com/lushprojects/circuitjs1/client/NTransistorElm.java index 099a83f1..6f17418c 100644 --- a/src/com/lushprojects/circuitjs1/client/NTransistorElm.java +++ b/src/com/lushprojects/circuitjs1/client/NTransistorElm.java @@ -20,9 +20,16 @@ package com.lushprojects.circuitjs1.client; class NTransistorElm extends TransistorElm { - public NTransistorElm(int xx, int yy) { super(xx, yy, false); } - Class getDumpClass() { return TransistorElm.class; } - - int getShortcut() { return 'n'; } - + public NTransistorElm(int xx, int yy) { + super(xx, yy, false); } + + Class getDumpClass() { + return TransistorElm.class; + } + + int getShortcut() { + return 'n'; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/NandGateElm.java b/src/com/lushprojects/circuitjs1/client/NandGateElm.java index aeb2f89b..af03922e 100644 --- a/src/com/lushprojects/circuitjs1/client/NandGateElm.java +++ b/src/com/lushprojects/circuitjs1/client/NandGateElm.java @@ -19,14 +19,28 @@ package com.lushprojects.circuitjs1.client; - class NandGateElm extends AndGateElm { - public NandGateElm(int xx, int yy) { super(xx, yy); } - public NandGateElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - } - boolean isInverting() { return true; } - String getGateName() { return "NAND gate"; } - int getDumpType() { return 151; } - int getShortcut() { return '@'; } +class NandGateElm extends AndGateElm { + public NandGateElm(int xx, int yy) { + super(xx, yy); } + + public NandGateElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + } + + boolean isInverting() { + return true; + } + + String getGateName() { + return "NAND gate"; + } + + int getDumpType() { + return 151; + } + + int getShortcut() { + return '@'; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/NoiseElm.java b/src/com/lushprojects/circuitjs1/client/NoiseElm.java index 0d0afafc..76539c77 100644 --- a/src/com/lushprojects/circuitjs1/client/NoiseElm.java +++ b/src/com/lushprojects/circuitjs1/client/NoiseElm.java @@ -19,15 +19,20 @@ package com.lushprojects.circuitjs1.client; - class NoiseElm extends RailElm { - public NoiseElm(int xx, int yy) { super(xx, yy, WF_NOISE); } - public NoiseElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - waveform = WF_NOISE; - } - - // dump this class as a RailElm. The 'n' dump type is still used in CirSim.createCe to read old files -// int getDumpType() { return 'n'; } - int getShortcut() { return 0; } +class NoiseElm extends RailElm { + public NoiseElm(int xx, int yy) { + super(xx, yy, WF_NOISE); } + + public NoiseElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + waveform = WF_NOISE; + } + + // dump this class as a RailElm. The 'n' dump type is still used in + // CirSim.createCe to read old files + // int getDumpType() { return 'n'; } + int getShortcut() { + return 0; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/NorGateElm.java b/src/com/lushprojects/circuitjs1/client/NorGateElm.java index 7bd9b86f..19ec173f 100644 --- a/src/com/lushprojects/circuitjs1/client/NorGateElm.java +++ b/src/com/lushprojects/circuitjs1/client/NorGateElm.java @@ -19,14 +19,28 @@ package com.lushprojects.circuitjs1.client; - class NorGateElm extends OrGateElm { - public NorGateElm(int xx, int yy) { super(xx, yy); } - public NorGateElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - } - String getGateName() { return "NOR gate"; } - boolean isInverting() { return true; } - int getDumpType() { return 153; } - int getShortcut() { return '#'; } +class NorGateElm extends OrGateElm { + public NorGateElm(int xx, int yy) { + super(xx, yy); } + + public NorGateElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + } + + String getGateName() { + return "NOR gate"; + } + + boolean isInverting() { + return true; + } + + int getDumpType() { + return 153; + } + + int getShortcut() { + return '#'; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/OhmMeterElm.java b/src/com/lushprojects/circuitjs1/client/OhmMeterElm.java index acd3f1d5..e97e3fe5 100644 --- a/src/com/lushprojects/circuitjs1/client/OhmMeterElm.java +++ b/src/com/lushprojects/circuitjs1/client/OhmMeterElm.java @@ -3,62 +3,64 @@ import com.lushprojects.circuitjs1.client.util.Locale; public class OhmMeterElm extends CurrentElm { - public OhmMeterElm(int xx, int yy) { - super(xx, yy); - } - public OhmMeterElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - } - int getDumpType() { return 216; } + public OhmMeterElm(int xx, int yy) { + super(xx, yy); + } - void setPoints() { - super.setPoints(); - calcLeads(26); - } - void draw(Graphics g) { - int cr = 12; - draw2Leads(g); - setVoltageColor(g, (volts[0]+volts[1])/2); - setPowerColor(g, false); - - drawThickCircle(g, center.x, center.y, cr); - drawCenteredText(g, Locale.ohmString, center.x, center.y, true); + public OhmMeterElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + } - setBbox(point1, point2, cr); - doDots(g); - if (sim.showValuesCheckItem.getState() && current != 0) { - String s = getShortUnitText(getVoltageDiff()/current, Locale.ohmString); - if (dx == 0 || dy == 0) - drawValues(g, s, cr); - } - drawPosts(g); - } - double getScopeValue(int x) { - return (x == Scope.VAL_R) ? getVoltageDiff()/current : super.getScopeValue(x); - } - int getScopeUnits(int x) { - return (x == Scope.VAL_R) ? Scope.UNITS_OHMS : super.getScopeUnits(x); - } - boolean canShowValueInScope(int x) { - return x == Scope.VAL_R; - } + int getDumpType() { + return 216; + } - /* - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Current (A)", currentValue, 0, .1); - return null; - } - public void setEditValue(int n, EditInfo ei) { - currentValue = ei.value; - } - */ - void getInfo(String arr[]) { - arr[0] = "ohmmeter"; - if (current == 0) - arr[1] = "R = \u221e"; - else - arr[1] = "R = " + getUnitText(getVoltageDiff()/current, Locale.ohmString); + void setPoints() { + super.setPoints(); + calcLeads(26); + } + + void draw(Graphics g) { + int cr = 12; + draw2Leads(g); + setVoltageColor(g, (volts[0] + volts[1]) / 2); + setPowerColor(g, false); + + drawThickCircle(g, center.x, center.y, cr); + drawCenteredText(g, Locale.ohmString, center.x, center.y, true); + + setBbox(point1, point2, cr); + doDots(g); + if (sim.showValuesCheckItem.getState() && current != 0) { + String s = getShortUnitText(getVoltageDiff() / current, Locale.ohmString); + if (dx == 0 || dy == 0) + drawValues(g, s, cr); } + drawPosts(g); + } + + double getScopeValue(int x) { + return (x == Scope.VAL_R) ? getVoltageDiff() / current : super.getScopeValue(x); + } + + int getScopeUnits(int x) { + return (x == Scope.VAL_R) ? Scope.UNITS_OHMS : super.getScopeUnits(x); + } + + boolean canShowValueInScope(int x) { + return x == Scope.VAL_R; + } + + /* + * public EditInfo getEditInfo(int n) { if (n == 0) return new + * EditInfo("Current (A)", currentValue, 0, .1); return null; } public void + * setEditValue(int n, EditInfo ei) { currentValue = ei.value; } + */ + void getInfo(String arr[]) { + arr[0] = "ohmmeter"; + if (current == 0) + arr[1] = "R = \u221e"; + else + arr[1] = "R = " + getUnitText(getVoltageDiff() / current, Locale.ohmString); + } } diff --git a/src/com/lushprojects/circuitjs1/client/OpAmpElm.java b/src/com/lushprojects/circuitjs1/client/OpAmpElm.java index 904e00bc..182bc5e7 100644 --- a/src/com/lushprojects/circuitjs1/client/OpAmpElm.java +++ b/src/com/lushprojects/circuitjs1/client/OpAmpElm.java @@ -19,197 +19,237 @@ package com.lushprojects.circuitjs1.client; - class OpAmpElm extends CircuitElm { - int opsize, opheight, opwidth, opaddtext; - double maxOut, minOut, gain, gbw; - boolean reset; - final int FLAG_SWAP = 1; - final int FLAG_SMALL = 2; - final int FLAG_LOWGAIN = 4; - final int FLAG_GAIN = 8; - public OpAmpElm(int xx, int yy) { - super(xx, yy); - noDiagonal = true; - maxOut = 15; - minOut = -15; - gbw = 1e6; - flags = FLAG_GAIN; // need to do this before setSize() - gain = 100000; - setSize(sim.smallGridCheckItem.getState() ? 1 : 2); - } - public OpAmpElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - maxOut = 15; - minOut = -15; - // GBW has no effect in this version of the simulator, but we - // retain it to keep the file format the same - gbw = 1e6; - try { - maxOut = new Double(st.nextToken()).doubleValue(); - minOut = new Double(st.nextToken()).doubleValue(); - gbw = new Double(st.nextToken()).doubleValue(); - volts[0] = new Double(st.nextToken()).doubleValue(); - volts[1] = new Double(st.nextToken()).doubleValue(); - gain = new Double(st.nextToken()).doubleValue(); - } catch (Exception e) { - } - noDiagonal = true; - setSize((f & FLAG_SMALL) != 0 ? 1 : 2); - setGain(); - } - void setGain() { - if ((flags & FLAG_GAIN) != 0) - return; - - // gain of 100000 breaks e-amp-dfdx.txt - // gain was 1000, but it broke amp-schmitt.txt - gain = ((flags & FLAG_LOWGAIN) != 0) ? 1000 : 100000; - } - String dump() { - flags |= FLAG_GAIN; - return super.dump() + " " + maxOut + " " + minOut + " " + gbw + " " + volts[0] + " " + volts[1] + " " + gain; - } - boolean nonLinear() { return true; } - void draw(Graphics g) { - setBbox(point1, point2, opheight*2); - setVoltageColor(g, volts[0]); - drawThickLine(g, in1p[0], in1p[1]); - setVoltageColor(g, volts[1]); - drawThickLine(g, in2p[0], in2p[1]); - setVoltageColor(g, volts[2]); - drawThickLine(g, lead2, point2); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - setPowerColor(g, true); - drawThickPolygon(g, triangle); - g.setFont(plusFont); - drawCenteredText(g, "-", textp[0].x, textp[0].y-2, true); - drawCenteredText(g, "+", textp[1].x, textp[1].y , true); - curcount = updateDotCount(current, curcount); - drawDots(g, point2, lead2, curcount); - drawPosts(g); - } - double getPower() { return volts[2]*current; } - Point in1p[], in2p[], textp[]; - Polygon triangle; - Font plusFont; - void setSize(int s) { - opsize = s; - opheight = 8*s; - opwidth = 13*s; - flags = (flags & ~FLAG_SMALL) | ((s == 1) ? FLAG_SMALL : 0); - } - void setPoints() { - super.setPoints(); - if (dn > 150 && this == sim.dragElm) - setSize(2); - int ww = opwidth; - if (ww > dn/2) - ww = (int) (dn/2); - calcLeads(ww*2); - int hs = opheight*dsign; - if ((flags & FLAG_SWAP) != 0) - hs = -hs; - in1p = newPointArray(2); - in2p = newPointArray(2); - textp = newPointArray(2); - interpPoint2(point1, point2, in1p[0], in2p[0], 0, hs); - interpPoint2(lead1 , lead2, in1p[1], in2p[1], 0, hs); - interpPoint2(lead1 , lead2, textp[0], textp[1], .2, hs); - Point tris[] = newPointArray(2); - interpPoint2(lead1, lead2, tris[0], tris[1], 0, hs*2); - triangle = createPolygon(tris[0], tris[1], lead2); - plusFont = new Font("SansSerif", 0, opsize == 2 ? 14 : 10); - } - int getPostCount() { return 3; } - Point getPost(int n) { - return (n == 0) ? in1p[0] : (n == 1) ? in2p[0] : point2; - } - int getVoltageSourceCount() { return 1; } - void getInfo(String arr[]) { - arr[0] = "op-amp"; - arr[1] = "V+ = " + getVoltageText(volts[1]); - arr[2] = "V- = " + getVoltageText(volts[0]); - // sometimes the voltage goes slightly outside range, to make - // convergence easier. so we hide that here. - double vo = Math.max(Math.min(volts[2], maxOut), minOut); - arr[3] = "Vout = " + getVoltageText(vo); - arr[4] = "Iout = " + getCurrentText(-current); - arr[5] = "range = " + getVoltageText(minOut) + " to " + - getVoltageText(maxOut); - } +class OpAmpElm extends CircuitElm { + int opsize, opheight, opwidth, opaddtext; + double maxOut, minOut, gain, gbw; + boolean reset; + final int FLAG_SWAP = 1; + final int FLAG_SMALL = 2; + final int FLAG_LOWGAIN = 4; + final int FLAG_GAIN = 8; - double lastvd; + public OpAmpElm(int xx, int yy) { + super(xx, yy); + noDiagonal = true; + maxOut = 15; + minOut = -15; + gbw = 1e6; + flags = FLAG_GAIN; // need to do this before setSize() + gain = 100000; + setSize(sim.smallGridCheckItem.getState() ? 1 : 2); + } - void stamp() { - int vn = sim.nodeList.size()+voltSource; - sim.stampNonLinear(vn); - sim.stampMatrix(nodes[2], vn, 1); - } - void doStep() { - double vd = volts[1] - volts[0]; - double midpoint = (maxOut+minOut)*.5; - if (Math.abs(lastvd-vd) > .1) - sim.converged = false; - else if (volts[2] > maxOut+.1 || volts[2] < minOut-.1) - sim.converged = false; - double x = 0; - int vn = sim.nodeList.size()+voltSource; - double dx = 0; - double maxAdj = maxOut-midpoint; - double minAdj = minOut-midpoint; - if (vd >= maxAdj/gain && (lastvd >= 0 || sim.getrand(4) == 1)) { - dx = 1e-4; - x = maxOut - dx*maxAdj/gain; - } else if (vd <= minAdj/gain && (lastvd <= 0 || sim.getrand(4) == 1)) { - dx = 1e-4; - x = minOut - dx*minAdj/gain; - } else { - dx = gain; - x = midpoint; - } - //System.out.println("opamp " + vd + " " + volts[2] + " " + dx + " " + x + " " + lastvd + " " + sim.converged); - - // newton-raphson - sim.stampMatrix(vn, nodes[0], dx); - sim.stampMatrix(vn, nodes[1], -dx); - sim.stampMatrix(vn, nodes[2], 1); - sim.stampRightSide(vn, x); - - lastvd = vd; - /*if (sim.converged) - System.out.println((volts[1]-volts[0]) + " " + volts[2] + " " + initvd);*/ - } - // there is no current path through the op-amp inputs, but there - // is an indirect path through the output to ground. - boolean getConnection(int n1, int n2) { return false; } - boolean hasGroundConnection(int n1) { - return (n1 == 2); + public OpAmpElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + maxOut = 15; + minOut = -15; + // GBW has no effect in this version of the simulator, but we + // retain it to keep the file format the same + gbw = 1e6; + try { + maxOut = Double.valueOf(st.nextToken()).doubleValue(); + minOut = Double.valueOf(st.nextToken()).doubleValue(); + gbw = Double.valueOf(st.nextToken()).doubleValue(); + volts[0] = Double.valueOf(st.nextToken()).doubleValue(); + volts[1] = Double.valueOf(st.nextToken()).doubleValue(); + gain = Double.valueOf(st.nextToken()).doubleValue(); + } catch (Exception e) { } - double getVoltageDiff() { return volts[2] - volts[1]; } - int getDumpType() { return 'a'; } - public EditInfo getEditInfo(int n) { - if (n == 0) - return new EditInfo("Max Output (V)", maxOut, 1, 20); - if (n == 1) - return new EditInfo("Min Output (V)", minOut, -20, 0); - if (n == 2) - return new EditInfo("Gain", gain, 10, 1000000); - return null; - } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) - maxOut = ei.value; - if (n == 1) - minOut = ei.value; - if (n == 2 && ei.value > 0) - gain = ei.value; - } - int getShortcut() { return 'a'; } - - @Override double getCurrentIntoNode(int n) { - if (n==2) - return -current; - return 0; + noDiagonal = true; + setSize((f & FLAG_SMALL) != 0 ? 1 : 2); + setGain(); + } + + void setGain() { + if ((flags & FLAG_GAIN) != 0) + return; + + // gain of 100000 breaks e-amp-dfdx.txt + // gain was 1000, but it broke amp-schmitt.txt + gain = ((flags & FLAG_LOWGAIN) != 0) ? 1000 : 100000; + } + + String dump() { + flags |= FLAG_GAIN; + return super.dump() + " " + maxOut + " " + minOut + " " + gbw + " " + volts[0] + " " + volts[1] + " " + gain; + } + + boolean nonLinear() { + return true; + } + + void draw(Graphics g) { + setBbox(point1, point2, opheight * 2); + setVoltageColor(g, volts[0]); + drawThickLine(g, in1p[0], in1p[1]); + setVoltageColor(g, volts[1]); + drawThickLine(g, in2p[0], in2p[1]); + setVoltageColor(g, volts[2]); + drawThickLine(g, lead2, point2); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + setPowerColor(g, true); + drawThickPolygon(g, triangle); + g.setFont(plusFont); + drawCenteredText(g, "-", textp[0].x, textp[0].y - 2, true); + drawCenteredText(g, "+", textp[1].x, textp[1].y, true); + curcount = updateDotCount(current, curcount); + drawDots(g, point2, lead2, curcount); + drawPosts(g); + } + + double getPower() { + return volts[2] * current; + } + + Point in1p[], in2p[], textp[]; + Polygon triangle; + Font plusFont; + + void setSize(int s) { + opsize = s; + opheight = 8 * s; + opwidth = 13 * s; + flags = (flags & ~FLAG_SMALL) | ((s == 1) ? FLAG_SMALL : 0); + } + + void setPoints() { + super.setPoints(); + if (dn > 150 && this == sim.dragElm) + setSize(2); + int ww = opwidth; + if (ww > dn / 2) + ww = (int) (dn / 2); + calcLeads(ww * 2); + int hs = opheight * dsign; + if ((flags & FLAG_SWAP) != 0) + hs = -hs; + in1p = newPointArray(2); + in2p = newPointArray(2); + textp = newPointArray(2); + interpPoint2(point1, point2, in1p[0], in2p[0], 0, hs); + interpPoint2(lead1, lead2, in1p[1], in2p[1], 0, hs); + interpPoint2(lead1, lead2, textp[0], textp[1], .2, hs); + Point tris[] = newPointArray(2); + interpPoint2(lead1, lead2, tris[0], tris[1], 0, hs * 2); + triangle = createPolygon(tris[0], tris[1], lead2); + plusFont = new Font("SansSerif", 0, opsize == 2 ? 14 : 10); + } + + int getPostCount() { + return 3; + } + + Point getPost(int n) { + return (n == 0) ? in1p[0] : (n == 1) ? in2p[0] : point2; + } + + int getVoltageSourceCount() { + return 1; + } + + void getInfo(String arr[]) { + arr[0] = "op-amp"; + arr[1] = "V+ = " + getVoltageText(volts[1]); + arr[2] = "V- = " + getVoltageText(volts[0]); + // sometimes the voltage goes slightly outside range, to make + // convergence easier. so we hide that here. + double vo = Math.max(Math.min(volts[2], maxOut), minOut); + arr[3] = "Vout = " + getVoltageText(vo); + arr[4] = "Iout = " + getCurrentText(-current); + arr[5] = "range = " + getVoltageText(minOut) + " to " + getVoltageText(maxOut); + } + + double lastvd; + + void stamp() { + int vn = sim.nodeList.size() + voltSource; + sim.stampNonLinear(vn); + sim.stampMatrix(nodes[2], vn, 1); + } + + void doStep() { + double vd = volts[1] - volts[0]; + double midpoint = (maxOut + minOut) * .5; + if (Math.abs(lastvd - vd) > .1) + sim.converged = false; + else if (volts[2] > maxOut + .1 || volts[2] < minOut - .1) + sim.converged = false; + double x = 0; + int vn = sim.nodeList.size() + voltSource; + double dx = 0; + double maxAdj = maxOut - midpoint; + double minAdj = minOut - midpoint; + if (vd >= maxAdj / gain && (lastvd >= 0 || sim.getrand(4) == 1)) { + dx = 1e-4; + x = maxOut - dx * maxAdj / gain; + } else if (vd <= minAdj / gain && (lastvd <= 0 || sim.getrand(4) == 1)) { + dx = 1e-4; + x = minOut - dx * minAdj / gain; + } else { + dx = gain; + x = midpoint; } + // System.out.println("opamp " + vd + " " + volts[2] + " " + dx + " " + x + " " + // + lastvd + " " + sim.converged); + + // newton-raphson + sim.stampMatrix(vn, nodes[0], dx); + sim.stampMatrix(vn, nodes[1], -dx); + sim.stampMatrix(vn, nodes[2], 1); + sim.stampRightSide(vn, x); + + lastvd = vd; + /* + * if (sim.converged) System.out.println((volts[1]-volts[0]) + " " + volts[2] + + * " " + initvd); + */ + } + + // there is no current path through the op-amp inputs, but there + // is an indirect path through the output to ground. + boolean getConnection(int n1, int n2) { + return false; + } + + boolean hasGroundConnection(int n1) { + return (n1 == 2); + } + + double getVoltageDiff() { + return volts[2] - volts[1]; + } + + int getDumpType() { + return 'a'; + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return new EditInfo("Max Output (V)", maxOut, 1, 20); + if (n == 1) + return new EditInfo("Min Output (V)", minOut, -20, 0); + if (n == 2) + return new EditInfo("Gain", gain, 10, 1000000); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) + maxOut = ei.value; + if (n == 1) + minOut = ei.value; + if (n == 2 && ei.value > 0) + gain = ei.value; + } + + int getShortcut() { + return 'a'; + } + + @Override + double getCurrentIntoNode(int n) { + if (n == 2) + return -current; + return 0; } +} diff --git a/src/com/lushprojects/circuitjs1/client/OpAmpRealElm.java b/src/com/lushprojects/circuitjs1/client/OpAmpRealElm.java index 7549e547..0e626a05 100644 --- a/src/com/lushprojects/circuitjs1/client/OpAmpRealElm.java +++ b/src/com/lushprojects/circuitjs1/client/OpAmpRealElm.java @@ -2,54 +2,53 @@ public class OpAmpRealElm extends CompositeElm { - // from https://commons.wikimedia.org/wiki/File:OpAmpTransistorLevel_Colored_Labeled.svg - private static String model741String = - "NTransistorElm 3 8 9\rNTransistorElm 2 8 10\rPTransistorElm 11 12 9\rPTransistorElm 11 13 10\rNTransistorElm 14 12 1\r" + // Q1-5 - "NTransistorElm 14 13 5\rNTransistorElm 12 7 14\rPTransistorElm 8 8 7\rPTransistorElm 8 11 7\rNTransistorElm 17 11 16\r" + // Q6-10 - "NTransistorElm 17 17 4\rPTransistorElm 18 18 7\rPTransistorElm 18 20 7\rNTransistorElm 20 7 25\rNTransistorElm 13 22 24\r" + // Q11-15 - "NTransistorElm 21 20 22\rNTransistorElm 25 20 6\rNTransistorElm 24 22 23\rPTransistorElm 22 4 15\rNTransistorElm 23 13 4\r" + // Q16-22 (no Q18, Q21) - "CapacitorElm 13 20\r" + - "ResistorElm 15 6\rResistorElm 6 25\r" + // output resistors - "ResistorElm 4 1\rResistorElm 4 14\rResistorElm 4 5\rResistorElm 4 16\rResistorElm 4 24\rResistorElm 4 23\rResistorElm 17 18\r" + - "ResistorElm 22 21\rResistorElm 21 20\r"; + // from + // https://commons.wikimedia.org/wiki/File:OpAmpTransistorLevel_Colored_Labeled.svg + private static String model741String = "NTransistorElm 3 8 9\rNTransistorElm 2 8 10\rPTransistorElm 11 12 9\rPTransistorElm 11 13 10\rNTransistorElm 14 12 1\r" + + // Q1-5 + "NTransistorElm 14 13 5\rNTransistorElm 12 7 14\rPTransistorElm 8 8 7\rPTransistorElm 8 11 7\rNTransistorElm 17 11 16\r" + + // Q6-10 + "NTransistorElm 17 17 4\rPTransistorElm 18 18 7\rPTransistorElm 18 20 7\rNTransistorElm 20 7 25\rNTransistorElm 13 22 24\r" + + // Q11-15 + "NTransistorElm 21 20 22\rNTransistorElm 25 20 6\rNTransistorElm 24 22 23\rPTransistorElm 22 4 15\rNTransistorElm 23 13 4\r" + + // Q16-22 (no Q18, Q21) + "CapacitorElm 13 20\r" + "ResistorElm 15 6\rResistorElm 6 25\r" + // output resistors + "ResistorElm 4 1\rResistorElm 4 14\rResistorElm 4 5\rResistorElm 4 16\rResistorElm 4 24\rResistorElm 4 23\rResistorElm 17 18\r" + + "ResistorElm 22 21\rResistorElm 21 20\r"; private static int[] model741ExternalNodes = { 2, 3, 6, 7, 4 }; // , 1, 5 }; // 0 = input -, 1 = input +, 2 = output, 3 = V+, 4 = V-, 5, 6 = offset null - - private static String lm324ModelString = - "TransistorElm 1 2 3\rCurrentElm 4 3\rTransistorElm 2 2 5\rTransistorElm 2 6 5\rCapacitorElm 6 7\rCurrentElm 4 8\rCurrentElm 4 7\rTransistorElm 8 4 9\r" + - "TransistorElm 7 4 10\rTransistorElm 10 4 11\rTransistorElm 11 7 12\rResistorElm 11 12\rTransistorElm 7 5 12\rCurrentElm 12 5\rTransistorElm 6 5 8\r" + - "ResistorElm 9 5\rTransistorElm 9 7 5\rTransistorElm 13 6 3"; + + private static String lm324ModelString = "TransistorElm 1 2 3\rCurrentElm 4 3\rTransistorElm 2 2 5\rTransistorElm 2 6 5\rCapacitorElm 6 7\rCurrentElm 4 8\rCurrentElm 4 7\rTransistorElm 8 4 9\r" + + "TransistorElm 7 4 10\rTransistorElm 10 4 11\rTransistorElm 11 7 12\rResistorElm 11 12\rTransistorElm 7 5 12\rCurrentElm 12 5\rTransistorElm 6 5 8\r" + + "ResistorElm 9 5\rTransistorElm 9 7 5\rTransistorElm 13 6 3"; private static int[] lm324ExternalNodes = { 1, 13, 12, 4, 5 }; - private static String lm324ModelDump = - "0 -1 -0 0 10000/0 0.000006/0 1 0 0 100/0 1 0 0 100/0 1e-11 0/0 0.000004/0 0.0001/0 1 0 0 100/0 1 0 0 100/0 1 0 0 100/0 1 0 0 100/0 25/0 -1 0 0 100/0 0.00005/" + - "0 -1 0 0 100/0 10000/0 1 0 0 100/0 -1 0 0 10000"; - + private static String lm324ModelDump = "0 -1 -0 0 10000/0 0.000006/0 1 0 0 100/0 1 0 0 100/0 1e-11 0/0 0.000004/0 0.0001/0 1 0 0 100/0 1 0 0 100/0 1 0 0 100/0 1 0 0 100/0 25/0 -1 0 0 100/0 0.00005/" + + "0 -1 0 0 100/0 10000/0 1 0 0 100/0 -1 0 0 10000"; + // from LM324 spice model, ON SEMICONDUCTOR NEXT GEN MODEL 9/27/2018 - private static String lm324v2ModelString = - "ResistorElm 4 6\rCurrentElm 4 7\rResistorElm 4 29\rResistorElm 8 30\rResistorElm 9 31\rTransistorElm 30 29 31 \rResistorElm 4 32\rResistorElm 2 33\rResistorElm 10 34\r" + - "TransistorElm 33 32 34 \rResistorElm 9 35\rResistorElm 9 36\rResistorElm 11 37\rTransistorElm 36 35 37 \rResistorElm 10 38\rResistorElm 10 39\rResistorElm 11 40\r" + - "TransistorElm 39 38 40 \rResistorElm 12 41\rTransistorElm 13 41 4 \rResistorElm 13 42\rTransistorElm 13 42 4 \rResistorElm 4 43\rTransistorElm 12 43 14 \rResistorElm 3 44\r" + - "TransistorElm 14 44 6 \rResistorElm 15 45\rTransistorElm 6 45 4 \rResistorElm 3 46\rTransistorElm 15 46 16 \rResistorElm 3 47\rTransistorElm 16 47 17 \rResistorElm 17 16\r" + - "ResistorElm 5 17\rResistorElm 4 48\rTransistorElm 15 48 5 \rResistorElm 15 49\rTransistorElm 17 49 5 \rCurrentElm 18 3\rCurrentElm 19 3\rCurrentElm 20 3\rResistorElm 11 50\r" + - "TransistorElm 18 50 3 \rResistorElm 14 51\rTransistorElm 19 51 3 \rResistorElm 5 52\rTransistorElm 7 52 4 \rResistorElm 15 53\rTransistorElm 20 53 3 \rCapacitorElm 21 22\r" + - "ResistorElm 12 21\rResistorElm 12 15\rVCVSElm 3 0 23 8\rVoltageElm 23 1\rCurrentElm 3 4\rResistorElm 4 3\rResistorElm 12 54\rTransistorElm 9 54 11 \rResistorElm 13 55\r" + - "TransistorElm 10 55 11 \rCapacitorElm 12 13\rCapacitorElm 6 15\rCapacitorElm 3 24\rResistorElm 11 24\rCapacitorElm 1 2\rCapacitorElm 2 0\rCapacitorElm 1 0\r" + - "VCVSElm 15 0 22 0\rCapacitorElm 5 0\rResistorElm 25 56\rTransistorElm 25 56 0 \rVCCSElm 27 0 4 3\rCurrentElm 0 25\rVoltageElm 25 26\rResistorElm 0 26\r" + - "VCVSElm 28 26 27 0\rResistorElm 0 27\rVoltageElm 28 0\rResistorElm 0 28"; + private static String lm324v2ModelString = "ResistorElm 4 6\rCurrentElm 4 7\rResistorElm 4 29\rResistorElm 8 30\rResistorElm 9 31\rTransistorElm 30 29 31 \rResistorElm 4 32\rResistorElm 2 33\rResistorElm 10 34\r" + + "TransistorElm 33 32 34 \rResistorElm 9 35\rResistorElm 9 36\rResistorElm 11 37\rTransistorElm 36 35 37 \rResistorElm 10 38\rResistorElm 10 39\rResistorElm 11 40\r" + + "TransistorElm 39 38 40 \rResistorElm 12 41\rTransistorElm 13 41 4 \rResistorElm 13 42\rTransistorElm 13 42 4 \rResistorElm 4 43\rTransistorElm 12 43 14 \rResistorElm 3 44\r" + + "TransistorElm 14 44 6 \rResistorElm 15 45\rTransistorElm 6 45 4 \rResistorElm 3 46\rTransistorElm 15 46 16 \rResistorElm 3 47\rTransistorElm 16 47 17 \rResistorElm 17 16\r" + + "ResistorElm 5 17\rResistorElm 4 48\rTransistorElm 15 48 5 \rResistorElm 15 49\rTransistorElm 17 49 5 \rCurrentElm 18 3\rCurrentElm 19 3\rCurrentElm 20 3\rResistorElm 11 50\r" + + "TransistorElm 18 50 3 \rResistorElm 14 51\rTransistorElm 19 51 3 \rResistorElm 5 52\rTransistorElm 7 52 4 \rResistorElm 15 53\rTransistorElm 20 53 3 \rCapacitorElm 21 22\r" + + "ResistorElm 12 21\rResistorElm 12 15\rVCVSElm 3 0 23 8\rVoltageElm 23 1\rCurrentElm 3 4\rResistorElm 4 3\rResistorElm 12 54\rTransistorElm 9 54 11 \rResistorElm 13 55\r" + + "TransistorElm 10 55 11 \rCapacitorElm 12 13\rCapacitorElm 6 15\rCapacitorElm 3 24\rResistorElm 11 24\rCapacitorElm 1 2\rCapacitorElm 2 0\rCapacitorElm 1 0\r" + + "VCVSElm 15 0 22 0\rCapacitorElm 5 0\rResistorElm 25 56\rTransistorElm 25 56 0 \rVCCSElm 27 0 4 3\rCurrentElm 0 25\rVoltageElm 25 26\rResistorElm 0 26\r" + + "VCVSElm 28 26 27 0\rResistorElm 0 27\rVoltageElm 28 0\rResistorElm 0 28"; private static int[] lm324v2ExternalNodes = { 2, 1, 5, 3, 4 }; - private static String lm324v2ModelDump = - "0 40000/0 5e-7/0 380/0 1700/0 5/0 -1 0 0 306 xlm324v2-qpi/0 380/0 1700/0 5/0 -1 0 0 300 xlm324v2-qpa/0 380/0 1700/0 5/0 -1 0 0 306 xlm324v2-qpi/0 380/0 1700/0 5/" + - "0 -1 0 0 306 xlm324v2-qpi/0 25/0 1 0 0 100 xlm324v2-qnq/0 25/0 1 0 0 100 xlm324v2-qnq/0 300/0 -1 0 0 100 xlm324v2-qpq/0 25/0 1 0 0 100 xlm324v2-qnq/0 25/0 1 0 0 100 xlm324v2-qnq/" + - "0 25/0 1 0 0 100 xlm324v2-qnq/0 25/0 1 0 0 100 xlm324v2-qnq/0 40000/0 18/0 300/0 -1 0 0 100 xlm324v2-qpq/0 25/0 1 0 0 100 xlm324v2-qnq/0 1.2e-7/0 6e-8/0 0.000001/0 300/" + - "0 -1 0 0 100 xlm324v2-qpq/0 300/0 -1 0 0 100 xlm324v2-qpq/0 25/0 1 0 0 100 xlm324v2-qnq/0 300/0 -1 0 0 100 xlm324v2-qpq/2 4.8e-12 0 0/0 3/0 3000000000/0 2 -0.00001*(a-b)/" + - "0 0 0 -0.00156/0 0.000005/0 450000/0 300/0 -1 0 0 100 xlm324v2-qpq/0 300/0 -1 0 0 100 xlm324v2-qpq/2 8e-12 0 0/2 1e-12 0 0/2 1e-13 0 0/0 300000/2 2.3e-13 0 0/2 7.9e-13 0 0/" + - "2 7.9e-13 0 0/0 2 2*(a-b)/2 5e-14 0 0/0 25/0 1 0 0 100 xlm324v2-qnq/0 2 0.0003*(a-b)/0 0.001/0 0 0 -0.25/0 1000000/0 2 1*(a-b)/0 1000000/0 0 0 -0.55/0 1000000"; + private static String lm324v2ModelDump = "0 40000/0 5e-7/0 380/0 1700/0 5/0 -1 0 0 306 xlm324v2-qpi/0 380/0 1700/0 5/0 -1 0 0 300 xlm324v2-qpa/0 380/0 1700/0 5/0 -1 0 0 306 xlm324v2-qpi/0 380/0 1700/0 5/" + + "0 -1 0 0 306 xlm324v2-qpi/0 25/0 1 0 0 100 xlm324v2-qnq/0 25/0 1 0 0 100 xlm324v2-qnq/0 300/0 -1 0 0 100 xlm324v2-qpq/0 25/0 1 0 0 100 xlm324v2-qnq/0 25/0 1 0 0 100 xlm324v2-qnq/" + + "0 25/0 1 0 0 100 xlm324v2-qnq/0 25/0 1 0 0 100 xlm324v2-qnq/0 40000/0 18/0 300/0 -1 0 0 100 xlm324v2-qpq/0 25/0 1 0 0 100 xlm324v2-qnq/0 1.2e-7/0 6e-8/0 0.000001/0 300/" + + "0 -1 0 0 100 xlm324v2-qpq/0 300/0 -1 0 0 100 xlm324v2-qpq/0 25/0 1 0 0 100 xlm324v2-qnq/0 300/0 -1 0 0 100 xlm324v2-qpq/2 4.8e-12 0 0/0 3/0 3000000000/0 2 -0.00001*(a-b)/" + + "0 0 0 -0.00156/0 0.000005/0 450000/0 300/0 -1 0 0 100 xlm324v2-qpq/0 300/0 -1 0 0 100 xlm324v2-qpq/2 8e-12 0 0/2 1e-12 0 0/2 1e-13 0 0/0 300000/2 2.3e-13 0 0/2 7.9e-13 0 0/" + + "2 7.9e-13 0 0/0 2 2*(a-b)/2 5e-14 0 0/0 25/0 1 0 0 100 xlm324v2-qnq/0 2 0.0003*(a-b)/0 0.001/0 0 0 -0.25/0 1000000/0 2 1*(a-b)/0 1000000/0 0 0 -0.55/0 1000000"; static final int MODEL_741 = 0; static final int MODEL_324 = 1; static final int MODEL_324v2 = 2; - - private static double[] model741resistances = { 50, 25, 1e3, 50e3, 1e3, 5e3, 50e3, 50, 39e3, 7500, 4500 }; + + private static double[] model741resistances = { 50, 25, 1e3, 50e3, 1e3, 5e3, 50e3, 50, 39e3, 7500, 4500 }; int modelType; final int opheight = 16; @@ -80,51 +79,60 @@ public OpAmpRealElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { try { currentLimit = Double.parseDouble(st.nextToken()); modelType = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + } catch (Exception e) { + } initModel(); } private void initModel() { flags |= FLAG_ESCAPE; switch (modelType) { - case MODEL_741: init741(); break; - case MODEL_324: init324(); break; - case MODEL_324v2: init324v2(); break; + case MODEL_741: + init741(); + break; + case MODEL_324: + init324(); + break; + case MODEL_324v2: + init324v2(); + break; } curCounts = new double[5]; setPoints(); } - + private void init741() { loadComposite(null, model741String, model741ExternalNodes); - + // adjust capacitor value to get desired slew rate - getCapacitor().capacitance = 30e-12 / (slewRate/.6); + getCapacitor().capacitance = 30e-12 / (slewRate / .6); getCapacitor().voltdiff = capValue; - + // set resistor values int i; for (i = 0; i != 11; i++) - ((ResistorElm) compElmList.get(21+i)).resistance = model741resistances[i]; - - // adjust output stage resistor values and transistor betas to increase current if desired + ((ResistorElm) compElmList.get(21 + i)).resistance = model741resistances[i]; + + // adjust output stage resistor values and transistor betas to increase current + // if desired double currentMult = currentLimit / defaultCurrentLimit; ((ResistorElm) compElmList.get(21)).resistance /= currentMult; ((ResistorElm) compElmList.get(22)).resistance /= currentMult; ((TransistorElm) compElmList.get(13)).setBeta(currentMult * 100); // Q14 ((TransistorElm) compElmList.get(18)).setBeta(currentMult * 100); // Q20 - + } private void init324() { StringTokenizer st = new StringTokenizer(lm324ModelDump, "/"); loadComposite(st, lm324ModelString, lm324ExternalNodes); - + // adjust capacitor value to get desired slew rate - getCapacitor().capacitance = 10e-12 / (slewRate/.55); + getCapacitor().capacitance = 10e-12 / (slewRate / .55); getCapacitor().voltdiff = capValue; - - // adjust output stage resistor values and transistor betas to increase current if desired + + // adjust output stage resistor values and transistor betas to increase current + // if desired double currentMult = currentLimit / defaultCurrentLimit; ((ResistorElm) compElmList.get(11)).resistance /= currentMult; ((TransistorElm) compElmList.get(9)).setBeta(currentMult * 100); @@ -132,12 +140,12 @@ private void init324() { ((TransistorElm) compElmList.get(12)).setBeta(currentMult * 100); ((TransistorElm) compElmList.get(16)).setBeta(currentMult * 100); } - + private void init324v2() { StringTokenizer st = new StringTokenizer(lm324v2ModelDump, "/"); loadComposite(st, lm324v2ModelString, lm324v2ExternalNodes); } - + public void reset() { super.reset(); curCounts = new double[5]; @@ -148,86 +156,86 @@ CapacitorElm getCapacitor() { return null; return ((CapacitorElm) compElmList.get(modelType == MODEL_741 ? 20 : 4)); } - + public String dump() { CapacitorElm elm = getCapacitor(); double voltdiff = (elm == null) ? 0 : elm.voltdiff; return super.dumpWithMask(0) + " " + slewRate + " " + voltdiff + " " + currentLimit + " " + modelType; } - + public boolean getConnection(int n1, int n2) { return true; } void draw(Graphics g) { - setBbox(point1, point2, opheight*2); - setVoltageColor(g, volts[0]); - drawThickLine(g, in1p[0], in1p[1]); - setVoltageColor(g, volts[1]); - drawThickLine(g, in2p[0], in2p[1]); - setVoltageColor(g, volts[2]); - drawThickLine(g, lead2, point2); - setVoltageColor(g, volts[3]); - drawThickLine(g, rail1p[0], rail1p[1]); - setVoltageColor(g, volts[4]); - drawThickLine(g, rail2p[0], rail2p[1]); - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - setPowerColor(g, true); - drawThickPolygon(g, triangle); - g.setFont(plusFont); - drawCenteredText(g, "-", textp[0].x, textp[0].y-2, true); - drawCenteredText(g, "+", textp[1].x, textp[1].y , true); - int i; - for (i = 0; i != 5; i++) - curCounts[i] = updateDotCount(getCurrentIntoNode(i), curCounts[i]); - drawDots(g, in1p[1], in1p[0], curCounts[0]); - drawDots(g, in2p[1], in2p[0], curCounts[1]); - drawDots(g, lead2, point2, curCounts[2]); - // these two segments may not be an event multiple of gridSize so we draw them the other way so the dots line up - drawDots(g, rail1p[0], rail1p[1], -curCounts[3]); - drawDots(g, rail2p[0], rail2p[1], -curCounts[4]); - drawPosts(g); + setBbox(point1, point2, opheight * 2); + setVoltageColor(g, volts[0]); + drawThickLine(g, in1p[0], in1p[1]); + setVoltageColor(g, volts[1]); + drawThickLine(g, in2p[0], in2p[1]); + setVoltageColor(g, volts[2]); + drawThickLine(g, lead2, point2); + setVoltageColor(g, volts[3]); + drawThickLine(g, rail1p[0], rail1p[1]); + setVoltageColor(g, volts[4]); + drawThickLine(g, rail2p[0], rail2p[1]); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + setPowerColor(g, true); + drawThickPolygon(g, triangle); + g.setFont(plusFont); + drawCenteredText(g, "-", textp[0].x, textp[0].y - 2, true); + drawCenteredText(g, "+", textp[1].x, textp[1].y, true); + int i; + for (i = 0; i != 5; i++) + curCounts[i] = updateDotCount(getCurrentIntoNode(i), curCounts[i]); + drawDots(g, in1p[1], in1p[0], curCounts[0]); + drawDots(g, in2p[1], in2p[0], curCounts[1]); + drawDots(g, lead2, point2, curCounts[2]); + // these two segments may not be an event multiple of gridSize so we draw them + // the other way so the dots line up + drawDots(g, rail1p[0], rail1p[1], -curCounts[3]); + drawDots(g, rail2p[0], rail2p[1], -curCounts[4]); + drawPosts(g); } - + Point in1p[], in2p[], textp[], rail1p[], rail2p[]; Polygon triangle; Font plusFont; void setPoints() { - super.setPoints(); - int ww = opwidth; - if (ww > dn/2) - ww = (int) (dn/2); - calcLeads(ww*2); - int hs = opheight*dsign; - int hsswap = hs; - if ((flags & FLAG_SWAP) != 0) - hsswap = -hsswap; - in1p = newPointArray(2); - in2p = newPointArray(2); - textp = newPointArray(2); - rail1p = newPointArray(2); - rail2p = newPointArray(2); - interpPoint2(point1, point2, in1p[0], in2p[0], 0, hsswap); - interpPoint2(lead1 , lead2, in1p[1], in2p[1], 0, hsswap); - interpPoint2(lead1 , lead2, textp[0], textp[1], .2, hsswap); - - // position rails; ideally in middle, but may need to be off-center to fit grid - double railPos = .5 - ((dn/2) % sim.gridSize)/(ww*2); - interpPoint2(lead1 , lead2, rail1p[1], rail2p[1], railPos, hs*2*(1-railPos)); - interpPoint2(lead1 , lead2, rail1p[0], rail2p[0], railPos, hs*2); - - Point tris[] = newPointArray(2); - interpPoint2(lead1, lead2, tris[0], tris[1], 0, hs*2); - triangle = createPolygon(tris[0], tris[1], lead2); - plusFont = new Font("SansSerif", 0, 14); - setPost(0, in1p[0]); - setPost(1, in2p[0]); - setPost(2, point2); - setPost(3, rail1p[0]); - setPost(4, rail2p[0]); - } + super.setPoints(); + int ww = opwidth; + if (ww > dn / 2) + ww = (int) (dn / 2); + calcLeads(ww * 2); + int hs = opheight * dsign; + int hsswap = hs; + if ((flags & FLAG_SWAP) != 0) + hsswap = -hsswap; + in1p = newPointArray(2); + in2p = newPointArray(2); + textp = newPointArray(2); + rail1p = newPointArray(2); + rail2p = newPointArray(2); + interpPoint2(point1, point2, in1p[0], in2p[0], 0, hsswap); + interpPoint2(lead1, lead2, in1p[1], in2p[1], 0, hsswap); + interpPoint2(lead1, lead2, textp[0], textp[1], .2, hsswap); + // position rails; ideally in middle, but may need to be off-center to fit grid + double railPos = .5 - ((dn / 2) % sim.gridSize) / (ww * 2); + interpPoint2(lead1, lead2, rail1p[1], rail2p[1], railPos, hs * 2 * (1 - railPos)); + interpPoint2(lead1, lead2, rail1p[0], rail2p[0], railPos, hs * 2); + + Point tris[] = newPointArray(2); + interpPoint2(lead1, lead2, tris[0], tris[1], 0, hs * 2); + triangle = createPolygon(tris[0], tris[1], lead2); + plusFont = new Font("SansSerif", 0, 14); + setPost(0, in1p[0]); + setPost(1, in2p[0]); + setPost(2, point2); + setPost(3, rail1p[0]); + setPost(4, rail2p[0]); + } @Override public int getDumpType() { @@ -236,47 +244,48 @@ public int getDumpType() { void getInfo(String arr[]) { String type = (modelType == MODEL_741) ? "LM741" : "LM324"; - arr[0] = "op-amp (" + type + ")"; - arr[1] = "V+ = " + getVoltageText(volts[1]); - arr[2] = "V- = " + getVoltageText(volts[0]); - arr[3] = "Vout = " + getVoltageText(volts[2]); - arr[4] = "Iout = " + getCurrentText(getCurrentIntoNode(2)); + arr[0] = "op-amp (" + type + ")"; + arr[1] = "V+ = " + getVoltageText(volts[1]); + arr[2] = "V- = " + getVoltageText(volts[0]); + arr[3] = "Vout = " + getVoltageText(volts[2]); + arr[4] = "Iout = " + getCurrentText(getCurrentIntoNode(2)); } - + public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo(EditInfo.makeLink("opampreal.html", "Model"), modelType); - ei.choice = new Choice(); - ei.choice.add("LM741"); - // hide old 324 model - if (modelType == MODEL_324) { - ei.choice.add("LM324, old"); - ei.choice.add("LM324, fixed"); - ei.choice.select(modelType); - } else { - ei.choice.add("LM324"); - ei.choice.select(modelType == MODEL_741 ? 0 : 1); - } - return ei; - } - if (n == 1) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Swap Inputs", (flags & FLAG_SWAP) != 0); - return ei; - } - if (modelType == MODEL_324v2) - return null; + if (n == 0) { + EditInfo ei = new EditInfo(EditInfo.makeLink("opampreal.html", "Model"), modelType); + ei.choice = new Choice(); + ei.choice.add("LM741"); + // hide old 324 model + if (modelType == MODEL_324) { + ei.choice.add("LM324, old"); + ei.choice.add("LM324, fixed"); + ei.choice.select(modelType); + } else { + ei.choice.add("LM324"); + ei.choice.select(modelType == MODEL_741 ? 0 : 1); + } + return ei; + } + if (n == 1) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Swap Inputs", (flags & FLAG_SWAP) != 0); + return ei; + } + if (modelType == MODEL_324v2) + return null; if (n == 2) return new EditInfo("Slew Rate (V/usec)", slewRate); if (n == 3) return new EditInfo("Output Current Limit (A)", currentLimit); return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) { modelType = ei.choice.getSelectedIndex(); - if (ei.choice.getItemCount() == 2 && modelType == 1) - modelType = MODEL_324v2; + if (ei.choice.getItemCount() == 2 && modelType == 1) + modelType = MODEL_324v2; capValue = 0; initModel(); ei.newDialog = true; @@ -294,5 +303,5 @@ public void setEditValue(int n, EditInfo ei) { initModel(); } } - + } diff --git a/src/com/lushprojects/circuitjs1/client/OpAmpSwapElm.java b/src/com/lushprojects/circuitjs1/client/OpAmpSwapElm.java index 2376d98d..08cea2d4 100644 --- a/src/com/lushprojects/circuitjs1/client/OpAmpSwapElm.java +++ b/src/com/lushprojects/circuitjs1/client/OpAmpSwapElm.java @@ -20,10 +20,16 @@ package com.lushprojects.circuitjs1.client; class OpAmpSwapElm extends OpAmpElm { - public OpAmpSwapElm(int xx, int yy) { - super(xx, yy); - flags |= FLAG_SWAP; - } - Class getDumpClass() { return OpAmpElm.class; } - int getShortcut() { return 'A'; } + public OpAmpSwapElm(int xx, int yy) { + super(xx, yy); + flags |= FLAG_SWAP; } + + Class getDumpClass() { + return OpAmpElm.class; + } + + int getShortcut() { + return 'A'; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/OptocouplerElm.java b/src/com/lushprojects/circuitjs1/client/OptocouplerElm.java index 86f29d84..b2f82dc2 100644 --- a/src/com/lushprojects/circuitjs1/client/OptocouplerElm.java +++ b/src/com/lushprojects/circuitjs1/client/OptocouplerElm.java @@ -27,17 +27,18 @@ public OptocouplerElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) public String dump() { return dumpWithMask(0); } - + private void initOptocoupler() { csize = 2; - cspc = 8*2; - cspc2 = cspc*2; + cspc = 8 * 2; + cspc2 = cspc * 2; diode = (DiodeElm) compElmList.get(0); CCCSElm cccs = (CCCSElm) compElmList.get(1); - + // from http://www.cel.com/pdf/appnotes/an3017.pdf - cccs.setExpr("max(0,min(.0001, select(i-.003, (-80000000000*(i)^5+800000000*(i)^4-3000000*(i)^3+5177.2*(i)^2+.2453*(i)-.00005)*1.04/700, (9000000*(i)^5-998113*(i)^4+42174*(i)^3-861.32*(i)^2+9.0836*(i)-.0078)*.945/700)))"); - + cccs.setExpr( + "max(0,min(.0001, select(i-.003, (-80000000000*(i)^5+800000000*(i)^4-3000000*(i)^3+5177.2*(i)^2+.2453*(i)-.00005)*1.04/700, (9000000*(i)^5-998113*(i)^4+42174*(i)^3-861.32*(i)^2+9.0836*(i)-.0078)*.945/700)))"); + transistor = (TransistorElm) compElmList.get(2); transistor.setBeta(700); curCounts = new double[4]; @@ -49,85 +50,88 @@ public void reset() { } public boolean getConnection(int n1, int n2) { - return n1/2 == n2/2; + return n1 / 2 == n2 / 2; } void draw(Graphics g) { - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - drawThickPolygon(g, rectPointsX, rectPointsY, 4); - - // draw stubs - int i; - for (i = 0; i != 4; i++) { - setVoltageColor(g, volts[i]); - Point a = posts[i]; - Point b = stubs[i]; - drawThickLine(g, a, b); - curCounts[i] = updateDotCount(-getCurrentIntoNode(i), curCounts[i]); - drawDots(g, a, b, curCounts[i]); - } - - diode.draw(g); - transistor.draw(g); - - drawPosts(g); - - // draw little arrows - g.setColor(lightGrayColor); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickPolygon(g, rectPointsX, rectPointsY, 4); + + // draw stubs + int i; + for (i = 0; i != 4; i++) { + setVoltageColor(g, volts[i]); + Point a = posts[i]; + Point b = stubs[i]; + drawThickLine(g, a, b); + curCounts[i] = updateDotCount(-getCurrentIntoNode(i), curCounts[i]); + drawDots(g, a, b, curCounts[i]); + } + + diode.draw(g); + transistor.draw(g); + + drawPosts(g); + + // draw little arrows + g.setColor(lightGrayColor); int dx = isFlippedX() ? -1 : 1; - int sx = stubs[0].x+2*dx; - int sy = (stubs[0].y+stubs[1].y)/2; - for (i = 0; i != 2; i++) { - int y = sy+i*10-5; - Point p1 = new Point(sx, y); - Point p2 = new Point(sx+20*dx, y); - Polygon p = calcArrow(p1, p2, 5, 2); - g.fillPolygon(p); - g.drawLine(sx+10*dx, y, sx+15*dx, y); - } + int sx = stubs[0].x + 2 * dx; + int sy = (stubs[0].y + stubs[1].y) / 2; + for (i = 0; i != 2; i++) { + int y = sy + i * 10 - 5; + Point p1 = new Point(sx, y); + Point p2 = new Point(sx + 20 * dx, y); + Polygon p = calcArrow(p1, p2, 5, 2); + g.fillPolygon(p); + g.drawLine(sx + 10 * dx, y, sx + 15 * dx, y); + } } Point stubs[]; - + void setPoints() { super.setPoints(); - + // adapted from ChipElm - int hs = cspc; - int x0 = x+cspc2; int y0 = y; - int xr = x0-cspc; - int yr = y0-cspc/2; - int sizeX = 2; - int sizeY = 2; - int xs = sizeX*cspc2; - int ys = sizeY*cspc2-cspc; - rectPointsX = new int[] { xr, xr+xs, xr+xs, xr }; - rectPointsY = new int[] { yr, yr, yr+ys, yr+ys }; - setBbox(xr, yr, rectPointsX[2], rectPointsY[2]); - stubs = new Point[4]; -// setPin(0, x0, y0, 1, 0, 0, -1, 0, 0); -// setPin(1, x0, y0, 1, 0, 0, 1, 0, ys-cspc2); -// setPin(2, x0, y0, 1, 0, 0, -1, 0, 0); -// setPin(3, x0, y0, 1, 0, 0, 1, 0, ys-cspc2); - setPin(0, x0, y0, 0, 1, -1, 0, 0, 0); - setPin(1, x0, y0, 0, 1, -1, 0, 0, 0); - setPin(2, x0, y0, 0, 1, 1, 0, xs-cspc2, 0); - setPin(3, x0, y0, 0, 1, 1, 0, xs-cspc2, 0); - int dx = isFlippedX() ? -1 : 1; - diode.setPosition(posts[0].x+32*dx, posts[0].y, posts[1].x+32*dx, posts[1].y); - stubs[0] = diode.getPost(0); - stubs[1] = diode.getPost(1); - - int midp = (posts[2].y+posts[3].y)/2; - transistor.setPosition(posts[2].x-40*dx, midp, posts[2].x-24*dx, midp); - stubs[2] = transistor.getPost(1); - stubs[3] = transistor.getPost(2); + int hs = cspc; + int x0 = x + cspc2; + int y0 = y; + int xr = x0 - cspc; + int yr = y0 - cspc / 2; + int sizeX = 2; + int sizeY = 2; + int xs = sizeX * cspc2; + int ys = sizeY * cspc2 - cspc; + rectPointsX = new int[] { xr, xr + xs, xr + xs, xr }; + rectPointsY = new int[] { yr, yr, yr + ys, yr + ys }; + setBbox(xr, yr, rectPointsX[2], rectPointsY[2]); + stubs = new Point[4]; + // setPin(0, x0, y0, 1, 0, 0, -1, 0, 0); + // setPin(1, x0, y0, 1, 0, 0, 1, 0, ys-cspc2); + // setPin(2, x0, y0, 1, 0, 0, -1, 0, 0); + // setPin(3, x0, y0, 1, 0, 0, 1, 0, ys-cspc2); + setPin(0, x0, y0, 0, 1, -1, 0, 0, 0); + setPin(1, x0, y0, 0, 1, -1, 0, 0, 0); + setPin(2, x0, y0, 0, 1, 1, 0, xs - cspc2, 0); + setPin(3, x0, y0, 0, 1, 1, 0, xs - cspc2, 0); + int dx = isFlippedX() ? -1 : 1; + diode.setPosition(posts[0].x + 32 * dx, posts[0].y, posts[1].x + 32 * dx, posts[1].y); + stubs[0] = diode.getPost(0); + stubs[1] = diode.getPost(1); + + int midp = (posts[2].y + posts[3].y) / 2; + transistor.setPosition(posts[2].x - 40 * dx, midp, posts[2].x - 24 * dx, midp); + stubs[2] = transistor.getPost(1); + stubs[3] = transistor.getPost(2); } - boolean isFlippedX() { return (flags & ChipElm.FLAG_FLIP_X) != 0; } + boolean isFlippedX() { + return (flags & ChipElm.FLAG_FLIP_X) != 0; + } void setPin(int n, int px, int py, int dx, int dy, int dax, int day, int sx, int sy) { - int pos = n % 2; + int pos = n % 2; if (isFlippedX()) { dx = -dx; dax = -dax; @@ -135,12 +139,12 @@ void setPin(int n, int px, int py, int dx, int dy, int dax, int day, int sx, int sx = -sx; } - int xa = px+cspc2*dx*pos+sx; - int ya = py+cspc2*dy*pos+sy; - setPost(n, new Point(xa+dax*cspc2, ya+day*cspc2)); - stubs[n] = new Point(xa+dax*cspc , ya+day*cspc ); + int xa = px + cspc2 * dx * pos + sx; + int ya = py + cspc2 * dy * pos + sy; + setPost(n, new Point(xa + dax * cspc2, ya + day * cspc2)); + stubs[n] = new Point(xa + dax * cspc, ya + day * cspc); } - + @Override public int getDumpType() { return 407; @@ -153,18 +157,18 @@ void getInfo(String arr[]) { } public EditInfo getEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Flip X", (flags & ChipElm.FLAG_FLIP_X) != 0); - return ei; - } - return null; + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Flip X", (flags & ChipElm.FLAG_FLIP_X) != 0); + return ei; + } + return null; } public void setEditValue(int n, EditInfo ei) { - if (n == 0) { - flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_X); - setPoints(); - } + if (n == 0) { + flags = ei.changeFlag(flags, ChipElm.FLAG_FLIP_X); + setPoints(); + } } } diff --git a/src/com/lushprojects/circuitjs1/client/OrGateElm.java b/src/com/lushprojects/circuitjs1/client/OrGateElm.java index 59c3d9ee..a9b166de 100644 --- a/src/com/lushprojects/circuitjs1/client/OrGateElm.java +++ b/src/com/lushprojects/circuitjs1/client/OrGateElm.java @@ -19,88 +19,94 @@ package com.lushprojects.circuitjs1.client; - class OrGateElm extends GateElm { - public OrGateElm(int xx, int yy) { super(xx, yy); } - public OrGateElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - } - String getGateName() { return "OR gate"; } - - void drawGatePolygon(Graphics g) { - g.setLineWidth(3.0); - g.context.beginPath(); - g.context.moveTo(gatePoly.xpoints[0], gatePoly.ypoints[0]); - g.context.lineTo(gatePoly.xpoints[1], gatePoly.ypoints[1]); - g.context.bezierCurveTo( - gatePoly.xpoints[2], gatePoly.ypoints[2], - gatePoly.xpoints[2], gatePoly.ypoints[2], - gatePoly.xpoints[3], gatePoly.ypoints[3]); - g.context.bezierCurveTo( - gatePoly.xpoints[4], gatePoly.ypoints[4], - gatePoly.xpoints[4], gatePoly.ypoints[4], - gatePoly.xpoints[5], gatePoly.ypoints[5]); - g.context.lineTo(gatePoly.xpoints[6], gatePoly.ypoints[6]); - g.context.bezierCurveTo( - gatePoly.xpoints[7], gatePoly.ypoints[7], - gatePoly.xpoints[7], gatePoly.ypoints[7], - gatePoly.xpoints[0], gatePoly.ypoints[0]); - g.context.closePath(); - - if (this instanceof XorGateElm) { - g.context.moveTo(gatePoly.xpoints[8], gatePoly.ypoints[8]); - g.context.bezierCurveTo( - gatePoly.xpoints[10], gatePoly.ypoints[10], - gatePoly.xpoints[10], gatePoly.ypoints[10], - gatePoly.xpoints[9], gatePoly.ypoints[9]); - } - - g.context.stroke(); - g.setLineWidth(1.0); +class OrGateElm extends GateElm { + public OrGateElm(int xx, int yy) { + super(xx, yy); + } + + public OrGateElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + } + + String getGateName() { + return "OR gate"; + } + + void drawGatePolygon(Graphics g) { + g.setLineWidth(3.0); + g.context.beginPath(); + g.context.moveTo(gatePoly.xpoints[0], gatePoly.ypoints[0]); + g.context.lineTo(gatePoly.xpoints[1], gatePoly.ypoints[1]); + g.context.bezierCurveTo(gatePoly.xpoints[2], gatePoly.ypoints[2], gatePoly.xpoints[2], gatePoly.ypoints[2], + gatePoly.xpoints[3], gatePoly.ypoints[3]); + g.context.bezierCurveTo(gatePoly.xpoints[4], gatePoly.ypoints[4], gatePoly.xpoints[4], gatePoly.ypoints[4], + gatePoly.xpoints[5], gatePoly.ypoints[5]); + g.context.lineTo(gatePoly.xpoints[6], gatePoly.ypoints[6]); + g.context.bezierCurveTo(gatePoly.xpoints[7], gatePoly.ypoints[7], gatePoly.xpoints[7], gatePoly.ypoints[7], + gatePoly.xpoints[0], gatePoly.ypoints[0]); + g.context.closePath(); + + if (this instanceof XorGateElm) { + g.context.moveTo(gatePoly.xpoints[8], gatePoly.ypoints[8]); + g.context.bezierCurveTo(gatePoly.xpoints[10], gatePoly.ypoints[10], gatePoly.xpoints[10], + gatePoly.ypoints[10], gatePoly.xpoints[9], gatePoly.ypoints[9]); } - - void setPoints() { - super.setPoints(); - - if (useEuroGates()) { - createEuroGatePolygon(); - linePoints = null; - } else { - // 0 - top left, 1 - start of top curve, 2 - control point for top curve - // 3 - right, 4 - control point for bottom curve, 5 - start of bottom curve, 6 - bottom right, 7 - control point for left curve -// if (this instanceof XorGateElm) -// linePoints = new Point[5]; - - Point triPoints[] = newPointArray(11); - interpPoint2(lead1, lead2, triPoints[0], triPoints[6], -.05, hs2); - interpPoint2(lead1, lead2, triPoints[1], triPoints[5], .3, hs2); - triPoints[3] = lead2; - interpPoint2(lead1, lead2, triPoints[2], triPoints[4], .7, hs2*.81); - interpPoint(lead1, lead2, triPoints[7], .08); // was .15 - - if (this instanceof XorGateElm) { - double ww2 = (ww == 0) ? dn*2 : ww*2; - interpPoint2(lead1, lead2, triPoints[8], triPoints[9], -.05-5/ww2, hs2); - interpPoint(lead1, lead2, triPoints[10], .08-5/ww2); - } - - gatePoly = createPolygon(triPoints); - } - if (isInverting()) { - pcircle = interpPoint(point1, point2, .5+(ww+4)/dn); - lead2 = interpPoint(point1, point2, .5+(ww+8)/dn); + + g.context.stroke(); + g.setLineWidth(1.0); + } + + void setPoints() { + super.setPoints(); + + if (useEuroGates()) { + createEuroGatePolygon(); + linePoints = null; + } else { + // 0 - top left, 1 - start of top curve, 2 - control point for top curve + // 3 - right, 4 - control point for bottom curve, 5 - start of bottom curve, 6 - + // bottom right, 7 - control point for left curve + // if (this instanceof XorGateElm) + // linePoints = new Point[5]; + + Point triPoints[] = newPointArray(11); + interpPoint2(lead1, lead2, triPoints[0], triPoints[6], -.05, hs2); + interpPoint2(lead1, lead2, triPoints[1], triPoints[5], .3, hs2); + triPoints[3] = lead2; + interpPoint2(lead1, lead2, triPoints[2], triPoints[4], .7, hs2 * .81); + interpPoint(lead1, lead2, triPoints[7], .08); // was .15 + + if (this instanceof XorGateElm) { + double ww2 = (ww == 0) ? dn * 2 : ww * 2; + interpPoint2(lead1, lead2, triPoints[8], triPoints[9], -.05 - 5 / ww2, hs2); + interpPoint(lead1, lead2, triPoints[10], .08 - 5 / ww2); } - } - String getGateText() { return "\u22651"; } - - boolean calcFunction() { - int i; - boolean f = false; - for (i = 0; i != inputCount; i++) - f |= getInput(i); - return f; + gatePoly = createPolygon(triPoints); } - int getDumpType() { return 152; } - int getShortcut() { return '3'; } + if (isInverting()) { + pcircle = interpPoint(point1, point2, .5 + (ww + 4) / dn); + lead2 = interpPoint(point1, point2, .5 + (ww + 8) / dn); + } + } + + String getGateText() { + return "\u22651"; + } + + boolean calcFunction() { + int i; + boolean f = false; + for (i = 0; i != inputCount; i++) + f |= getInput(i); + return f; + } + + int getDumpType() { + return 152; + } + + int getShortcut() { + return '3'; } +} diff --git a/src/com/lushprojects/circuitjs1/client/OutputElm.java b/src/com/lushprojects/circuitjs1/client/OutputElm.java index f38cbf7e..8adbf5fc 100644 --- a/src/com/lushprojects/circuitjs1/client/OutputElm.java +++ b/src/com/lushprojects/circuitjs1/client/OutputElm.java @@ -22,97 +22,119 @@ import com.lushprojects.circuitjs1.client.util.Locale; class OutputElm extends CircuitElm { - final int FLAG_VALUE = 1; - final int FLAG_FIXED = 2; - int scale; - public OutputElm(int xx, int yy) { - super(xx, yy); - scale = SCALE_AUTO; - } - public OutputElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - scale = SCALE_AUTO; - try { - scale = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} - } - - String dump() { - return super.dump() + " " + scale; - } - int getDumpType() { return 'O'; } - int getPostCount() { return 1; } - void setPoints() { - super.setPoints(); - lead1 = new Point(); - } - void draw(Graphics g) { - g.save(); - boolean selected = needsHighlight(); - Font f = new Font("SansSerif", selected ? Font.BOLD : 0, 14); - g.setFont(f); - g.setColor(selected ? selectColor : whiteColor); - String s = showVoltage() ? getUnitTextWithScale(volts[0], "V", scale, isFixed()) : Locale.LS("out"); -// FontMetrics fm = g.getFontMetrics(); - if (this == sim.plotXElm) - s = "X"; - if (this == sim.plotYElm) - s = "Y"; - interpPoint(point1, point2, lead1, 1-((int)g.context.measureText(s).getWidth()/2+8)/dn); - setBbox(point1, lead1, 0); - drawCenteredText(g, s, x2, y2, true); - setVoltageColor(g, volts[0]); - if (selected) - g.setColor(selectColor); - drawThickLine(g, point1, lead1); - drawPosts(g); - g.restore(); + final int FLAG_VALUE = 1; + final int FLAG_FIXED = 2; + int scale; + + public OutputElm(int xx, int yy) { + super(xx, yy); + scale = SCALE_AUTO; + } + + public OutputElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + scale = SCALE_AUTO; + try { + scale = Integer.parseInt(st.nextToken()); + } catch (Exception e) { } - double getVoltageDiff() { return volts[0]; } - void getInfo(String arr[]) { - arr[0] = "output"; - arr[1] = "V = " + getVoltageText(volts[0]); + } + + String dump() { + return super.dump() + " " + scale; + } + + int getDumpType() { + return 'O'; + } + + int getPostCount() { + return 1; + } + + void setPoints() { + super.setPoints(); + lead1 = new Point(); + } + + void draw(Graphics g) { + g.save(); + boolean selected = needsHighlight(); + Font f = new Font("SansSerif", selected ? Font.BOLD : 0, 14); + g.setFont(f); + g.setColor(selected ? selectColor : whiteColor); + String s = showVoltage() ? getUnitTextWithScale(volts[0], "V", scale, isFixed()) : Locale.LS("out"); + // FontMetrics fm = g.getFontMetrics(); + if (this == sim.plotXElm) + s = "X"; + if (this == sim.plotYElm) + s = "Y"; + interpPoint(point1, point2, lead1, 1 - ((int) g.context.measureText(s).getWidth() / 2 + 8) / dn); + setBbox(point1, lead1, 0); + drawCenteredText(g, s, x2, y2, true); + setVoltageColor(g, volts[0]); + if (selected) + g.setColor(selectColor); + drawThickLine(g, point1, lead1); + drawPosts(g); + g.restore(); + } + + double getVoltageDiff() { + return volts[0]; + } + + void getInfo(String arr[]) { + arr[0] = "output"; + arr[1] = "V = " + getVoltageText(volts[0]); + } + + public EditInfo getEditInfo(int n) { + if (n == 0) + return EditInfo.createCheckbox("Show Voltage", showVoltage()); + if (!showVoltage()) + return null; + if (n == 1) { + EditInfo ei = new EditInfo("Scale", 0); + ei.choice = new Choice(); + ei.choice.add("Auto"); + ei.choice.add("V"); + ei.choice.add("mV"); + ei.choice.add(Locale.muString + "V"); + ei.choice.select(scale); + return ei; } - public EditInfo getEditInfo(int n) { - if (n == 0) - return EditInfo.createCheckbox("Show Voltage", showVoltage()); - if (!showVoltage()) - return null; - if (n == 1) { - EditInfo ei = new EditInfo("Scale", 0); - ei.choice = new Choice(); - ei.choice.add("Auto"); - ei.choice.add("V"); - ei.choice.add("mV"); - ei.choice.add(Locale.muString + "V"); - ei.choice.select(scale); - return ei; - } - if (scale == SCALE_AUTO) - return null; - if (n == 2) - return EditInfo.createCheckbox("Fixed Precision", isFixed()); + if (scale == SCALE_AUTO) return null; + if (n == 2) + return EditInfo.createCheckbox("Fixed Precision", isFixed()); + return null; + } + + boolean isFixed() { + return (flags & FLAG_FIXED) != 0; + } + + boolean showVoltage() { + return (flags & FLAG_VALUE) != 0; + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 0) { + flags = ei.changeFlag(flags, FLAG_VALUE); + ei.newDialog = true; } - boolean isFixed() { return (flags & FLAG_FIXED) != 0; } - boolean showVoltage() { return (flags & FLAG_VALUE) != 0; } - public void setEditValue(int n, EditInfo ei) { - if (n == 0) { - flags = ei.changeFlag(flags, FLAG_VALUE); - ei.newDialog = true; - } - if (n==1) { - scale = ei.choice.getSelectedIndex(); - ei.newDialog = true; - } - if (n == 2) - flags = ei.changeFlag(flags, FLAG_FIXED); + if (n == 1) { + scale = ei.choice.getSelectedIndex(); + ei.newDialog = true; } - -// void drawHandles(Graphics g, Color c) { -// g.setColor(c); -// g.fillRect(x-3, y-3, 7, 7); -// } - + if (n == 2) + flags = ei.changeFlag(flags, FLAG_FIXED); } + + // void drawHandles(Graphics g, Color c) { + // g.setColor(c); + // g.fillRect(x-3, y-3, 7, 7); + // } + +} diff --git a/src/com/lushprojects/circuitjs1/client/PDarlingtonElm.java b/src/com/lushprojects/circuitjs1/client/PDarlingtonElm.java index c9f0f790..a5e736e8 100644 --- a/src/com/lushprojects/circuitjs1/client/PDarlingtonElm.java +++ b/src/com/lushprojects/circuitjs1/client/PDarlingtonElm.java @@ -1,17 +1,12 @@ package com.lushprojects.circuitjs1.client; - public class PDarlingtonElm extends DarlingtonElm { - - public PDarlingtonElm(int xx, int yy) { super(xx, yy, true); } - - Class getDumpClass() { + Class getDumpClass() { return DarlingtonElm.class; } } - diff --git a/src/com/lushprojects/circuitjs1/client/PMosfetElm.java b/src/com/lushprojects/circuitjs1/client/PMosfetElm.java index 15c62743..797df088 100644 --- a/src/com/lushprojects/circuitjs1/client/PMosfetElm.java +++ b/src/com/lushprojects/circuitjs1/client/PMosfetElm.java @@ -20,7 +20,15 @@ package com.lushprojects.circuitjs1.client; class PMosfetElm extends MosfetElm { - public PMosfetElm(int xx, int yy) { super(xx, yy, true); } - Class getDumpClass() { return MosfetElm.class; } - int getShortcut() { return 'P'; } + public PMosfetElm(int xx, int yy) { + super(xx, yy, true); } + + Class getDumpClass() { + return MosfetElm.class; + } + + int getShortcut() { + return 'P'; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/PTransistorElm.java b/src/com/lushprojects/circuitjs1/client/PTransistorElm.java index 391f0d43..21b3a4b8 100644 --- a/src/com/lushprojects/circuitjs1/client/PTransistorElm.java +++ b/src/com/lushprojects/circuitjs1/client/PTransistorElm.java @@ -20,9 +20,16 @@ package com.lushprojects.circuitjs1.client; class PTransistorElm extends TransistorElm { - public PTransistorElm(int xx, int yy) { super(xx, yy, true); } - Class getDumpClass() { return TransistorElm.class; } - - int getShortcut() { return 'p'; } - + public PTransistorElm(int xx, int yy) { + super(xx, yy, true); } + + Class getDumpClass() { + return TransistorElm.class; + } + + int getShortcut() { + return 'p'; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/PhaseCompElm.java b/src/com/lushprojects/circuitjs1/client/PhaseCompElm.java index 463bf29f..702b2b43 100644 --- a/src/com/lushprojects/circuitjs1/client/PhaseCompElm.java +++ b/src/com/lushprojects/circuitjs1/client/PhaseCompElm.java @@ -19,14 +19,19 @@ package com.lushprojects.circuitjs1.client; - class PhaseCompElm extends ChipElm { - public PhaseCompElm(int xx, int yy) { super(xx, yy); } - public PhaseCompElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + public PhaseCompElm(int xx, int yy) { + super(xx, yy); + } + + public PhaseCompElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f, st); } - String getChipName() { return "phase comparator"; } + + String getChipName() { + return "phase comparator"; + } + void setupPins() { sizeX = 2; sizeY = 2; @@ -36,14 +41,20 @@ void setupPins() { pins[2] = new Pin(0, SIDE_E, "O"); pins[2].output = true; } - boolean nonLinear() { return true; } + + boolean nonLinear() { + return true; + } + void stamp() { - int vn = sim.nodeList.size()+pins[2].voltSource; + int vn = sim.nodeList.size() + pins[2].voltSource; sim.stampNonLinear(vn); sim.stampNonLinear(0); sim.stampNonLinear(nodes[2]); } + boolean ff1, ff2; + void doStep() { boolean v1 = volts[0] > getThreshold(); boolean v2 = volts[1] > getThreshold(); @@ -54,19 +65,27 @@ void doStep() { if (ff1 && ff2) ff1 = ff2 = false; double out = (ff1) ? highVoltage : (ff2) ? 0 : -1; - //System.out.println(out + " " + v1 + " " + v2); + // System.out.println(out + " " + v1 + " " + v2); if (out != -1) sim.stampVoltageSource(0, nodes[2], pins[2].voltSource, out); else { // tie current through output pin to 0 - int vn = sim.nodeList.size()+pins[2].voltSource; + int vn = sim.nodeList.size() + pins[2].voltSource; sim.stampMatrix(vn, vn, 1); } pins[0].value = v1; pins[1].value = v2; } - int getPostCount() { return 3; } - int getVoltageSourceCount() { return 1; } - int getDumpType() { return 161; } + + int getPostCount() { + return 3; + } + + int getVoltageSourceCount() { + return 1; + } + + int getDumpType() { + return 161; + } } - diff --git a/src/com/lushprojects/circuitjs1/client/PisoShiftElm.java b/src/com/lushprojects/circuitjs1/client/PisoShiftElm.java index 9ef7148a..84b6ba94 100644 --- a/src/com/lushprojects/circuitjs1/client/PisoShiftElm.java +++ b/src/com/lushprojects/circuitjs1/client/PisoShiftElm.java @@ -22,126 +22,147 @@ // contributed by Edward Calver class PisoShiftElm extends ChipElm { - final int FLAG_NEW_BEHAVIOR = 2; //SER and no extra output register - - boolean[] data = new boolean[0]; - int dataIndex = 0; - boolean clockState = false; - boolean loadState = false; - int dataPinIndex; // the register pins' starting index - - public PisoShiftElm(int xx, int yy) { - super(xx, yy); - data = new boolean[bits]; - flags |= FLAG_NEW_BEHAVIOR; - setupPins(); - } - public PisoShiftElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - data = new boolean[bits]; - readBits(st, data); - setupPins(); - } - - String dump() { - //Normalize the circular array before exporting - boolean[] newData = new boolean[data.length]; - for (int i = 0; i < data.length; i++) - newData[i] = data[(i + dataIndex) % data.length]; - dataIndex = 0; - data = newData; - - return super.dump() + writeBits(data); - } - int getDumpType() { return 186; } - String getChipName() { return "PISO shift register"; } - - boolean needsBits() { return true; } - int defaultBitCount() { return 8; } - - boolean hasNewBhvr() { return (flags & FLAG_NEW_BEHAVIOR) != 0; } - - void reset() { - super.reset(); - data = new boolean[bits]; + final int FLAG_NEW_BEHAVIOR = 2; // SER and no extra output register + + boolean[] data = new boolean[0]; + int dataIndex = 0; + boolean clockState = false; + boolean loadState = false; + int dataPinIndex; // the register pins' starting index + + public PisoShiftElm(int xx, int yy) { + super(xx, yy); + data = new boolean[bits]; + flags |= FLAG_NEW_BEHAVIOR; + setupPins(); + } + + public PisoShiftElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + data = new boolean[bits]; + readBits(st, data); + setupPins(); + } + + String dump() { + // Normalize the circular array before exporting + boolean[] newData = new boolean[data.length]; + for (int i = 0; i < data.length; i++) + newData[i] = data[(i + dataIndex) % data.length]; + dataIndex = 0; + data = newData; + + return super.dump() + writeBits(data); + } + + int getDumpType() { + return 186; + } + + String getChipName() { + return "PISO shift register"; + } + + boolean needsBits() { + return true; + } + + int defaultBitCount() { + return 8; + } + + boolean hasNewBhvr() { + return (flags & FLAG_NEW_BEHAVIOR) != 0; + } + + void reset() { + super.reset(); + data = new boolean[bits]; + } + + void setupPins() { + sizeX = bits + 2; + sizeY = 3; + pins = new Pin[getPostCount()]; + + pins[0] = new Pin(1, SIDE_W, "LD"); + pins[1] = new Pin(2, SIDE_W, ""); + pins[1].clock = true; + + pins[2] = new Pin(1, SIDE_E, "Q" + (hasNewBhvr() ? bits - 1 : bits)); + pins[2].output = true; + + if (hasNewBhvr()) { + pins[3] = new Pin(0, SIDE_W, "SER"); + if (data != null && data.length > 0) + pins[2].value = data[0]; + dataPinIndex = 4; + } else { + dataPinIndex = 3; } - void setupPins() { - sizeX = bits + 2; - sizeY = 3; - pins = new Pin[getPostCount()]; - - pins[0] = new Pin(1, SIDE_W, "LD"); - pins[1] = new Pin(2, SIDE_W, ""); - pins[1].clock = true; - - pins[2] = new Pin(1, SIDE_E, "Q" + (hasNewBhvr() ? bits-1 : bits)); - pins[2].output = true; - + for (int i = 0; i < bits; i++) + pins[dataPinIndex + i] = new Pin(bits - i, SIDE_N, "D" + (bits - (i + 1))); + + allocNodes(); + } + + int getPostCount() { + return (hasNewBhvr() ? 4 : 3) + bits; + } + + int getVoltageSourceCount() { + return 1; + } + + void execute() { + // LOAD raised + if (pins[0].value != loadState) { + loadState = pins[0].value; + if (loadState && data.length > 0) { if (hasNewBhvr()) { - pins[3] = new Pin(0, SIDE_W, "SER"); - if (data != null && data.length > 0) - pins[2].value = data[0]; - dataPinIndex = 4; + pins[2].value = pins[dataPinIndex].value; // Set output immediately + dataIndex = 0; } else { - dataPinIndex = 3; - } - - for (int i = 0; i < bits; i++) - pins[dataPinIndex + i] = new Pin(bits - i, SIDE_N, "D" + (bits - (i + 1))); - - allocNodes(); - } - int getPostCount() { return (hasNewBhvr() ? 4 : 3) + bits; } - int getVoltageSourceCount() { return 1; } - - void execute() { - //LOAD raised - if (pins[0].value != loadState) { - loadState = pins[0].value; - if (loadState && data.length > 0) { - if (hasNewBhvr()) { - pins[2].value = pins[dataPinIndex].value; //Set output immediately - dataIndex = 0; - } else { - dataIndex = -1; - } - for (int i = 0; i < data.length; i++) - data[i] = pins[dataPinIndex + i].value; - } - } - - //CLK raised: Rotate the circular array - if (pins[1].value != clockState) { - clockState = pins[1].value; - if (clockState) { - //Shift - if (dataIndex >= 0) - data[dataIndex] = hasNewBhvr() && pins[3].value; - dataIndex++; - if (dataIndex >= data.length) - dataIndex = 0; - - //Write - pins[2].value = data[dataIndex]; - } + dataIndex = -1; } + for (int i = 0; i < data.length; i++) + data[i] = pins[dataPinIndex + i].value; + } } - - public EditInfo getChipEditInfo(int n) { - if (n == 0) - return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); - return null; + + // CLK raised: Rotate the circular array + if (pins[1].value != clockState) { + clockState = pins[1].value; + if (clockState) { + // Shift + if (dataIndex >= 0) + data[dataIndex] = hasNewBhvr() && pins[3].value; + dataIndex++; + if (dataIndex >= data.length) + dataIndex = 0; + + // Write + pins[2].value = data[dataIndex]; + } } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0) { - if (ei.value != bits && ei.value >= 1) { - bits = (int)ei.value; - data = new boolean[bits]; - setupPins(); - setPoints(); - } - return; - } + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) + return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); + return null; + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0) { + if (ei.value != bits && ei.value >= 1) { + bits = (int) ei.value; + data = new boolean[bits]; + setupPins(); + setPoints(); + } + return; } + } } diff --git a/src/com/lushprojects/circuitjs1/client/Point.java b/src/com/lushprojects/circuitjs1/client/Point.java index 8e65027a..d319d37c 100644 --- a/src/com/lushprojects/circuitjs1/client/Point.java +++ b/src/com/lushprojects/circuitjs1/client/Point.java @@ -20,41 +20,45 @@ package com.lushprojects.circuitjs1.client; public class Point { - public int x; - public int y; - - public Point(int i, int j) { - x=i; - y=j; - } - - public Point(Point p) { - x=p.x; - y=p.y; + public int x; + public int y; + + public Point(int i, int j) { + x = i; + y = j; + } + + public Point(Point p) { + x = p.x; + y = p.y; + } + + public Point() { + x = 0; + y = 0; + } + + public void setLocation(Point p) { + x = p.x; + y = p.y; + } + + public String toString() { + return "Point(" + x + "," + y + ")"; + } + + @Override + public boolean equals(Object other) { + boolean result = false; + if (other instanceof Point) { + Point that = (Point) other; + result = (this.x == that.x && this.y == that.y); } - - public Point() { - x=0; - y=0; - } - - public void setLocation(Point p) { - x=p.x; - y=p.y; - } - - public String toString() { return "Point(" + x + "," + y + ")"; } - - @Override public boolean equals(Object other) { - boolean result = false; - if (other instanceof Point) { - Point that = (Point) other; - result = (this.x == that.x && this.y == that.y); - } - return result; - } - - @Override public int hashCode() { - return (41 * (41 + x) + y); - } + return result; + } + + @Override + public int hashCode() { + return (41 * (41 + x) + y); + } } \ No newline at end of file diff --git a/src/com/lushprojects/circuitjs1/client/PolarCapacitorElm.java b/src/com/lushprojects/circuitjs1/client/PolarCapacitorElm.java index fb1e5438..7e134fdb 100644 --- a/src/com/lushprojects/circuitjs1/client/PolarCapacitorElm.java +++ b/src/com/lushprojects/circuitjs1/client/PolarCapacitorElm.java @@ -1,68 +1,79 @@ package com.lushprojects.circuitjs1.client; public class PolarCapacitorElm extends CapacitorElm { - double maxNegativeVoltage; - - public PolarCapacitorElm(int xx, int yy) { - super(xx, yy); - maxNegativeVoltage = 1; - } - public PolarCapacitorElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - maxNegativeVoltage = new Double(st.nextToken()).doubleValue(); - } - int getDumpType() { return 209; } - String dump() { - return super.dump() + " " + maxNegativeVoltage; - } - - Point plusPoint; - - void setPoints() { - super.setPoints(); - double f = (dn/2-4)/dn; - int i; - platePoints = newPointArray(14); - int maxI = platePoints.length-1; - double midI = maxI/2.; - for (i = 0; i <= maxI; i++) { - double q = (i - midI)*.9/midI; - platePoints[i] = interpPoint(plate2[0], plate2[1], i/(double) maxI, 5*(1-Math.sqrt(1-q*q))); - } - plusPoint = interpPoint(point1, point2, f-8/dn, -10*dsign); - if (y2 > y) - plusPoint.y += 4; - if (y > y2) - plusPoint.y += 3; - } - - void draw(Graphics g) { - super.draw(g); - g.setColor(whiteColor); - g.setFont(unitsFont); - int w = (int)g.context.measureText("+").getWidth();; - g.drawString("+", plusPoint.x-w/2, plusPoint.y); - } - void getInfo(String arr[]) { - super.getInfo(arr); - arr[0] = "capacitor (polarized)"; - } - public EditInfo getEditInfo(int n) { - if (n == 3) - return new EditInfo("Max Reverse Voltage", maxNegativeVoltage, 0, 0); - return super.getEditInfo(n); - } - public void setEditValue(int n, EditInfo ei) { - if (n == 3 && ei.value >= 0) - maxNegativeVoltage = ei.value; - super.setEditValue(n, ei); - } - - void stepFinished() { - if (getVoltageDiff() < 0 && getVoltageDiff() < -maxNegativeVoltage) - sim.stop("capacitor exceeded max reverse voltage", this); - super.stepFinished(); + double maxNegativeVoltage; + + public PolarCapacitorElm(int xx, int yy) { + super(xx, yy); + maxNegativeVoltage = 1; + } + + public PolarCapacitorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + maxNegativeVoltage = Double.valueOf(st.nextToken()).doubleValue(); + } + + int getDumpType() { + return 209; + } + + String dump() { + return super.dump() + " " + maxNegativeVoltage; + } + + Point plusPoint; + + void setPoints() { + super.setPoints(); + double f = (dn / 2 - 4) / dn; + int i; + platePoints = newPointArray(14); + int maxI = platePoints.length - 1; + double midI = maxI / 2.; + for (i = 0; i <= maxI; i++) { + double q = (i - midI) * .9 / midI; + platePoints[i] = interpPoint(plate2[0], plate2[1], i / (double) maxI, 5 * (1 - Math.sqrt(1 - q * q))); } - int getShortcut() { return 'C'; } + plusPoint = interpPoint(point1, point2, f - 8 / dn, -10 * dsign); + if (y2 > y) + plusPoint.y += 4; + if (y > y2) + plusPoint.y += 3; + } + + void draw(Graphics g) { + super.draw(g); + g.setColor(whiteColor); + g.setFont(unitsFont); + int w = (int) g.context.measureText("+").getWidth(); + ; + g.drawString("+", plusPoint.x - w / 2, plusPoint.y); + } + + void getInfo(String arr[]) { + super.getInfo(arr); + arr[0] = "capacitor (polarized)"; + } + + public EditInfo getEditInfo(int n) { + if (n == 3) + return new EditInfo("Max Reverse Voltage", maxNegativeVoltage, 0, 0); + return super.getEditInfo(n); + } + + public void setEditValue(int n, EditInfo ei) { + if (n == 3 && ei.value >= 0) + maxNegativeVoltage = ei.value; + super.setEditValue(n, ei); + } + + void stepFinished() { + if (getVoltageDiff() < 0 && getVoltageDiff() < -maxNegativeVoltage) + sim.stop("capacitor exceeded max reverse voltage", this); + super.stepFinished(); + } + + int getShortcut() { + return 'C'; + } } diff --git a/src/com/lushprojects/circuitjs1/client/Polygon.java b/src/com/lushprojects/circuitjs1/client/Polygon.java index 337e1767..9c868c93 100644 --- a/src/com/lushprojects/circuitjs1/client/Polygon.java +++ b/src/com/lushprojects/circuitjs1/client/Polygon.java @@ -19,51 +19,50 @@ // via http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/awt/Polygon.java class Polygon { -// ArrayList poly; - - private static final int MIN_LENGTH = 4; - public int npoints; - public int xpoints[]; - public int ypoints[]; - - - public Polygon(){ -// poly = new ArrayList(); - xpoints = new int[MIN_LENGTH]; - ypoints = new int[MIN_LENGTH]; - } - -// public void addPoint(int x, int y){ -// poly.add(new Point(x,y)); -// } - + // ArrayList poly; + + private static final int MIN_LENGTH = 4; + public int npoints; + public int xpoints[]; + public int ypoints[]; + + public Polygon() { + // poly = new ArrayList(); + xpoints = new int[MIN_LENGTH]; + ypoints = new int[MIN_LENGTH]; + } + + // public void addPoint(int x, int y){ + // poly.add(new Point(x,y)); + // } + public void addPoint(int x, int y) { - if (npoints >= xpoints.length || npoints >= ypoints.length) { - int newLength = npoints * 2; - // Make sure that newLength will be greater than MIN_LENGTH and - // aligned to the power of 2 - if (newLength < MIN_LENGTH) { - newLength = MIN_LENGTH; - } else if ((newLength & (newLength - 1)) != 0) { - newLength = Integer.highestOneBit(newLength); - } + if (npoints >= xpoints.length || npoints >= ypoints.length) { + int newLength = npoints * 2; + // Make sure that newLength will be greater than MIN_LENGTH and + // aligned to the power of 2 + if (newLength < MIN_LENGTH) { + newLength = MIN_LENGTH; + } else if ((newLength & (newLength - 1)) != 0) { + newLength = Integer.highestOneBit(newLength); + } - xpoints = expand(xpoints, newLength); - ypoints = expand(ypoints, newLength); - } - xpoints[npoints] = x; - ypoints[npoints] = y; - npoints++; -// if (bounds != null) { -// updateBounds(x, y); -// } + xpoints = expand(xpoints, newLength); + ypoints = expand(ypoints, newLength); + } + xpoints[npoints] = x; + ypoints[npoints] = y; + npoints++; + // if (bounds != null) { + // updateBounds(x, y); + // } } - + private int[] expand(int[] in, int newlen) { - int[] out=new int[newlen]; - for(int i=0; i abs(dy)) { - myLen = 2 * sim.gridSize * Integer.signum(dx) * ((((Integer)Math.abs(dx))+ 2 * sim.gridSize -1) / (2 * sim.gridSize)); - point2.x = point1.x + myLen; + myLen = 2 * sim.gridSize * Integer.signum(dx) + * ((((Integer) Math.abs(dx)) + 2 * sim.gridSize - 1) / (2 * sim.gridSize)); + point2.x = point1.x + myLen; offset = (dx < 0) ? dy : -dy; point2.y = point1.y; } else { - myLen = 2 * sim.gridSize * Integer.signum(dy) * ((((Integer)Math.abs(dy))+ 2 * sim.gridSize -1) / (2 * sim.gridSize)); + myLen = 2 * sim.gridSize * Integer.signum(dy) + * ((((Integer) Math.abs(dy)) + 2 * sim.gridSize - 1) / (2 * sim.gridSize)); if (dy != 0) { point2.y = point1.y + myLen; offset = (dy > 0) ? dx : -dx; point2.x = point1.x; } } -// if (abs(dx) > abs(dy)) { -// dx = Integer.signum(dx) * sim.snapGrid(Math.abs(dx) / 2) * 2; -// point2.x = x2 = point1.x + dx; -// offset = (dx < 0) ? dy : -dy; -// point2.y = point1.y; -// } else { -// dy = Integer.signum(dy) * sim.snapGrid(Math.abs(dy) / 2) * 2; -// if (dy != 0) { -// point2.y = y2 = point1.y + dy; -// offset = (dy > 0) ? dx : -dx; -// point2.x = point1.x; -// } -// } + // if (abs(dx) > abs(dy)) { + // dx = Integer.signum(dx) * sim.snapGrid(Math.abs(dx) / 2) * 2; + // point2.x = x2 = point1.x + dx; + // offset = (dx < 0) ? dy : -dy; + // point2.y = point1.y; + // } else { + // dy = Integer.signum(dy) * sim.snapGrid(Math.abs(dy) / 2) * 2; + // if (dy != 0) { + // point2.y = y2 = point1.y + dy; + // offset = (dy > 0) ? dx : -dx; + // point2.x = point1.x; + // } + // } if (offset == 0) offset = sim.gridSize; dn = distance(point1, point2); @@ -140,8 +148,7 @@ void setPoints() { ps3 = new Point(); ps4 = new Point(); } - - + void draw(Graphics g) { int segments = 16; int i; @@ -153,23 +160,29 @@ void draw(Graphics g) { setBbox(point1, point2, hs); draw2Leads(g); setPowerColor(g, true); - double segf = 1./segments; - int divide = (int) (segments*position); + double segf = 1. / segments; + int divide = (int) (segments * position); if (!sim.euroResistorCheckItem.getState()) { // draw zigzag for (i = 0; i != segments; i++) { int nx = 0; switch (i & 3) { - case 0: nx = 1; break; - case 2: nx = -1; break; - default: nx = 0; break; + case 0: + nx = 1; + break; + case 2: + nx = -1; + break; + default: + nx = 0; + break; } - double v = v1+(v3-v1)*i/divide; + double v = v1 + (v3 - v1) * i / divide; if (i >= divide) - v = v3+(v2-v3)*(i-divide)/(segments-divide); + v = v3 + (v2 - v3) * (i - divide) / (segments - divide); setVoltageColor(g, v); - interpPoint(lead1, lead2, ps1, i*segf, hs*ox); - interpPoint(lead1, lead2, ps2, (i+1)*segf, hs*nx); + interpPoint(lead1, lead2, ps1, i * segf, hs * ox); + interpPoint(lead1, lead2, ps2, (i + 1) * segf, hs * nx); drawThickLine(g, ps1, ps2); ox = nx; } @@ -179,12 +192,12 @@ void draw(Graphics g) { interpPoint2(lead1, lead2, ps1, ps2, 0, hs); drawThickLine(g, ps1, ps2); for (i = 0; i != segments; i++) { - double v = v1+(v3-v1)*i/divide; + double v = v1 + (v3 - v1) * i / divide; if (i >= divide) - v = v3+(v2-v3)*(i-divide)/(segments-divide); + v = v3 + (v2 - v3) * (i - divide) / (segments - divide); setVoltageColor(g, v); - interpPoint2(lead1, lead2, ps1, ps2, i*segf, hs); - interpPoint2(lead1, lead2, ps3, ps4, (i+1)*segf, hs); + interpPoint2(lead1, lead2, ps1, ps2, i * segf, hs); + interpPoint2(lead1, lead2, ps3, ps4, (i + 1) * segf, hs); drawThickLine(g, ps1, ps3); drawThickLine(g, ps2, ps4); } @@ -203,8 +216,7 @@ void draw(Graphics g) { drawDots(g, point1, midpoint, curcount1); drawDots(g, point2, midpoint, curcount2); drawDots(g, post3, corner2, curcount3); - drawDots(g, corner2, midpoint, - curcount3+distance(post3, corner2)); + drawDots(g, corner2, midpoint, curcount3 + distance(post3, corner2)); } drawPosts(g); @@ -213,41 +225,45 @@ void draw(Graphics g) { boolean reverseY = (post3.x < lead1.x && lead1.x == lead2.x); // check for horizontal pot with 3rd terminal on top boolean reverseX = (post3.y < lead1.y && lead1.x != lead2.x); - // check if we need to swap texts (if leads are reversed, e.g. drawn right to left) + // check if we need to swap texts (if leads are reversed, e.g. drawn right to + // left) boolean rev = (lead1.x == lead2.x && lead1.y < lead2.y) || (lead1.y == lead2.y && lead1.x > lead2.x); - + // draw units String s1 = getShortUnitText(rev ? resistance2 : resistance1, ""); String s2 = getShortUnitText(rev ? resistance1 : resistance2, ""); g.setFont(unitsFont); g.setColor(whiteColor); - int ya = (int)g.currentFontSize/2; + int ya = (int) g.currentFontSize / 2; int w; - w = (int)g.context.measureText(s1).getWidth(); - + w = (int) g.context.measureText(s1).getWidth(); + // vertical? if (lead1.x == lead2.x) - g.drawString(s1, !reverseY ? arrowPoint.x+2 : arrowPoint.x-2-w, Math.max(arrow1.y, arrow2.y)+5+ya); + g.drawString(s1, !reverseY ? arrowPoint.x + 2 : arrowPoint.x - 2 - w, + Math.max(arrow1.y, arrow2.y) + 5 + ya); else - g.drawString(s1, Math.min(arrow1.x, arrow2.x)-2-w, !reverseX ? arrowPoint.y+4+ya : arrowPoint.y-4); - - w = (int)g.context.measureText(s2).getWidth(); + g.drawString(s1, Math.min(arrow1.x, arrow2.x) - 2 - w, + !reverseX ? arrowPoint.y + 4 + ya : arrowPoint.y - 4); + + w = (int) g.context.measureText(s2).getWidth(); if (lead1.x == lead2.x) - g.drawString(s2, !reverseY ? arrowPoint.x+2 : arrowPoint.x-2-w, Math.min(arrow1.y, arrow2.y)-3); + g.drawString(s2, !reverseY ? arrowPoint.x + 2 : arrowPoint.x - 2 - w, Math.min(arrow1.y, arrow2.y) - 3); else - g.drawString(s2, Math.max(arrow1.x, arrow2.x)+2, !reverseX ? arrowPoint.y+4+ya : arrowPoint.y-4); + g.drawString(s2, Math.max(arrow1.x, arrow2.x) + 2, + !reverseX ? arrowPoint.y + 4 + ya : arrowPoint.y - 4); } } - - // draw component values (number of resistor ohms, etc). hs = offset + + // draw component values (number of resistor ohms, etc). hs = offset void drawValues(Graphics g, String s, Point pt, int hs) { if (s == null) return; g.setFont(unitsFont); - //FontMetrics fm = g.getFontMetrics(); - int w = (int)g.context.measureText(s).getWidth(); + // FontMetrics fm = g.getFontMetrics(); + int w = (int) g.context.measureText(s).getWidth(); g.setColor(whiteColor); - int ya = (int)g.currentFontSize/2; + int ya = (int) g.currentFontSize / 2; int xc = pt.x; int yc = pt.y; int dpx = hs; @@ -258,39 +274,42 @@ void drawValues(Graphics g, String s, Point pt, int hs) { } CirSim.console("dv " + dpx + " " + w); if (dpx == 0) - g.drawString(s, xc-w/2, yc-abs(dpy)-2); + g.drawString(s, xc - w / 2, yc - abs(dpy) - 2); else { - int xx = xc+abs(dpx)+2; - g.drawString(s, xx, yc+dpy+ya); + int xx = xc + abs(dpx) + 2; + g.drawString(s, xx, yc + dpy + ya); } } - + void reset() { curcount1 = curcount2 = curcount3 = 0; super.reset(); } + void calculateCurrent() { if (resistance1 == 0) return; // avoid NaN - current1 = (volts[0]-volts[2])/resistance1; - current2 = (volts[1]-volts[2])/resistance2; - current3 = -current1-current2; + current1 = (volts[0] - volts[2]) / resistance1; + current2 = (volts[1] - volts[2]) / resistance2; + current3 = -current1 - current2; } - - @Override double getCurrentIntoNode(int n) { + + @Override + double getCurrentIntoNode(int n) { if (n == 0) return -current1; if (n == 1) return -current2; return -current3; } - + void stamp() { - resistance1 = maxResistance*position; - resistance2 = maxResistance*(1-position); + resistance1 = maxResistance * position; + resistance2 = maxResistance * (1 - position); sim.stampResistor(nodes[0], nodes[2], resistance1); sim.stampResistor(nodes[2], nodes[1], resistance2); } + void getInfo(String arr[]) { arr[0] = "potentiometer"; arr[1] = "Vd = " + getVoltageDText(getVoltageDiff()); @@ -299,6 +318,7 @@ void getInfo(String arr[]) { arr[4] = "I1 = " + getCurrentDText(current1); arr[5] = "I2 = " + getCurrentDText(current2); } + public EditInfo getEditInfo(int n) { // ohmString doesn't work here on linux if (n == 0) @@ -309,12 +329,13 @@ public EditInfo getEditInfo(int n) { return ei; } if (n == 2) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Show Values", (flags & FLAG_SHOW_VALUES) != 0); - return ei; + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Show Values", (flags & FLAG_SHOW_VALUES) != 0); + return ei; } return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0) maxResistance = ei.value; @@ -326,15 +347,15 @@ public void setEditValue(int n, EditInfo ei) { if (n == 2) flags = ei.changeFlag(flags, FLAG_SHOW_VALUES); } + void setMouseElm(boolean v) { - super.setMouseElm(v); - if (slider!=null) - slider.draw(); + super.setMouseElm(v); + if (slider != null) + slider.draw(); } - + public void onMouseWheel(MouseWheelEvent e) { - if (slider!=null) - slider.onMouseWheel(e); + if (slider != null) + slider.onMouseWheel(e); } } - diff --git a/src/com/lushprojects/circuitjs1/client/ProbeElm.java b/src/com/lushprojects/circuitjs1/client/ProbeElm.java index 974b151e..ef6023ad 100644 --- a/src/com/lushprojects/circuitjs1/client/ProbeElm.java +++ b/src/com/lushprojects/circuitjs1/client/ProbeElm.java @@ -38,86 +38,91 @@ class ProbeElm extends CircuitElm { final int TP_FRQ = 6; final int TP_PER = 7; final int TP_PWI = 8; - final int TP_DUT = 9; //mark to space ratio - - public ProbeElm(int xx, int yy) { super(xx, yy); - meter = TP_VOL; - - // default for new elements - flags = FLAG_SHOWVOLTAGE | FLAG_CIRCLE; - scale = SCALE_AUTO; + final int TP_DUT = 9; // mark to space ratio + + public ProbeElm(int xx, int yy) { + super(xx, yy); + meter = TP_VOL; + + // default for new elements + flags = FLAG_SHOWVOLTAGE | FLAG_CIRCLE; + scale = SCALE_AUTO; } - public ProbeElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public ProbeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - meter = TP_VOL; - scale = SCALE_AUTO; + meter = TP_VOL; + scale = SCALE_AUTO; try { meter = Integer.parseInt(st.nextToken()); // get meter type from saved dump scale = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + } catch (Exception e) { + } + } + + int getDumpType() { + return 'p'; } - int getDumpType() { return 'p'; } + String dump() { - return super.dump() + " " + meter + " " + scale; + return super.dump() + " " + meter + " " + scale; } - String getMeter(){ - switch (meter) { - case TP_VOL: - return "V"; - case TP_RMS: - return "V(rms)"; - case TP_MAX: - return "Vmax"; - case TP_MIN: - return "Vmin"; - case TP_P2P: - return "Peak to peak"; - case TP_BIN: - return "Binary"; - case TP_FRQ: - return "Frequency"; - case TP_PER: - return "Period"; - case TP_PWI: - return "Pulse width"; - case TP_DUT: - return "Duty cycle"; - } - return ""; + + String getMeter() { + switch (meter) { + case TP_VOL: + return "V"; + case TP_RMS: + return "V(rms)"; + case TP_MAX: + return "Vmax"; + case TP_MIN: + return "Vmin"; + case TP_P2P: + return "Peak to peak"; + case TP_BIN: + return "Binary"; + case TP_FRQ: + return "Frequency"; + case TP_PER: + return "Period"; + case TP_PWI: + return "Pulse width"; + case TP_DUT: + return "Duty cycle"; + } + return ""; } - - double rmsV=0, total, count; - double binaryLevel=0;//0 or 1 - double because we only pass doubles back to the web page - int zerocount=0; - double maxV=0, lastMaxV; - double minV=0, lastMinV; - double frequency=0; - double period=0; - double pulseWidth=0; - double dutyCycle=0; - double selectedValue=0; - - boolean increasingV=true, decreasingV=true; - long periodStart, periodLength, pulseStart;//time between consecutive max values + + double rmsV = 0, total, count; + double binaryLevel = 0;// 0 or 1 - double because we only pass doubles back to the web page + int zerocount = 0; + double maxV = 0, lastMaxV; + double minV = 0, lastMinV; + double frequency = 0; + double period = 0; + double pulseWidth = 0; + double dutyCycle = 0; + double selectedValue = 0; + + boolean increasingV = true, decreasingV = true; + long periodStart, periodLength, pulseStart;// time between consecutive max values Point center; - - void setPoints() { - super.setPoints(); - center = interpPoint(point1, point2, .5); - } - - + + void setPoints() { + super.setPoints(); + center = interpPoint(point1, point2, .5); + } void draw(Graphics g) { g.save(); int hs = (drawAsCircle()) ? circleSize : 8; setBbox(point1, point2, hs); boolean selected = needsHighlight(); - double len = (selected || sim.dragElm == this || mustShowVoltage()) ? 16 : dn-32; + double len = (selected || sim.dragElm == this || mustShowVoltage()) ? 16 : dn - 32; if (drawAsCircle()) - len = circleSize*2; + len = circleSize * 2; calcLeads((int) len); setVoltageColor(g, volts[0]); if (selected) @@ -135,145 +140,150 @@ void draw(Graphics g) { drawCenteredText(g, "Y", center.x, center.y, true); if (mustShowVoltage()) { String s = ""; - switch (meter) { - case TP_VOL: - s = getUnitTextWithScale(getVoltageDiff(),"V", scale); - break; - case TP_RMS: - s = getUnitTextWithScale(rmsV,"V(rms)", scale); - break; - case TP_MAX: - s = getUnitTextWithScale(lastMaxV,"Vpk", scale); - break; - case TP_MIN: - s = getUnitTextWithScale(lastMinV,"Vmin", scale); - break; - case TP_P2P: - s = getUnitTextWithScale(lastMaxV-lastMinV,"Vp2p", scale); - break; - case TP_BIN: - s= binaryLevel + ""; - break; - case TP_FRQ: - s = getUnitText(frequency, "Hz"); - break; - case TP_PER: -// s = "percent:"+period + " " + sim.timeStep + " " + sim.simTime + " " + sim.getIterCount(); - break; - case TP_PWI: - s = getUnitText(pulseWidth, "S"); - break; - case TP_DUT: - s = showFormat.format(dutyCycle); - break; - } - drawValues(g, s, drawAsCircle() ? circleSize+3 : 4); + switch (meter) { + case TP_VOL: + s = getUnitTextWithScale(getVoltageDiff(), "V", scale); + break; + case TP_RMS: + s = getUnitTextWithScale(rmsV, "V(rms)", scale); + break; + case TP_MAX: + s = getUnitTextWithScale(lastMaxV, "Vpk", scale); + break; + case TP_MIN: + s = getUnitTextWithScale(lastMinV, "Vmin", scale); + break; + case TP_P2P: + s = getUnitTextWithScale(lastMaxV - lastMinV, "Vp2p", scale); + break; + case TP_BIN: + s = binaryLevel + ""; + break; + case TP_FRQ: + s = getUnitText(frequency, "Hz"); + break; + case TP_PER: + // s = "percent:"+period + " " + sim.timeStep + " " + sim.simTime + " " + + // sim.getIterCount(); + break; + case TP_PWI: + s = getUnitText(pulseWidth, "S"); + break; + case TP_DUT: + s = showFormat.format(dutyCycle); + break; + } + drawValues(g, s, drawAsCircle() ? circleSize + 3 : 4); + } + g.setColor(whiteColor); + g.setFont(unitsFont); + Point plusPoint = interpPoint(point1, point2, (dn / 2 - len / 2 - 4) / dn, -10 * dsign); + if (y2 > y) + plusPoint.y += 4; + if (y > y2) + plusPoint.y += 3; + int w = (int) g.context.measureText("+").getWidth(); + g.drawString("+", plusPoint.x - w / 2, plusPoint.y); + if (drawAsCircle()) { + g.setColor(lightGrayColor); + drawThickCircle(g, center.x, center.y, circleSize); + drawCenteredText(g, "V", center.x, center.y, true); } - g.setColor(whiteColor); - g.setFont(unitsFont); - Point plusPoint = interpPoint(point1, point2, (dn/2-len/2-4)/dn, -10*dsign ); - if (y2 > y) - plusPoint.y += 4; - if (y > y2) - plusPoint.y += 3; - int w = (int)g.context.measureText("+").getWidth(); - g.drawString("+", plusPoint.x-w/2, plusPoint.y); - if (drawAsCircle()) { - g.setColor(lightGrayColor); - drawThickCircle(g, center.x, center.y, circleSize); - drawCenteredText(g, "V", center.x, center.y, true); - } drawPosts(g); g.restore(); } final int circleSize = 12; - + boolean mustShowVoltage() { return (flags & FLAG_SHOWVOLTAGE) != 0; } - boolean drawAsCircle() { return (flags & FLAG_CIRCLE) != 0; } - - void stepFinished(){ - count++;//how many counts are in a cycle - double v = getVoltageDiff(); - total += v*v; //sum of squares - - if (v<2.5) - binaryLevel = 0; - else - binaryLevel = 1; - - - //V going up, track maximum value with - if (v>maxV && increasingV){ - maxV = v; - increasingV = true; - decreasingV = false; - } - if (vminV && decreasingV){ //change of direction V now going up - lastMinV=minV; //capture last minimum - pulseStart = System.currentTimeMillis(); - maxV = v; - increasingV = true; - decreasingV = false; - - //rms data - total = total/count; - rmsV = Math.sqrt(total); - if (Double.isNaN(rmsV)) - rmsV=0; - count=0; - total=0; - - - } - //need to zero the rms value if it stays at 0 for a while - if (v==0){ - zerocount++; - if (zerocount > 5){ - total=0; - rmsV=0; - maxV=0; - minV=0; - } - }else{ - zerocount=0; - } + + boolean drawAsCircle() { + return (flags & FLAG_CIRCLE) != 0; + } + + void stepFinished() { + count++;// how many counts are in a cycle + double v = getVoltageDiff(); + total += v * v; // sum of squares + + if (v < 2.5) + binaryLevel = 0; + else + binaryLevel = 1; + + // V going up, track maximum value with + if (v > maxV && increasingV) { + maxV = v; + increasingV = true; + decreasingV = false; + } + if (v < maxV && increasingV) {// change of direction V now going down - at start of waveform + lastMaxV = maxV; // capture last maximum + // capture time between + periodLength = System.currentTimeMillis() - periodStart; + periodStart = System.currentTimeMillis(); + period = periodLength; + pulseWidth = System.currentTimeMillis() - pulseStart; + dutyCycle = pulseWidth / periodLength; + minV = v; // track minimum value with V + increasingV = false; + decreasingV = true; + + // rms data + total = total / count; + rmsV = Math.sqrt(total); + if (Double.isNaN(rmsV)) + rmsV = 0; + count = 0; + total = 0; + + } + if (v < minV && decreasingV) { // V going down, track minimum value with V + minV = v; + increasingV = false; + decreasingV = true; + } + + if (v > minV && decreasingV) { // change of direction V now going up + lastMinV = minV; // capture last minimum + pulseStart = System.currentTimeMillis(); + maxV = v; + increasingV = true; + decreasingV = false; + + // rms data + total = total / count; + rmsV = Math.sqrt(total); + if (Double.isNaN(rmsV)) + rmsV = 0; + count = 0; + total = 0; + + } + // need to zero the rms value if it stays at 0 for a while + if (v == 0) { + zerocount++; + if (zerocount > 5) { + total = 0; + rmsV = 0; + maxV = 0; + minV = 0; + } + } else { + zerocount = 0; + } } void getInfo(String arr[]) { arr[0] = "voltmeter"; arr[1] = "Vd = " + getVoltageText(getVoltageDiff()); } - boolean getConnection(int n1, int n2) { return false; } + + boolean getConnection(int n1, int n2) { + return false; + } public EditInfo getEditInfo(int n) { if (n == 0) { @@ -281,38 +291,38 @@ public EditInfo getEditInfo(int n) { ei.checkbox = new Checkbox("Show Value", mustShowVoltage()); return ei; } - if (n==1){ - EditInfo ei = new EditInfo("Value", selectedValue, -1, -1); - ei.choice = new Choice(); - ei.choice.add("Voltage"); - ei.choice.add("RMS Voltage"); - ei.choice.add("Max Voltage"); - ei.choice.add("Min Voltage"); - ei.choice.add("P2P Voltage"); - ei.choice.add("Binary Value"); - //ei.choice.add("Frequency"); - //ei.choice.add("Period"); - //ei.choice.add("Pulse Width"); - //ei.choice.add("Duty Cycle"); - ei.choice.select(meter); - return ei; - } - if (n == 2) { - EditInfo ei = new EditInfo("Scale", 0); - ei.choice = new Choice(); - ei.choice.add("Auto"); - ei.choice.add("V"); - ei.choice.add("mV"); - ei.choice.add(Locale.muString + "V"); - ei.choice.select(scale); - return ei; - } - if (n == 3) { - EditInfo ei = EditInfo.createCheckbox("Use Circle Symbol", drawAsCircle()); - return ei; - } - - return null; + if (n == 1) { + EditInfo ei = new EditInfo("Value", selectedValue, -1, -1); + ei.choice = new Choice(); + ei.choice.add("Voltage"); + ei.choice.add("RMS Voltage"); + ei.choice.add("Max Voltage"); + ei.choice.add("Min Voltage"); + ei.choice.add("P2P Voltage"); + ei.choice.add("Binary Value"); + // ei.choice.add("Frequency"); + // ei.choice.add("Period"); + // ei.choice.add("Pulse Width"); + // ei.choice.add("Duty Cycle"); + ei.choice.select(meter); + return ei; + } + if (n == 2) { + EditInfo ei = new EditInfo("Scale", 0); + ei.choice = new Choice(); + ei.choice.add("Auto"); + ei.choice.add("V"); + ei.choice.add("mV"); + ei.choice.add(Locale.muString + "V"); + ei.choice.select(scale); + return ei; + } + if (n == 3) { + EditInfo ei = EditInfo.createCheckbox("Use Circle Symbol", drawAsCircle()); + return ei; + } + + return null; } public void setEditValue(int n, EditInfo ei) { @@ -322,13 +332,12 @@ public void setEditValue(int n, EditInfo ei) { else flags &= ~FLAG_SHOWVOLTAGE; } - if (n==1){ - meter = ei.choice.getSelectedIndex(); - } - if (n == 2) - scale = ei.choice.getSelectedIndex(); - if (n == 3) - flags = ei.changeFlag(flags, FLAG_CIRCLE); + if (n == 1) { + meter = ei.choice.getSelectedIndex(); + } + if (n == 2) + scale = ei.choice.getSelectedIndex(); + if (n == 3) + flags = ei.changeFlag(flags, FLAG_CIRCLE); } } - diff --git a/src/com/lushprojects/circuitjs1/client/PushSwitchElm.java b/src/com/lushprojects/circuitjs1/client/PushSwitchElm.java index 39ce5ea1..fb0a0e1e 100644 --- a/src/com/lushprojects/circuitjs1/client/PushSwitchElm.java +++ b/src/com/lushprojects/circuitjs1/client/PushSwitchElm.java @@ -20,7 +20,15 @@ package com.lushprojects.circuitjs1.client; class PushSwitchElm extends SwitchElm { - public PushSwitchElm(int xx, int yy) { super(xx, yy, true); } - Class getDumpClass() { return SwitchElm.class; } - int getShortcut() { return 0; } + public PushSwitchElm(int xx, int yy) { + super(xx, yy, true); } + + Class getDumpClass() { + return SwitchElm.class; + } + + int getShortcut() { + return 0; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/QueryParameters.java b/src/com/lushprojects/circuitjs1/client/QueryParameters.java index 6114df1e..bd9ffad4 100644 --- a/src/com/lushprojects/circuitjs1/client/QueryParameters.java +++ b/src/com/lushprojects/circuitjs1/client/QueryParameters.java @@ -22,40 +22,33 @@ import java.util.HashMap; import com.google.gwt.http.client.URL; -public class QueryParameters -{ +public class QueryParameters { private HashMap map = new HashMap(); - public QueryParameters() - { - String search = getQueryString(); - if ((search != null) && (search.length() > 0)) - { - String[] nameValues = search.substring(1).split("&"); - for (int i = 0; i < nameValues.length; i++) - { - String[] pair = nameValues[i].split("="); - - map.put(pair[0], URL.decode(pair[1])); - } - } + public QueryParameters() { + String search = getQueryString(); + if ((search != null) && (search.length() > 0)) { + String[] nameValues = search.substring(1).split("&"); + for (int i = 0; i < nameValues.length; i++) { + String[] pair = nameValues[i].split("="); + + map.put(pair[0], URL.decode(pair[1])); + } + } } - - public String getValue(String key) - { - return (String) map.get(key); + + public String getValue(String key) { + return (String) map.get(key); } - - - public boolean getBooleanValue(String key, boolean def){ - String val=getValue(key); - if (val==null) - return def; - else - return (val=="1" || val.equalsIgnoreCase("true")); + public boolean getBooleanValue(String key, boolean def) { + String val = getValue(key); + if (val == null) + return def; + else + return (val == "1" || val.equalsIgnoreCase("true")); } - + private native String getQueryString() /*-{ return $wnd.location.search; diff --git a/src/com/lushprojects/circuitjs1/client/RailElm.java b/src/com/lushprojects/circuitjs1/client/RailElm.java index 66470364..a64f87f1 100644 --- a/src/com/lushprojects/circuitjs1/client/RailElm.java +++ b/src/com/lushprojects/circuitjs1/client/RailElm.java @@ -20,39 +20,44 @@ package com.lushprojects.circuitjs1.client; class RailElm extends VoltageElm { - public RailElm(int xx, int yy) { - super(xx, yy, WF_DC); + public RailElm(int xx, int yy) { + super(xx, yy, WF_DC); - } - RailElm(int xx, int yy, int wf) { - super(xx, yy, wf); - } + } - public RailElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - } + RailElm(int xx, int yy, int wf) { + super(xx, yy, wf); + } + + public RailElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + } - final int FLAG_CLOCK = 1; - int getDumpType() { return 'R'; } - int getPostCount() { return 1; } - + + int getDumpType() { + return 'R'; + } + + int getPostCount() { + return 1; + } + void setPoints() { super.setPoints(); - lead1 = interpPoint(point1, point2, 1-circleSize/dn); + lead1 = interpPoint(point1, point2, 1 - circleSize / dn); } - + String getRailText() { return null; } - + void draw(Graphics g) { String rt = getRailText(); - double w = rt == null ? circleSize : g.context.measureText(rt).getWidth()/2; - if (w > dn*.8) - w = dn*.8; - lead1 = interpPoint(point1, point2, 1-w/dn); + double w = rt == null ? circleSize : g.context.measureText(rt).getWidth() / 2; + if (w > dn * .8) + w = dn * .8; + lead1 = interpPoint(point1, point2, 1 - w / dn); setBbox(point1, point2, circleSize); setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); @@ -72,9 +77,9 @@ else if (waveform == WF_DC || waveform == WF_VAR) { double v = getVoltage(); String s; if (Math.abs(v) < 1) - s = showFormat.format(v)+" V"; + s = showFormat.format(v) + " V"; else - s = getShortUnitText(v, "V"); + s = getShortUnitText(v, "V"); if (getVoltage() > 0) s = "+" + s; drawLabeledNode(g, s, point1, lead1); @@ -82,30 +87,40 @@ else if (waveform == WF_DC || waveform == WF_VAR) { drawWaveform(g, point2); } } - + void drawRailText(Graphics g, String s) { g.setColor(needsHighlight() ? selectColor : whiteColor); setPowerColor(g, false); drawLabeledNode(g, s, point1, lead1); } - - double getVoltageDiff() { return volts[0]; } + + double getVoltageDiff() { + return volts[0]; + } + void stamp() { if (waveform == WF_DC) sim.stampVoltageSource(0, nodes[0], voltSource, getVoltage()); else sim.stampVoltageSource(0, nodes[0], voltSource); } + void doStep() { if (waveform != WF_DC) sim.updateVoltageSource(0, nodes[0], voltSource, getVoltage()); } - boolean hasGroundConnection(int n1) { return true; } - int getShortcut() { return 'V'; } - -// void drawHandles(Graphics g, Color c) { -// g.setColor(c); -// g.fillRect(x-3, y-3, 7, 7); -// } - + + boolean hasGroundConnection(int n1) { + return true; + } + + int getShortcut() { + return 'V'; + } + + // void drawHandles(Graphics g, Color c) { + // g.setColor(c); + // g.fillRect(x-3, y-3, 7, 7); + // } + } diff --git a/src/com/lushprojects/circuitjs1/client/Rectangle.java b/src/com/lushprojects/circuitjs1/client/Rectangle.java index 94109d03..7fb7dacc 100644 --- a/src/com/lushprojects/circuitjs1/client/Rectangle.java +++ b/src/com/lushprojects/circuitjs1/client/Rectangle.java @@ -19,148 +19,145 @@ // Via http://grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/awt/Rectangle.java/?v=source public class Rectangle { - int x; - int y; - int width; - int height; - - public Rectangle(){ - x=0; - y=0; - width=0; - height=0; - } - + int x; + int y; + int width; + int height; + + public Rectangle() { + x = 0; + y = 0; + width = 0; + height = 0; + } + public Rectangle(int x, int y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; + this.x = x; + this.y = y; + this.width = width; + this.height = height; } - + public Rectangle(Point pt) { this.x = pt.x; this.y = pt.y; this.width = 0; this.height = 0; } - + public Rectangle(Rectangle r) { - this(r.x, r.y, r.width, r.height); + this(r.x, r.y, r.width, r.height); } - + public void setBounds(int x, int y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; + this.x = x; + this.y = y; + this.width = width; + this.height = height; } - + public void translate(int dx, int dy) { - x += dx; - y += dy; + x += dx; + y += dy; } - + public boolean contains(int X, int Y) { - int w = this.width; - int h = this.height; - if ((w | h) < 0) { - // At least one of the dimensions is negative... - return false; - } - // Note: if either dimension is zero, tests below must return false... - int x = this.x; - int y = this.y; - if (X < x || Y < y) { - return false; - } - w += x; - h += y; - // overflow || intersect - return ((w < x || w > X) && - (h < y || h > Y)); + int w = this.width; + int h = this.height; + if ((w | h) < 0) { + // At least one of the dimensions is negative... + return false; + } + // Note: if either dimension is zero, tests below must return false... + int x = this.x; + int y = this.y; + if (X < x || Y < y) { + return false; + } + w += x; + h += y; + // overflow || intersect + return ((w < x || w > X) && (h < y || h > Y)); } - + /* - public void move(int x, int y) { - this.x = x; - this.y = y; - } - */ - + * public void move(int x, int y) { this.x = x; this.y = y; } + */ + public boolean intersects(Rectangle r) { - int tw = this.width; - int th = this.height; - int rw = r.width; - int rh = r.height; - if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) { - return false; - } - int tx = this.x; - int ty = this.y; - int rx = r.x; - int ry = r.y; - rw += rx; - rh += ry; - tw += tx; - th += ty; - // overflow || intersect - return ((rw < rx || rw > tx) && - (rh < ry || rh > ty) && - (tw < tx || tw > rx) && - (th < ty || th > ry)); + int tw = this.width; + int th = this.height; + int rw = r.width; + int rh = r.height; + if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) { + return false; + } + int tx = this.x; + int ty = this.y; + int rx = r.x; + int ry = r.y; + rw += rx; + rh += ry; + tw += tx; + th += ty; + // overflow || intersect + return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry)); } - + public Rectangle union(Rectangle r) { - long tx2 = this.width; - long ty2 = this.height; - if ((tx2 | ty2) < 0) { - // This rectangle has negative dimensions... - // If r has non-negative dimensions then it is the answer. - // If r is non-existant (has a negative dimension), then both - // are non-existant and we can return any non-existant rectangle - // as an answer. Thus, returning r meets that criterion. - // Either way, r is our answer. - return new Rectangle(r); - } - long rx2 = r.width; - long ry2 = r.height; - if ((rx2 | ry2) < 0) { - return new Rectangle(this); - } - int tx1 = this.x; - int ty1 = this.y; - tx2 += tx1; - ty2 += ty1; - int rx1 = r.x; - int ry1 = r.y; - rx2 += rx1; - ry2 += ry1; - if (tx1 > rx1) tx1 = rx1; - if (ty1 > ry1) ty1 = ry1; - if (tx2 < rx2) tx2 = rx2; - if (ty2 < ry2) ty2 = ry2; - tx2 -= tx1; - ty2 -= ty1; - // tx2,ty2 will never underflow since both original rectangles - // were already proven to be non-empty - // they might overflow, though... - if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE; - if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE; - return new Rectangle(tx1, ty1, (int) tx2, (int) ty2); + long tx2 = this.width; + long ty2 = this.height; + if ((tx2 | ty2) < 0) { + // This rectangle has negative dimensions... + // If r has non-negative dimensions then it is the answer. + // If r is non-existant (has a negative dimension), then both + // are non-existant and we can return any non-existant rectangle + // as an answer. Thus, returning r meets that criterion. + // Either way, r is our answer. + return new Rectangle(r); + } + long rx2 = r.width; + long ry2 = r.height; + if ((rx2 | ry2) < 0) { + return new Rectangle(this); + } + int tx1 = this.x; + int ty1 = this.y; + tx2 += tx1; + ty2 += ty1; + int rx1 = r.x; + int ry1 = r.y; + rx2 += rx1; + ry2 += ry1; + if (tx1 > rx1) + tx1 = rx1; + if (ty1 > ry1) + ty1 = ry1; + if (tx2 < rx2) + tx2 = rx2; + if (ty2 < ry2) + ty2 = ry2; + tx2 -= tx1; + ty2 -= ty1; + // tx2,ty2 will never underflow since both original rectangles + // were already proven to be non-empty + // they might overflow, though... + if (tx2 > Integer.MAX_VALUE) + tx2 = Integer.MAX_VALUE; + if (ty2 > Integer.MAX_VALUE) + ty2 = Integer.MAX_VALUE; + return new Rectangle(tx1, ty1, (int) tx2, (int) ty2); + } + + public String toString() { + return "Rect(" + x + "," + y + "," + width + "," + height + ")"; } - - public String toString() { return "Rect(" + x + "," + y + "," + width + "," + height + ")"; } - public boolean equals(Object obj) { - if (obj instanceof Rectangle) { - Rectangle r = (Rectangle)obj; - return ((x == r.x) && - (y == r.y) && - (width == r.width) && - (height == r.height)); - } - return super.equals(obj); + if (obj instanceof Rectangle) { + Rectangle r = (Rectangle) obj; + return ((x == r.x) && (y == r.y) && (width == r.width) && (height == r.height)); + } + return super.equals(obj); } } \ No newline at end of file diff --git a/src/com/lushprojects/circuitjs1/client/RelayElm.java b/src/com/lushprojects/circuitjs1/client/RelayElm.java index a9834bfa..18279402 100644 --- a/src/com/lushprojects/circuitjs1/client/RelayElm.java +++ b/src/com/lushprojects/circuitjs1/client/RelayElm.java @@ -31,10 +31,10 @@ // 3n+2 = end of coil resistor class RelayElm extends CircuitElm { - final int FLAG_SWAP_COIL = 1; - final int FLAG_SHOW_BOX = 2; - final int FLAG_BOTH_SIDES_COIL = 4; - + final int FLAG_SWAP_COIL = 1; + final int FLAG_SHOW_BOX = 2; + final int FLAG_BOTH_SIDES_COIL = 4; + double inductance; Inductor ind; double r_on, r_off, onCurrent, offCurrent; @@ -42,18 +42,19 @@ class RelayElm extends CircuitElm { Point lines[]; Point outline[] = newPointArray(4); double coilCurrent, switchCurrent[], coilCurCount, switchCurCount[]; - + // fractional position, between 0 and 1 inclusive double d_position; - + // integer position, can be 0 (off), 1 (on), 2 (in between) int i_position; - + double coilR; - - // time to switch in seconds, or 0 for old model where switching time was not constant + + // time to switch in seconds, or 0 for old model where switching time was not + // constant double switchingTime; - + int poleCount; int openhs; boolean onState; @@ -62,7 +63,7 @@ class RelayElm extends CircuitElm { final int nSwitch2 = 2; int nCoil1, nCoil2, nCoil3; double currentOffset1, currentOffset2; - + public RelayElm(int xx, int yy) { super(xx, yy); ind = new Inductor(sim); @@ -80,23 +81,24 @@ public RelayElm(int xx, int yy) { flags |= FLAG_SHOW_BOX | FLAG_BOTH_SIDES_COIL; setupPoles(); } - public RelayElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public RelayElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - poleCount = new Integer(st.nextToken()).intValue(); - inductance = new Double(st.nextToken()).doubleValue(); - coilCurrent = new Double(st.nextToken()).doubleValue(); - r_on = new Double(st.nextToken()).doubleValue(); - r_off = new Double(st.nextToken()).doubleValue(); - onCurrent = new Double(st.nextToken()).doubleValue(); - coilR = new Double(st.nextToken()).doubleValue(); + poleCount = Integer.valueOf(st.nextToken()).intValue(); + inductance = Double.valueOf(st.nextToken()).doubleValue(); + coilCurrent = Double.valueOf(st.nextToken()).doubleValue(); + r_on = Double.valueOf(st.nextToken()).doubleValue(); + r_off = Double.valueOf(st.nextToken()).doubleValue(); + onCurrent = Double.valueOf(st.nextToken()).doubleValue(); + coilR = Double.valueOf(st.nextToken()).doubleValue(); try { offCurrent = onCurrent; switchingTime = 0; - offCurrent = new Double(st.nextToken()).doubleValue(); + offCurrent = Double.valueOf(st.nextToken()).doubleValue(); switchingTime = Double.parseDouble(st.nextToken()); d_position = i_position = Integer.parseInt(st.nextToken()); - } catch (Exception e) {} + } catch (Exception e) { + } if (i_position == 1) onState = true; // intermediate state? @@ -106,110 +108,106 @@ public RelayElm(int xa, int ya, int xb, int yb, int f, ind = new Inductor(sim); ind.setup(inductance, coilCurrent, Inductor.FLAG_BACK_EULER); setupPoles(); - allocNodes(); + allocNodes(); } - + void setupPoles() { - nCoil1 = 3*poleCount; - nCoil2 = nCoil1+1; - nCoil3 = nCoil1+2; + nCoil1 = 3 * poleCount; + nCoil2 = nCoil1 + 1; + nCoil3 = nCoil1 + 2; if (switchCurrent == null || switchCurrent.length != poleCount) { switchCurrent = new double[poleCount]; switchCurCount = new double[poleCount]; } } - - int getDumpType() { return 178; } - + + int getDumpType() { + return 178; + } + String dump() { - return super.dump() + " " + poleCount + " " + - inductance + " " + coilCurrent + " " + - r_on + " " + r_off + " " + onCurrent + " " + coilR + " " + offCurrent + " " + switchingTime + " " + i_position; + return super.dump() + " " + poleCount + " " + inductance + " " + coilCurrent + " " + r_on + " " + r_off + " " + + onCurrent + " " + coilR + " " + offCurrent + " " + switchingTime + " " + i_position; } - + void draw(Graphics g) { int i, p; for (i = 0; i != 2; i++) { - setVoltageColor(g, volts[nCoil1+i]); + setVoltageColor(g, volts[nCoil1 + i]); drawThickLine(g, coilLeads[i], coilPosts[i]); } int x = ((flags & FLAG_SWAP_COIL) != 0) ? 1 : 0; - setPowerColor(g, coilCurrent * (volts[nCoil1]-volts[nCoil2])); - drawCoil(g, dsign*6, coilLeads[x], coilLeads[1-x], - volts[nCoil1+x], volts[nCoil2-x]); + setPowerColor(g, coilCurrent * (volts[nCoil1] - volts[nCoil2])); + drawCoil(g, dsign * 6, coilLeads[x], coilLeads[1 - x], volts[nCoil1 + x], volts[nCoil2 - x]); // draw rectangle if ((flags & FLAG_SHOW_BOX) != 0) { - g.setColor(needsHighlight() ? selectColor : lightGrayColor); - drawThickLine(g, outline[0], outline[1]); - drawThickLine(g, outline[1], outline[2]); - drawThickLine(g, outline[2], outline[3]); - drawThickLine(g, outline[3], outline[0]); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickLine(g, outline[0], outline[1]); + drawThickLine(g, outline[1], outline[2]); + drawThickLine(g, outline[2], outline[3]); + drawThickLine(g, outline[3], outline[0]); } - + // draw lines g.setColor(Color.darkGray); for (i = 0; i != poleCount; i++) { if (i == 0) { int off = ((flags & FLAG_BOTH_SIDES_COIL) == 0) ? 0 : 4; - interpPoint(point1, point2, lines[i*2 ], .5, - openhs*2+5*dsign-i*openhs*3+off); + interpPoint(point1, point2, lines[i * 2], .5, openhs * 2 + 5 * dsign - i * openhs * 3 + off); } else - interpPoint(point1, point2, lines[i*2], .5, - (int) (openhs*(-i*3+3-.5+d_position))+5*dsign); - interpPoint(point1, point2, lines[i*2+1], .5, - (int) (openhs*(-i*3-.5+d_position))-5*dsign); + interpPoint(point1, point2, lines[i * 2], .5, + (int) (openhs * (-i * 3 + 3 - .5 + d_position)) + 5 * dsign); + interpPoint(point1, point2, lines[i * 2 + 1], .5, (int) (openhs * (-i * 3 - .5 + d_position)) - 5 * dsign); g.setLineDash(4, 4); - g.drawLine(lines[i*2].x, lines[i*2].y, lines[i*2+1].x, lines[i*2+1].y); - g.setLineDash(0, 0); + g.drawLine(lines[i * 2].x, lines[i * 2].y, lines[i * 2 + 1].x, lines[i * 2 + 1].y); + g.setLineDash(0, 0); } - + for (p = 0; p != poleCount; p++) { - int po = p*3; + int po = p * 3; for (i = 0; i != 3; i++) { // draw lead - setVoltageColor(g, volts[nSwitch0+po+i]); + setVoltageColor(g, volts[nSwitch0 + po + i]); drawThickLine(g, swposts[p][i], swpoles[p][i]); } - + interpPoint(swpoles[p][1], swpoles[p][2], ptSwitch[p], d_position); - //setVoltageColor(g, volts[nSwitch0]); + // setVoltageColor(g, volts[nSwitch0]); g.setColor(Color.lightGray); drawThickLine(g, swpoles[p][0], ptSwitch[p]); - switchCurCount[p] = updateDotCount(switchCurrent[p], - switchCurCount[p]); + switchCurCount[p] = updateDotCount(switchCurrent[p], switchCurCount[p]); drawDots(g, swposts[p][0], swpoles[p][0], switchCurCount[p]); - + if (i_position != 2) - drawDots(g, swpoles[p][i_position+1], swposts[p][i_position+1], - switchCurCount[p]); + drawDots(g, swpoles[p][i_position + 1], swposts[p][i_position + 1], switchCurCount[p]); } - + coilCurCount = updateDotCount(coilCurrent, coilCurCount); - + if (coilCurCount != 0) { drawDots(g, coilPosts[0], coilLeads[0], coilCurCount); - drawDots(g, coilLeads[0], coilLeads[1], coilCurCount+currentOffset1); - drawDots(g, coilLeads[1], coilPosts[1], coilCurCount+currentOffset2); + drawDots(g, coilLeads[0], coilLeads[1], coilCurCount + currentOffset1); + drawDots(g, coilLeads[1], coilPosts[1], coilCurCount + currentOffset2); } - + drawPosts(g); setBbox(outline[0], outline[2], 0); adjustBbox(coilPosts[0], coilPosts[1]); adjustBbox(swposts[0][0], swposts[0][1]); } - + double getCurrentIntoNode(int n) { - if (n < 3*poleCount) { - int p = n/3; - int k = n%3; + if (n < 3 * poleCount) { + int p = n / 3; + int k = n % 3; if (k == 0) return -switchCurrent[p]; - if (k == 1+i_position) + if (k == 1 + i_position) return switchCurrent[p]; return 0; } - if (n == 3*poleCount) + if (n == 3 * poleCount) return -coilCurrent; return coilCurrent; } @@ -218,7 +216,7 @@ void setPoints() { super.setPoints(); setupPoles(); allocNodes(); - openhs = -dsign*16; + openhs = -dsign * 16; // switch calcLeads(32); @@ -230,56 +228,63 @@ void setPoints() { swposts[i][j] = new Point(); swpoles[i][j] = new Point(); } - interpPoint(lead1, lead2, swpoles[i][0], 0, -openhs*3*i); - interpPoint(lead1, lead2, swpoles[i][1], 1, -openhs*3*i-openhs); - interpPoint(lead1, lead2, swpoles[i][2], 1, -openhs*3*i+openhs); - interpPoint(point1, point2, swposts[i][0], 0, -openhs*3*i); - interpPoint(point1, point2, swposts[i][1], 1, -openhs*3*i-openhs); - interpPoint(point1, point2, swposts[i][2], 1, -openhs*3*i+openhs); + interpPoint(lead1, lead2, swpoles[i][0], 0, -openhs * 3 * i); + interpPoint(lead1, lead2, swpoles[i][1], 1, -openhs * 3 * i - openhs); + interpPoint(lead1, lead2, swpoles[i][2], 1, -openhs * 3 * i + openhs); + interpPoint(point1, point2, swposts[i][0], 0, -openhs * 3 * i); + interpPoint(point1, point2, swposts[i][1], 1, -openhs * 3 * i - openhs); + interpPoint(point1, point2, swposts[i][2], 1, -openhs * 3 * i + openhs); } // coil coilPosts = newPointArray(2); - coilLeads = newPointArray(2); + coilLeads = newPointArray(2); ptSwitch = newPointArray(poleCount); int x = ((flags & FLAG_SWAP_COIL) != 0) ? 1 : 0; int boxSize; if ((flags & FLAG_BOTH_SIDES_COIL) == 0) { - interpPoint(point1, point2, coilPosts[0], x, openhs*2); - interpPoint(point1, point2, coilPosts[1], x, openhs*3); - interpPoint(point1, point2, coilLeads[0], .5, openhs*2); - interpPoint(point1, point2, coilLeads[1], .5, openhs*3); + interpPoint(point1, point2, coilPosts[0], x, openhs * 2); + interpPoint(point1, point2, coilPosts[1], x, openhs * 3); + interpPoint(point1, point2, coilLeads[0], .5, openhs * 2); + interpPoint(point1, point2, coilLeads[1], .5, openhs * 3); boxSize = 56; } else { - interpPoint(point1, point2, coilPosts[0], 0, openhs*2); - interpPoint(point1, point2, coilPosts[1], 1, openhs*2); - interpPoint(point1, point2, coilLeads[0], .5-16/dn, openhs*2); - interpPoint(point1, point2, coilLeads[1], .5+16/dn, openhs*2); + interpPoint(point1, point2, coilPosts[0], 0, openhs * 2); + interpPoint(point1, point2, coilPosts[1], 1, openhs * 2); + interpPoint(point1, point2, coilLeads[0], .5 - 16 / dn, openhs * 2); + interpPoint(point1, point2, coilLeads[1], .5 + 16 / dn, openhs * 2); boxSize = 40; } // lines - lines = newPointArray(poleCount*2); - + lines = newPointArray(poleCount * 2); + // outline double boxWScale = Math.min(0.4, 25.0 / dn); interpPoint(point1, point2, outline[0], 0.5 - boxWScale, -boxSize * dsign); interpPoint(point1, point2, outline[1], 0.5 + boxWScale, -boxSize * dsign); - interpPoint(point1, point2, outline[2], 0.5 + boxWScale, -(openhs*3*poleCount) - (24.0 * dsign)); - interpPoint(point1, point2, outline[3], 0.5 - boxWScale, -(openhs*3*poleCount) - (24.0 * dsign)); - + interpPoint(point1, point2, outline[2], 0.5 + boxWScale, -(openhs * 3 * poleCount) - (24.0 * dsign)); + interpPoint(point1, point2, outline[3], 0.5 - boxWScale, -(openhs * 3 * poleCount) - (24.0 * dsign)); + currentOffset1 = distance(coilPosts[0], coilLeads[0]); currentOffset2 = currentOffset1 + distance(coilLeads[0], coilLeads[1]); } - + Point getPost(int n) { - if (n < 3*poleCount) + if (n < 3 * poleCount) return swposts[n / 3][n % 3]; - return coilPosts[n-3*poleCount]; + return coilPosts[n - 3 * poleCount]; + } + + int getPostCount() { + return 2 + poleCount * 3; + } + + int getInternalNodeCount() { + return 1; } - int getPostCount() { return 2+poleCount*3; } - int getInternalNodeCount() { return 1; } + void reset() { super.reset(); ind.reset(); @@ -289,10 +294,13 @@ void reset() { switchCurrent[i] = switchCurCount[i] = 0; d_position = i_position = 0; - // preserve onState because if we don't, Relay Flip-Flop gets left in a weird state on reset. + // preserve onState because if we don't, Relay Flip-Flop gets left in a weird + // state on reset. // onState = false; } + double a1, a2, a3, a4; + void stamp() { // inductor from coil post 1 to internal node ind.stamp(nodes[nCoil1], nodes[nCoil3]); @@ -300,54 +308,55 @@ void stamp() { sim.stampResistor(nodes[nCoil3], nodes[nCoil2], coilR); int i; - for (i = 0; i != poleCount*3; i++) - sim.stampNonLinear(nodes[nSwitch0+i]); + for (i = 0; i != poleCount * 3; i++) + sim.stampNonLinear(nodes[nSwitch0 + i]); } - + void startIteration() { // using old model? if (switchingTime == 0) { startIterationOld(); return; } - ind.startIteration(volts[nCoil1]-volts[nCoil3]); + ind.startIteration(volts[nCoil1] - volts[nCoil3]); double absCurrent = Math.abs(coilCurrent); - + if (onState) { - // on or turning on. check if we need to turn off + // on or turning on. check if we need to turn off if (absCurrent < offCurrent) { // turning off, set switch to intermediate position onState = false; i_position = 2; } else { - d_position += sim.timeStep/switchingTime; + d_position += sim.timeStep / switchingTime; if (d_position >= 1) d_position = i_position = 1; } } else { - // off or turning off. check if we need to turn on + // off or turning off. check if we need to turn on if (absCurrent > onCurrent) { // turning on, set switch to intermediate position onState = true; i_position = 2; } else { - d_position -= sim.timeStep/switchingTime; + d_position -= sim.timeStep / switchingTime; if (d_position <= 0) d_position = i_position = 0; } - + } } - + void startIterationOld() { - ind.startIteration(volts[nCoil1]-volts[nCoil3]); + ind.startIteration(volts[nCoil1] - volts[nCoil3]); - // magic value to balance operate speed with reset speed not at all realistically + // magic value to balance operate speed with reset speed not at all + // realistically double magic = 1.3; - double pmult = Math.sqrt(magic+1); + double pmult = Math.sqrt(magic + 1); double c = onCurrent; - double p = coilCurrent*pmult/c; - d_position = Math.abs(p*p) - 1.3; + double p = coilCurrent * pmult / c; + d_position = Math.abs(p * p) - 1.3; if (d_position < 0) d_position = 0; if (d_position > 1) @@ -358,25 +367,26 @@ else if (d_position > .9) i_position = 1; else i_position = 2; - //System.out.println("ind " + this + " " + current + " " + voltdiff); + // System.out.println("ind " + this + " " + current + " " + voltdiff); } - + // we need this to be able to change the matrix for each step - boolean nonLinear() { return true; } + boolean nonLinear() { + return true; + } void doStep() { - double voltdiff = volts[nCoil1]-volts[nCoil3]; + double voltdiff = volts[nCoil1] - volts[nCoil3]; ind.doStep(voltdiff); int p; - for (p = 0; p != poleCount*3; p += 3) { - sim.stampResistor(nodes[nSwitch0+p], nodes[nSwitch1+p], - i_position == 0 ? r_on : r_off); - sim.stampResistor(nodes[nSwitch0+p], nodes[nSwitch2+p], - i_position == 1 ? r_on : r_off); + for (p = 0; p != poleCount * 3; p += 3) { + sim.stampResistor(nodes[nSwitch0 + p], nodes[nSwitch1 + p], i_position == 0 ? r_on : r_off); + sim.stampResistor(nodes[nSwitch0 + p], nodes[nSwitch2 + p], i_position == 1 ? r_on : r_off); } } + void calculateCurrent() { - double voltdiff = volts[nCoil1]-volts[nCoil3]; + double voltdiff = volts[nCoil1] - volts[nCoil3]; coilCurrent = ind.calculateCurrent(voltdiff); // actually this isn't correct, since there is a small amount @@ -386,10 +396,10 @@ void calculateCurrent() { if (i_position == 2) switchCurrent[p] = 0; else - switchCurrent[p] = - (volts[nSwitch0+p*3]-volts[nSwitch1+p*3+i_position])/r_on; + switchCurrent[p] = (volts[nSwitch0 + p * 3] - volts[nSwitch1 + p * 3 + i_position]) / r_on; } } + void getInfo(String arr[]) { arr[0] = Locale.LS("relay"); if (i_position == 0) @@ -401,11 +411,11 @@ else if (i_position == 1) int i; int ln = 1; for (i = 0; i != poleCount; i++) - arr[ln++] = "I" + (i+1) + " = " + getCurrentDText(switchCurrent[i]); + arr[ln++] = "I" + (i + 1) + " = " + getCurrentDText(switchCurrent[i]); arr[ln++] = Locale.LS("coil I") + " = " + getCurrentDText(coilCurrent); - arr[ln++] = Locale.LS("coil Vd") + " = " + - getVoltageDText(volts[nCoil1] - volts[nCoil2]); + arr[ln++] = Locale.LS("coil Vd") + " = " + getVoltageDText(volts[nCoil1] - volts[nCoil2]); } + public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Inductance (H)", inductance, 0, 0); @@ -419,15 +429,14 @@ public EditInfo getEditInfo(int n) { if (switchingTime == 0) { // still using old model, so hide off current which won't work. // make button to switch to new model - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.button = new Button(Locale.LS("Use New Model")); - return ei; + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.button = new Button(Locale.LS("Use New Model")); + return ei; } return new EditInfo("Off Current (A)", offCurrent, 0, 0); } if (n == 5) - return new EditInfo("Number of Poles", poleCount, 1, 4). - setDimensionless(); + return new EditInfo("Number of Poles", poleCount, 1, 4).setDimensionless(); if (n == 6) return new EditInfo("Coil Resistance (ohms)", coilR, 0, 0); if (n == 7) { @@ -449,13 +458,13 @@ else if ((flags & FLAG_BOTH_SIDES_COIL) != 0) ei.checkbox = new Checkbox("Show Box", (flags & FLAG_SHOW_BOX) != 0); return ei; } - + // show switching time only for new model, since it is meaningless for old one if (n == 9 && switchingTime > 0) return new EditInfo("Switching Time (s)", switchingTime, 0, 0); return null; } - + public void setEditValue(int n, EditInfo ei) { if (n == 0 && ei.value > 0) { inductance = ei.value; @@ -485,7 +494,7 @@ public void setEditValue(int n, EditInfo ei) { if (n == 7) { int style = ei.choice.getSelectedIndex(); final int styles[] = { FLAG_BOTH_SIDES_COIL, 0, FLAG_SWAP_COIL }; - flags &= ~(FLAG_SWAP_COIL|FLAG_BOTH_SIDES_COIL); + flags &= ~(FLAG_SWAP_COIL | FLAG_BOTH_SIDES_COIL); flags |= styles[style]; setPoints(); } @@ -494,11 +503,12 @@ public void setEditValue(int n, EditInfo ei) { if (n == 9 && ei.value > 0) switchingTime = ei.value; } - + boolean getConnection(int n1, int n2) { return (n1 / 3 == n2 / 3); } - - int getShortcut() { return 'R'; } + + int getShortcut() { + return 'R'; + } } - diff --git a/src/com/lushprojects/circuitjs1/client/ResistorElm.java b/src/com/lushprojects/circuitjs1/client/ResistorElm.java index d86aad45..92f59343 100644 --- a/src/com/lushprojects/circuitjs1/client/ResistorElm.java +++ b/src/com/lushprojects/circuitjs1/client/ResistorElm.java @@ -22,100 +22,125 @@ import com.google.gwt.canvas.dom.client.CanvasGradient; import com.lushprojects.circuitjs1.client.util.Locale; - class ResistorElm extends CircuitElm { - double resistance; - public ResistorElm(int xx, int yy) { super(xx, yy); resistance = 1000; } - public ResistorElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f); - resistance = new Double(st.nextToken()).doubleValue(); - } - int getDumpType() { return 'r'; } - String dump() { - return super.dump() + " " + resistance; - } +class ResistorElm extends CircuitElm { + double resistance; - Point ps3, ps4; - void setPoints() { - super.setPoints(); - calcLeads(32); - ps3 = new Point(); - ps4 = new Point(); - } - - void draw(Graphics g) { - int segments = 16; - int i; - int ox = 0; - //int hs = sim.euroResistorCheckItem.getState() ? 6 : 8; - int hs=6; - double v1 = volts[0]; - double v2 = volts[1]; - setBbox(point1, point2, hs); - draw2Leads(g); - - // double segf = 1./segments; - double len = distance(lead1, lead2); - g.context.save(); - g.context.setLineWidth(3.0); - g.context.transform(((double)(lead2.x-lead1.x))/len, ((double)(lead2.y-lead1.y))/len, -((double)(lead2.y-lead1.y))/len,((double)(lead2.x-lead1.x))/len,lead1.x,lead1.y); - if (sim.voltsCheckItem.getState() ) { - CanvasGradient grad = g.context.createLinearGradient(0,0,len,0); - grad.addColorStop(0, getVoltageColor(g,v1).getHexValue()); - grad.addColorStop(1.0, getVoltageColor(g,v2).getHexValue()); - g.context.setStrokeStyle(grad); - } else - setPowerColor(g, true); - if (dn < 30) - hs = 2; - if (!sim.euroResistorCheckItem.getState()) { - g.context.beginPath(); - g.context.moveTo(0,0); - for (i=0;i<4;i++){ - g.context.lineTo((1+4*i)*len/16, hs); - g.context.lineTo((3+4*i)*len/16, -hs); - } - g.context.lineTo(len, 0); - g.context.stroke(); - - } else { - g.context.strokeRect(0, -hs, len, 2.0*hs); - } - g.context.restore(); - if (sim.showValuesCheckItem.getState()) { - String s = getShortUnitText(resistance, ""); - drawValues(g, s, hs+2); + public ResistorElm(int xx, int yy) { + super(xx, yy); + resistance = 1000; + } + + public ResistorElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f); + resistance = Double.valueOf(st.nextToken()).doubleValue(); + } + + int getDumpType() { + return 'r'; + } + + String dump() { + return super.dump() + " " + resistance; + } + + Point ps3, ps4; + + void setPoints() { + super.setPoints(); + calcLeads(32); + ps3 = new Point(); + ps4 = new Point(); + } + + void draw(Graphics g) { + int segments = 16; + int i; + int ox = 0; + // int hs = sim.euroResistorCheckItem.getState() ? 6 : 8; + int hs = 6; + double v1 = volts[0]; + double v2 = volts[1]; + setBbox(point1, point2, hs); + draw2Leads(g); + + // double segf = 1./segments; + double len = distance(lead1, lead2); + g.context.save(); + g.context.setLineWidth(3.0); + g.context.transform(((double) (lead2.x - lead1.x)) / len, ((double) (lead2.y - lead1.y)) / len, + -((double) (lead2.y - lead1.y)) / len, ((double) (lead2.x - lead1.x)) / len, lead1.x, lead1.y); + if (sim.voltsCheckItem.getState()) { + CanvasGradient grad = g.context.createLinearGradient(0, 0, len, 0); + grad.addColorStop(0, getVoltageColor(g, v1).getHexValue()); + grad.addColorStop(1.0, getVoltageColor(g, v2).getHexValue()); + g.context.setStrokeStyle(grad); + } else + setPowerColor(g, true); + if (dn < 30) + hs = 2; + if (!sim.euroResistorCheckItem.getState()) { + g.context.beginPath(); + g.context.moveTo(0, 0); + for (i = 0; i < 4; i++) { + g.context.lineTo((1 + 4 * i) * len / 16, hs); + g.context.lineTo((3 + 4 * i) * len / 16, -hs); } - doDots(g); - drawPosts(g); - } + g.context.lineTo(len, 0); + g.context.stroke(); - void calculateCurrent() { - current = (volts[0]-volts[1])/resistance; - //System.out.print(this + " res current set to " + current + "\n"); - } - void stamp() { - sim.stampResistor(nodes[0], nodes[1], resistance); - } - void getInfo(String arr[]) { - arr[0] = "resistor"; - getBasicInfo(arr); - arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); - arr[4] = "P = " + getUnitText(getPower(), "W"); - } - @Override String getScopeText(int v) { - return Locale.LS("resistor") + ", " + getUnitText(resistance, Locale.ohmString); + } else { + g.context.strokeRect(0, -hs, len, 2.0 * hs); } - public EditInfo getEditInfo(int n) { - // ohmString doesn't work here on linux - if (n == 0) - return new EditInfo("Resistance (ohms)", resistance, 0, 0); - return null; + g.context.restore(); + if (sim.showValuesCheckItem.getState()) { + String s = getShortUnitText(resistance, ""); + drawValues(g, s, hs + 2); } - public void setEditValue(int n, EditInfo ei) { - resistance = (ei.value <= 0) ? 1e-9 : ei.value; - } - int getShortcut() { return 'r'; } - double getResistance() { return resistance; } - void setResistance(double r) { resistance = r; } + doDots(g); + drawPosts(g); + } + + void calculateCurrent() { + current = (volts[0] - volts[1]) / resistance; + // System.out.print(this + " res current set to " + current + "\n"); + } + + void stamp() { + sim.stampResistor(nodes[0], nodes[1], resistance); + } + + void getInfo(String arr[]) { + arr[0] = "resistor"; + getBasicInfo(arr); + arr[3] = "R = " + getUnitText(resistance, Locale.ohmString); + arr[4] = "P = " + getUnitText(getPower(), "W"); + } + + @Override + String getScopeText(int v) { + return Locale.LS("resistor") + ", " + getUnitText(resistance, Locale.ohmString); + } + + public EditInfo getEditInfo(int n) { + // ohmString doesn't work here on linux + if (n == 0) + return new EditInfo("Resistance (ohms)", resistance, 0, 0); + return null; + } + + public void setEditValue(int n, EditInfo ei) { + resistance = (ei.value <= 0) ? 1e-9 : ei.value; + } + + int getShortcut() { + return 'r'; + } + + double getResistance() { + return resistance; + } + + void setResistance(double r) { + resistance = r; } +} diff --git a/src/com/lushprojects/circuitjs1/client/RingCounterElm.java b/src/com/lushprojects/circuitjs1/client/RingCounterElm.java index b8c895d6..d697832d 100644 --- a/src/com/lushprojects/circuitjs1/client/RingCounterElm.java +++ b/src/com/lushprojects/circuitjs1/client/RingCounterElm.java @@ -19,112 +19,139 @@ package com.lushprojects.circuitjs1.client; - class RingCounterElm extends ChipElm { - boolean justLoaded; - final int FLAG_CLOCK_INHIBIT = 2; - final int FLAG_RESET_HIGH = 4; - - public RingCounterElm(int xx, int yy) { - super(xx, yy); - flags |= FLAG_CLOCK_INHIBIT; - setupPins(); +class RingCounterElm extends ChipElm { + boolean justLoaded; + final int FLAG_CLOCK_INHIBIT = 2; + final int FLAG_RESET_HIGH = 4; + + public RingCounterElm(int xx, int yy) { + super(xx, yy); + flags |= FLAG_CLOCK_INHIBIT; + setupPins(); + } + + public RingCounterElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { + super(xa, ya, xb, yb, f, st); + justLoaded = true; + } + + String getChipName() { + return "ring counter"; + } + + boolean needsBits() { + return true; + } + + int defaultBitCount() { + return 10; + } + + boolean hasClockInhibit() { + return (flags & FLAG_CLOCK_INHIBIT) != 0 && bits >= 3; + } + + boolean hasInvertReset() { + return (flags & FLAG_RESET_HIGH) == 0; + } + + int clockInhibit; + + void setupPins() { + sizeX = bits > 2 ? bits : 2; + sizeY = 2; + pins = new Pin[getPostCount()]; + pins[0] = new Pin(1, SIDE_W, ""); + pins[0].clock = true; + pins[1] = new Pin(sizeX - 1, SIDE_S, "R"); + pins[1].lineOver = hasInvertReset(); + int i; + for (i = 0; i != bits; i++) { + int ii = i + 2; + pins[ii] = new Pin(i, SIDE_N, "Q" + i); + pins[ii].output = pins[ii].state = true; } - public RingCounterElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - justLoaded = true; + if (hasClockInhibit()) { + clockInhibit = pins.length - 1; + pins[clockInhibit] = new Pin(1, SIDE_S, "CE"); + pins[clockInhibit].lineOver = true; + } else + clockInhibit = -1; + allocNodes(); + } + + int getPostCount() { + return hasClockInhibit() ? bits + 3 : bits + 2; + } + + int getVoltageSourceCount() { + return bits; + } + + void execute() { + int i; + + // if we just loaded then the volts[] array is likely to be all zeroes, which + // might force us to do a reset, so defer execution until the next iteration + if (justLoaded) { + justLoaded = false; + return; + } + + boolean running = true; + if (hasClockInhibit() && pins[clockInhibit].value) + running = false; + + // find which output is high + for (i = 0; i != bits; i++) + if (pins[i + 2].value) + break; + + if (pins[0].value && !lastClock && running) { + if (i < bits) + pins[i++ + 2].value = false; + i %= bits; + pins[i + 2].value = true; } - String getChipName() { return "ring counter"; } - boolean needsBits() { return true; } - int defaultBitCount() { return 10; } - boolean hasClockInhibit() { return (flags & FLAG_CLOCK_INHIBIT) != 0 && bits >= 3; } - boolean hasInvertReset() { return (flags & FLAG_RESET_HIGH) == 0; } - - int clockInhibit; - - void setupPins() { - sizeX = bits > 2 ? bits : 2; - sizeY = 2; - pins = new Pin[getPostCount()]; - pins[0] = new Pin(1, SIDE_W, ""); - pins[0].clock = true; - pins[1] = new Pin(sizeX-1, SIDE_S, "R"); - pins[1].lineOver = hasInvertReset(); - int i; - for (i = 0; i != bits; i++) { - int ii = i+2; - pins[ii] = new Pin(i, SIDE_N, "Q" + i); - pins[ii].output = pins[ii].state = true; - } - if (hasClockInhibit()) { - clockInhibit = pins.length-1; - pins[clockInhibit] = new Pin(1, SIDE_S, "CE"); - pins[clockInhibit].lineOver = true; - } else - clockInhibit = -1; - allocNodes(); + + // reset if requested, or if all outputs are low + if (pins[1].value != hasInvertReset() || i == bits) { + for (i = 1; i != bits; i++) + pins[i + 2].value = false; + pins[2].value = true; } - int getPostCount() { return hasClockInhibit() ? bits+3 : bits+2; } - int getVoltageSourceCount() { return bits; } - void execute() { - int i; - - // if we just loaded then the volts[] array is likely to be all zeroes, which might force us to do a reset, so defer execution until the next iteration - if (justLoaded) { - justLoaded = false; - return; - } - - boolean running = true; - if (hasClockInhibit() && pins[clockInhibit].value) - running = false; - - // find which output is high - for (i = 0; i != bits; i++) - if (pins[i+2].value) - break; - - if (pins[0].value && !lastClock && running) { - if (i < bits) - pins[i++ +2].value = false; - i %= bits; - pins[i+2].value = true; - } - - // reset if requested, or if all outputs are low - if (pins[1].value != hasInvertReset() || i == bits) { - for (i = 1; i != bits; i++) - pins[i+2].value = false; - pins[2].value = true; - } - lastClock = pins[0].value; + lastClock = pins[0].value; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.checkbox = new Checkbox("Invert reset pin", hasInvertReset()); + return ei; } - public EditInfo getChipEditInfo(int n) { - if (n == 0) { - EditInfo ei = new EditInfo("", 0, -1, -1); - ei.checkbox = new Checkbox("Invert reset pin", hasInvertReset()); - return ei; - } - if (n == 1) - return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); - return null; + if (n == 1) + return new EditInfo("# of Bits", bits, 1, 1).setDimensionless(); + return null; + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0) { + if (ei.checkbox.getState()) + flags &= ~FLAG_RESET_HIGH; + else + flags |= FLAG_RESET_HIGH; + setupPins(); + setPoints(); + return; } - public void setChipEditValue(int n, EditInfo ei) { - if (n == 0) { - if (ei.checkbox.getState()) - flags &= ~FLAG_RESET_HIGH; - else - flags |= FLAG_RESET_HIGH; - setupPins(); - setPoints(); - return; - } - if (n == 1 && ei.value >= 2) { - bits = (int)ei.value; - setupPins(); - setPoints(); - } + if (n == 1 && ei.value >= 2) { + bits = (int) ei.value; + setupPins(); + setPoints(); } - - int getDumpType() { return 163; } } + + int getDumpType() { + return 163; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/RowInfo.java b/src/com/lushprojects/circuitjs1/client/RowInfo.java index d8b589e6..9ff1c862 100644 --- a/src/com/lushprojects/circuitjs1/client/RowInfo.java +++ b/src/com/lushprojects/circuitjs1/client/RowInfo.java @@ -20,13 +20,16 @@ package com.lushprojects.circuitjs1.client; // info about each row/column of the matrix for simplification purposes - class RowInfo { - static final int ROW_NORMAL = 0; // ordinary value - static final int ROW_CONST = 1; // value is constant - int type, mapCol, mapRow; - double value; - boolean rsChanges; // row's right side changes - boolean lsChanges; // row's left side changes - boolean dropRow; // row is not needed in matrix - RowInfo() { type = ROW_NORMAL; } +class RowInfo { + static final int ROW_NORMAL = 0; // ordinary value + static final int ROW_CONST = 1; // value is constant + int type, mapCol, mapRow; + double value; + boolean rsChanges; // row's right side changes + boolean lsChanges; // row's left side changes + boolean dropRow; // row is not needed in matrix + + RowInfo() { + type = ROW_NORMAL; } +} diff --git a/src/com/lushprojects/circuitjs1/client/SCRElm.java b/src/com/lushprojects/circuitjs1/client/SCRElm.java index b186aa3a..7b4d30ed 100644 --- a/src/com/lushprojects/circuitjs1/client/SCRElm.java +++ b/src/com/lushprojects/circuitjs1/client/SCRElm.java @@ -33,52 +33,62 @@ class SCRElm extends CircuitElm { final int inode = 3; final int FLAG_GATE_FIX = 1; Diode diode; - + public SCRElm(int xx, int yy) { super(xx, yy); setDefaults(); flags |= FLAG_GATE_FIX; setup(); } - public SCRElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public SCRElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); setDefaults(); try { - lastvac = new Double(st.nextToken()).doubleValue(); - lastvag = new Double(st.nextToken()).doubleValue(); + lastvac = Double.valueOf(st.nextToken()).doubleValue(); + lastvag = Double.valueOf(st.nextToken()).doubleValue(); volts[anode] = 0; volts[cnode] = -lastvac; volts[gnode] = -lastvag; - triggerI = new Double(st.nextToken()).doubleValue(); - holdingI = new Double(st.nextToken()).doubleValue(); - gresistance = new Double(st.nextToken()).doubleValue(); + triggerI = Double.valueOf(st.nextToken()).doubleValue(); + holdingI = Double.valueOf(st.nextToken()).doubleValue(); + gresistance = Double.valueOf(st.nextToken()).doubleValue(); } catch (Exception e) { } setup(); } + void setDefaults() { gresistance = 50; holdingI = .0082; triggerI = .01; } + void setup() { diode = new Diode(sim); diode.setupForDefaultModel(); aresistance = 1; // to avoid divide by zero } - boolean nonLinear() { return true; } + + boolean nonLinear() { + return true; + } + void reset() { volts[anode] = volts[cnode] = volts[gnode] = 0; diode.reset(); lastvag = lastvac = curcount_a = curcount_c = curcount_g = 0; } - int getDumpType() { return 177; } + + int getDumpType() { + return 177; + } + String dump() { - return super.dump() + " " + (volts[anode]-volts[cnode]) + " " + - (volts[anode]-volts[gnode]) + " " + triggerI + " "+ holdingI + " " + - gresistance; + return super.dump() + " " + (volts[anode] - volts[cnode]) + " " + (volts[anode] - volts[gnode]) + " " + triggerI + + " " + holdingI + " " + gresistance; } + double ia, ic, ig, curcount_a, curcount_c, curcount_g; double lastvac, lastvag; double gresistance, triggerI, holdingI; @@ -86,22 +96,25 @@ String dump() { final int hs = 8; Polygon poly; Point cathode[], gate[]; - - boolean applyGateFix() { return (flags & FLAG_GATE_FIX) != 0; } - + + boolean applyGateFix() { + return (flags & FLAG_GATE_FIX) != 0; + } + void setPoints() { super.setPoints(); int dir = 0; if (abs(dx) > abs(dy)) { - dir = -sign(dx)*sign(dy); - - // correct dn (length) or else calcLeads() may get confused, and also gate may be drawn weirdly. Can't do this with old circuits or it may + dir = -sign(dx) * sign(dy); + + // correct dn (length) or else calcLeads() may get confused, and also gate may + // be drawn weirdly. Can't do this with old circuits or it may // break them if (applyGateFix()) dn = abs(dx); point2.y = point1.y; } else { - dir = sign(dy)*sign(dx); + dir = sign(dy) * sign(dx); if (applyGateFix()) dn = abs(dy); point2.x = point1.x; @@ -116,19 +129,20 @@ void setPoints() { poly = createPolygon(pa[0], pa[1], lead2); gate = newPointArray(2); - double leadlen = (dn-16)/2; + double leadlen = (dn - 16) / 2; int gatelen = sim.gridSize; gatelen += leadlen % sim.gridSize; if (leadlen < gatelen) { - x2 = x; y2 = y; + x2 = x; + y2 = y; return; } - interpPoint(lead2, point2, gate[0], gatelen/leadlen, gatelen*dir); - interpPoint(lead2, point2, gate[1], gatelen/leadlen, sim.gridSize*2*dir); + interpPoint(lead2, point2, gate[0], gatelen / leadlen, gatelen * dir); + interpPoint(lead2, point2, gate[1], gatelen / leadlen, sim.gridSize * 2 * dir); gate[1].x = sim.snapGrid(gate[1].x); gate[1].y = sim.snapGrid(gate[1].y); } - + void draw(Graphics g) { setBbox(point1, point2, hs); adjustBbox(gate[0], gate[1]); @@ -144,14 +158,14 @@ void draw(Graphics g) { g.fillPolygon(poly); setVoltageColor(g, volts[gnode]); - drawThickLine(g, lead2, gate[0]); + drawThickLine(g, lead2, gate[0]); drawThickLine(g, gate[0], gate[1]); - + // draw thing arrow is pointing to setVoltageColor(g, v2); setPowerColor(g, true); drawThickLine(g, cathode[0], cathode[1]); - + curcount_a = updateDotCount(ia, curcount_a); curcount_c = updateDotCount(ic, curcount_c); curcount_g = updateDotCount(ig, curcount_g); @@ -159,20 +173,20 @@ void draw(Graphics g) { drawDots(g, point1, lead2, curcount_a); drawDots(g, point2, lead2, curcount_c); drawDots(g, gate[1], gate[0], curcount_g); - drawDots(g, gate[0], lead2, curcount_g+distance(gate[1], gate[0])); + drawDots(g, gate[0], lead2, curcount_g + distance(gate[1], gate[0])); } - + if ((needsHighlight() || sim.dragElm == this) && point1.x == point2.x && point2.y > point1.y) { g.setColor(whiteColor); int ds = sign(dx); - g.drawString("C", lead2.x+((ds < 0) ? 5 : -15), lead2.y+12); - g.drawString("A", lead1.x+5, lead1.y-4); // x+6 if ds=1, -12 if -1 - g.drawString("G", gate[0].x, gate[0].y+12); + g.drawString("C", lead2.x + ((ds < 0) ? 5 : -15), lead2.y + 12); + g.drawString("A", lead1.x + 5, lead1.y - 4); // x+6 if ds=1, -12 if -1 + g.drawString("G", gate[0].x, gate[0].y + 12); } - + drawPosts(g); } - + double getCurrentIntoNode(int n) { if (n == anode) return -ia; @@ -181,18 +195,24 @@ void draw(Graphics g) { return -ig; } - Point getPost(int n) { return (n == 0) ? point1 : (n == 1) ? point2 : gate[1]; } - - int getPostCount() { return 3; } - int getInternalNodeCount() { return 1; } + + int getPostCount() { + return 3; + } + + int getInternalNodeCount() { + return 1; + } + double getPower() { - return (volts[anode]-volts[gnode])*ia + (volts[cnode]-volts[gnode])*ic; + return (volts[anode] - volts[gnode]) * ia + (volts[cnode] - volts[gnode]) * ic; } double aresistance; + void stamp() { sim.stampNonLinear(nodes[anode]); sim.stampNonLinear(nodes[cnode]); @@ -203,38 +223,42 @@ void stamp() { } void doStep() { - double vac = volts[anode]-volts[cnode]; // typically negative - double vag = volts[anode]-volts[gnode]; // typically positive - if (Math.abs(vac-lastvac) > .01 || - Math.abs(vag-lastvag) > .01) + double vac = volts[anode] - volts[cnode]; // typically negative + double vag = volts[anode] - volts[gnode]; // typically positive + if (Math.abs(vac - lastvac) > .01 || Math.abs(vag - lastvag) > .01) sim.converged = false; lastvac = vac; lastvag = vag; - diode.doStep(volts[inode]-volts[cnode]); - double icmult = 1/triggerI; - double iamult = 1/holdingI - icmult; - //System.out.println(icmult + " " + iamult); - aresistance = (-icmult*ic + ia*iamult > 1) ? .0105 : 10e5; - //System.out.println(vac + " " + vag + " " + sim.converged + " " + ic + " " + ia + " " + aresistance + " " + volts[inode] + " " + volts[gnode] + " " + volts[anode]); + diode.doStep(volts[inode] - volts[cnode]); + double icmult = 1 / triggerI; + double iamult = 1 / holdingI - icmult; + // System.out.println(icmult + " " + iamult); + aresistance = (-icmult * ic + ia * iamult > 1) ? .0105 : 10e5; + // System.out.println(vac + " " + vag + " " + sim.converged + " " + ic + " " + + // ia + " " + aresistance + " " + volts[inode] + " " + volts[gnode] + " " + + // volts[anode]); sim.stampResistor(nodes[anode], nodes[inode], aresistance); } + void getInfo(String arr[]) { arr[0] = "SCR"; - double vac = volts[anode]-volts[cnode]; - double vag = volts[anode]-volts[gnode]; - double vgc = volts[gnode]-volts[cnode]; + double vac = volts[anode] - volts[cnode]; + double vag = volts[anode] - volts[gnode]; + double vgc = volts[gnode] - volts[cnode]; arr[1] = "Ia = " + getCurrentText(ia); arr[2] = "Ig = " + getCurrentText(ig); arr[3] = "Vac = " + getVoltageText(vac); arr[4] = "Vag = " + getVoltageText(vag); arr[5] = "Vgc = " + getVoltageText(vgc); - arr[6] = "P = " + getUnitText(getPower(), "W"); + arr[6] = "P = " + getUnitText(getPower(), "W"); } + void calculateCurrent() { - ig = (volts[gnode]-volts[cnode])/gresistance; - ia = (volts[anode]-volts[inode])/aresistance; - ic = -ig-ia; + ig = (volts[gnode] - volts[cnode]) / gresistance; + ia = (volts[anode] - volts[inode]) / aresistance; + ic = -ig - ia; } + public EditInfo getEditInfo(int n) { if (n == 0) return new EditInfo("Trigger Current (A)", triggerI, 0, 0); @@ -244,6 +268,7 @@ public EditInfo getEditInfo(int n) { return new EditInfo("Gate Resistance (ohms)", gresistance, 0, 0); return null; } + public void setEditValue(int n, EditInfo ei) { if (n == 0 && ei.value > 0) triggerI = ei.value; @@ -253,4 +278,3 @@ public void setEditValue(int n, EditInfo ei) { gresistance = ei.value; } } - diff --git a/src/com/lushprojects/circuitjs1/client/SRAMElm.java b/src/com/lushprojects/circuitjs1/client/SRAMElm.java index da6451c8..f836e45c 100644 --- a/src/com/lushprojects/circuitjs1/client/SRAMElm.java +++ b/src/com/lushprojects/circuitjs1/client/SRAMElm.java @@ -24,232 +24,252 @@ import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.TextArea; - class SRAMElm extends ChipElm { - int addressNodes, dataNodes, internalNodes; - int addressBits, dataBits; - HashMap map; - static String contentsOverride = null; - - public SRAMElm(int xx, int yy) { - super(xx, yy); - addressBits = dataBits = 4; - map = new HashMap(); - setupPins(); - } +class SRAMElm extends ChipElm { + int addressNodes, dataNodes, internalNodes; + int addressBits, dataBits; + HashMap map; + static String contentsOverride = null; - public SRAMElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa, ya, xb, yb, f, st); - map = new HashMap(); - addressBits = Integer.parseInt(st.nextToken()); - dataBits = Integer.parseInt(st.nextToken()); - setupPins(); - try { - // load contents - // format: addr val(addr) val(addr+1) val(addr+2) ... -1 addr val val ... -1 ... -2 - while (true) { - int a = Integer.parseInt(st.nextToken()); - if (a < 0) - break; - int v = Integer.parseInt(st.nextToken()); - map.put(a, v); - while (true) { - v = Integer.parseInt(st.nextToken()); - if (v < 0) - break; - map.put(++a, v); - } - } - } catch (Exception e) {} - } + public SRAMElm(int xx, int yy) { + super(xx, yy); + addressBits = dataBits = 4; + map = new HashMap(); + setupPins(); + } - String dump() { - String s = super.dump() + " " + addressBits + " " + dataBits; - - // dump contents - int maxI = 1<(); + addressBits = Integer.parseInt(st.nextToken()); + dataBits = Integer.parseInt(st.nextToken()); + setupPins(); + try { + // load contents + // format: addr val(addr) val(addr+1) val(addr+2) ... -1 addr val val ... -1 ... + // -2 + while (true) { + int a = Integer.parseInt(st.nextToken()); + if (a < 0) + break; + int v = Integer.parseInt(st.nextToken()); + map.put(a, v); while (true) { - val = map.get(++i); - if (val == null) + v = Integer.parseInt(st.nextToken()); + if (v < 0) break; - s += " " + val; + map.put(++a, v); } - s += " -1"; } - s += " -2"; - return s; + } catch (Exception e) { } + } - boolean nonLinear() { return true; } - String getChipName() { return "Static RAM"; } - void setupPins() { - sizeX = 2; - sizeY = max(addressBits, dataBits) + 1; - pins = new Pin[getPostCount()]; - pins[0] = new Pin(0, SIDE_W, "WE"); - pins[0].lineOver = true; - pins[1] = new Pin(0, SIDE_E, "OE"); - pins[1].lineOver = true; - int i; - addressNodes = 2; - dataNodes = 2+addressBits; - internalNodes = 2+addressBits+dataBits; - for (i = 0; i != addressBits; i++) { - int ii = i+addressNodes; - pins[ii] = new Pin(sizeY-addressBits+i, SIDE_W, "A" + (addressBits-i-1)); - } - for (i = 0; i != dataBits; i++) { - int ii = i+dataNodes; - pins[ii] = new Pin(sizeY-dataBits+i, SIDE_E, "D" + (dataBits-i-1)); - pins[ii].output = true; + String dump() { + String s = super.dump() + " " + addressBits + " " + dataBits; + + // dump contents + int maxI = 1 << addressBits; + int i; + for (i = 0; i < maxI; i++) { + Integer val = map.get(i); + if (val == null) + continue; + s += " " + i + " " + val; + while (true) { + val = map.get(++i); + if (val == null) + break; + s += " " + val; } - allocNodes(); - } - int getPostCount() { - return 2 + addressBits + dataBits; + s += " -1"; } - public EditInfo getChipEditInfo(int n) { - if (n == 0) - return new EditInfo("# of Address Bits", addressBits, 1, 1).setDimensionless(); - if (n == 1) - return new EditInfo("# of Data Bits", dataBits, 1, 1).setDimensionless(); - if (n == 2) { - EditInfo ei = new EditInfo("Contents", 0); - ei.textArea = new TextArea(); - ei.textArea.setVisibleLines(5); - String s = ""; - if (contentsOverride != null) { - s = contentsOverride; - contentsOverride = null; - } else { - int i; - int maxI = 1<= 2 && ei.value <= 16) { - addressBits = (int)ei.value; - setupPins(); - setPoints(); - } - if (n == 1 && ei.value >= 2 && ei.value <= 16) { - dataBits = (int)ei.value; - setupPins(); - setPoints(); - } - if (n == 2) { - String s = ei.textArea.getText(); - String lines[] = s.split("\n"); + int getPostCount() { + return 2 + addressBits + dataBits; + } + + public EditInfo getChipEditInfo(int n) { + if (n == 0) + return new EditInfo("# of Address Bits", addressBits, 1, 1).setDimensionless(); + if (n == 1) + return new EditInfo("# of Data Bits", dataBits, 1, 1).setDimensionless(); + if (n == 2) { + EditInfo ei = new EditInfo("Contents", 0); + ei.textArea = new TextArea(); + ei.textArea.setVisibleLines(5); + String s = ""; + if (contentsOverride != null) { + s = contentsOverride; + contentsOverride = null; + } else { int i; - map.clear(); - for (i = 0; i != lines.length; i++) { - try { - String line = lines[i]; - String args[] = line.split(": *"); - int addr = parseNumber(args[0]); - String vals[] = args[1].split(" +"); - int j; - for (j = 0; j != vals.length; j++) { - int val = parseNumber(vals[j]); - map.put(addr++, val); - } - } catch (Exception e) {} + int maxI = 1 << addressBits; + for (i = 0; i < maxI; i++) { + Integer val = map.get(i); + if (val == null) + continue; + s += i + ": " + val; + int ct = 1; + while (true) { + val = map.get(++i); + if (val == null) + break; + s += " " + val; + if (++ct == 8) + break; + } + s += "\n"; + // sim.console("got " + i + " " + s); } } + ei.textArea.setText(s); + return ei; } - int getVoltageSourceCount() { return dataBits; } - int getInternalNodeCount() { return dataBits; } - - int address; - - void stamp() { - int i; - for (i = 0; i != dataBits; i++) { - Pin p = pins[i+dataNodes]; - sim.stampVoltageSource(0, nodes[internalNodes+i], p.voltSource); - sim.stampNonLinear(nodes[internalNodes+i]); - sim.stampNonLinear(nodes[dataNodes+i]); - } + if (n == 3 && SRAMLoadFile.isSupported()) { + EditInfo ei = new EditInfo("", 0, -1, -1); + ei.loadFile = new SRAMLoadFile(); + ei.button = new Button("Load Contents From File"); + ei.newDialog = true; + return ei; } - - void doStep() { - int i; - boolean writeEnabled = volts[0] < getThreshold(); - boolean outputEnabled = (volts[1] < getThreshold()) && !writeEnabled; - - // get address - address = 0; - for (i = 0; i != addressBits; i++) { - address |= (volts[addressNodes+i] > getThreshold()) ? 1<<(addressBits-1-i) : 0; - } - - Integer dataObj = map.get(address); - int data = (dataObj == null) ? 0 : dataObj; - for (i = 0; i != dataBits; i++) { - Pin p = pins[i+dataNodes]; - sim.updateVoltageSource(0, nodes[internalNodes+i], p.voltSource, (data & (1<<(dataBits-1-i))) == 0 ? 0 : 5); - - // stamp resistor from internal voltage source to data pin. - // if output enabled, make it a small resistor. otherwise large. - sim.stampResistor(nodes[internalNodes+i], nodes[dataNodes+i], outputEnabled ? 1 : 1e8); - } + return super.getChipEditInfo(n); + } + + int parseNumber(String str) { + if (str.startsWith("0x")) + return Integer.parseInt(str.substring(2), 16); + if (str.startsWith("0b")) + return Integer.parseInt(str.substring(2), 2); + return Integer.parseInt(str); + } + + public void setChipEditValue(int n, EditInfo ei) { + if (n == 0 && ei.value >= 2 && ei.value <= 16) { + addressBits = (int) ei.value; + setupPins(); + setPoints(); + } + if (n == 1 && ei.value >= 2 && ei.value <= 16) { + dataBits = (int) ei.value; + setupPins(); + setPoints(); } - - void stepFinished() { + if (n == 2) { + String s = ei.textArea.getText(); + String lines[] = s.split("\n"); int i; - int data = 0; - boolean writeEnabled = volts[0] < getThreshold(); - if (!writeEnabled) - return; - - // store data in RAM - for (i = 0; i != dataBits; i++) { - data |= (volts[dataNodes+i] > getThreshold()) ? 1<<(dataBits-1-i) : 0; + map.clear(); + for (i = 0; i != lines.length; i++) { + try { + String line = lines[i]; + String args[] = line.split(": *"); + int addr = parseNumber(args[0]); + String vals[] = args[1].split(" +"); + int j; + for (j = 0; j != vals.length; j++) { + int val = parseNumber(vals[j]); + map.put(addr++, val); + } + } catch (Exception e) { + } } - map.put(address, data); } - int getDumpType() { return 413; } } + + int getVoltageSourceCount() { + return dataBits; + } + + int getInternalNodeCount() { + return dataBits; + } + + int address; + + void stamp() { + int i; + for (i = 0; i != dataBits; i++) { + Pin p = pins[i + dataNodes]; + sim.stampVoltageSource(0, nodes[internalNodes + i], p.voltSource); + sim.stampNonLinear(nodes[internalNodes + i]); + sim.stampNonLinear(nodes[dataNodes + i]); + } + } + + void doStep() { + int i; + boolean writeEnabled = volts[0] < getThreshold(); + boolean outputEnabled = (volts[1] < getThreshold()) && !writeEnabled; + + // get address + address = 0; + for (i = 0; i != addressBits; i++) { + address |= (volts[addressNodes + i] > getThreshold()) ? 1 << (addressBits - 1 - i) : 0; + } + + Integer dataObj = map.get(address); + int data = (dataObj == null) ? 0 : dataObj; + for (i = 0; i != dataBits; i++) { + Pin p = pins[i + dataNodes]; + sim.updateVoltageSource(0, nodes[internalNodes + i], p.voltSource, + (data & (1 << (dataBits - 1 - i))) == 0 ? 0 : 5); + + // stamp resistor from internal voltage source to data pin. + // if output enabled, make it a small resistor. otherwise large. + sim.stampResistor(nodes[internalNodes + i], nodes[dataNodes + i], outputEnabled ? 1 : 1e8); + } + } + + void stepFinished() { + int i; + int data = 0; + boolean writeEnabled = volts[0] < getThreshold(); + if (!writeEnabled) + return; + + // store data in RAM + for (i = 0; i != dataBits; i++) { + data |= (volts[dataNodes + i] > getThreshold()) ? 1 << (dataBits - 1 - i) : 0; + } + map.put(address, data); + } + + int getDumpType() { + return 413; + } +} diff --git a/src/com/lushprojects/circuitjs1/client/SRAMLoadFile.java b/src/com/lushprojects/circuitjs1/client/SRAMLoadFile.java index bdef2bfa..ac23d217 100644 --- a/src/com/lushprojects/circuitjs1/client/SRAMLoadFile.java +++ b/src/com/lushprojects/circuitjs1/client/SRAMLoadFile.java @@ -20,33 +20,33 @@ package com.lushprojects.circuitjs1.client; public class SRAMLoadFile extends EditDialogLoadFile { - - public final native void handle() - /*-{ - var oFiles = $doc.getElementById("EditDialogLoadFileElement").files, - nFiles = oFiles.length; - if (nFiles>=1) { - if (oFiles[0].size >= 128000) { - @com.lushprojects.circuitjs1.client.EditDialogLoadFile::doErrorCallback(Ljava/lang/String;)("Cannot load: That file is too large!"); - return; - } - - var reader = new FileReader(); - reader.onload = function(e) { - var arr = new Uint8Array(reader.result); - var str = "0:"; - for (var i = 0; i < arr.length; i++) - str += " " + arr[i]; - @com.lushprojects.circuitjs1.client.SRAMLoadFile::doLoadCallback(Ljava/lang/String;)(str); - }; - - reader.readAsArrayBuffer(oFiles[0]); - } - }-*/; - - static public void doLoadCallback(String data) { - SRAMElm.contentsOverride = data; - CirSim.editDialog.resetDialog(); - SRAMElm.contentsOverride = null; - } + + public final native void handle() + /*-{ + var oFiles = $doc.getElementById("EditDialogLoadFileElement").files, + nFiles = oFiles.length; + if (nFiles>=1) { + if (oFiles[0].size >= 128000) { + @com.lushprojects.circuitjs1.client.EditDialogLoadFile::doErrorCallback(Ljava/lang/String;)("Cannot load: That file is too large!"); + return; + } + + var reader = new FileReader(); + reader.onload = function(e) { + var arr = new Uint8Array(reader.result); + var str = "0:"; + for (var i = 0; i < arr.length; i++) + str += " " + arr[i]; + @com.lushprojects.circuitjs1.client.SRAMLoadFile::doLoadCallback(Ljava/lang/String;)(str); + }; + + reader.readAsArrayBuffer(oFiles[0]); + } + }-*/; + + static public void doLoadCallback(String data) { + SRAMElm.contentsOverride = data; + CirSim.editDialog.resetDialog(); + SRAMElm.contentsOverride = null; + } } diff --git a/src/com/lushprojects/circuitjs1/client/SchmittElm.java b/src/com/lushprojects/circuitjs1/client/SchmittElm.java index 9b639516..93f2f1be 100644 --- a/src/com/lushprojects/circuitjs1/client/SchmittElm.java +++ b/src/com/lushprojects/circuitjs1/client/SchmittElm.java @@ -21,81 +21,81 @@ // contributed by Edward Calver -class SchmittElm extends InvertingSchmittElm{ - public SchmittElm(int xx, int yy) { - super(xx,yy); - } - public SchmittElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { - super(xa,ya,xb,yb,f,st); - } +class SchmittElm extends InvertingSchmittElm { + public SchmittElm(int xx, int yy) { + super(xx, yy); + } - int getDumpType() { return 182; } - void doStep() { - double v0 = volts[1]; - double out; - if(state) - {//Output is high - if(volts[0]>upperTrigger)//Input voltage high enough to set output high - { - state=false; - out=logicOnLevel; - } - else - { - out=logicOffLevel; - } - } - else - {//Output is low - if(volts[0] dn/2) - ww = (int) (dn/2); - lead1 = interpPoint(point1, point2, .5-ww/dn); - lead2 = interpPoint(point1, point2, .5+(ww-3)/dn); - Point triPoints[] = newPointArray(3); - interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); - triPoints[2] = interpPoint(point1, point2, .5+(ww-5)/dn); - gatePoly = createPolygon(triPoints); - } - void getInfo(String arr[]) { - arr[0] = "Schmitt Trigger~"; // ~ is for localization - } + int getDumpType() { + return 182; + } - @Override double getCurrentIntoNode(int n) { - if (n == 1) - return current; - return 0; + void doStep() { + double v0 = volts[1]; + double out; + if (state) {// Output is high + if (volts[0] > upperTrigger)// Input voltage high enough to set output high + { + state = false; + out = logicOnLevel; + } else { + out = logicOffLevel; + } + } else {// Output is low + if (volts[0] < lowerTrigger)// Input voltage low enough to set output low + { + state = true; + out = logicOffLevel; + } else { + out = logicOnLevel; + } } + double maxStep = slewRate * sim.timeStep * 1e9; + out = Math.max(Math.min(v0 + maxStep, out), v0 - maxStep); + sim.updateVoltageSource(0, nodes[1], voltSource, out); } + + void draw(Graphics g) { + drawPosts(g); + draw2Leads(g); + g.setColor(needsHighlight() ? selectColor : lightGrayColor); + drawThickPolygon(g, gatePoly); + g.setLineWidth(2); + drawPolygon(g, symbolPoly); + g.setLineWidth(1); + ; + curcount = updateDotCount(current, curcount); + drawDots(g, lead2, point2, curcount); + } + + void setPoints() { + super.setPoints(); + int hs = 16; + int ww = 16; + if (ww > dn / 2) + ww = (int) (dn / 2); + lead1 = interpPoint(point1, point2, .5 - ww / dn); + lead2 = interpPoint(point1, point2, .5 + (ww - 3) / dn); + Point triPoints[] = newPointArray(3); + interpPoint2(lead1, lead2, triPoints[0], triPoints[1], 0, hs); + triPoints[2] = interpPoint(point1, point2, .5 + (ww - 5) / dn); + gatePoly = createPolygon(triPoints); + } + + void getInfo(String arr[]) { + arr[0] = "Schmitt Trigger~"; // ~ is for localization + } + + @Override + double getCurrentIntoNode(int n) { + if (n == 1) + return current; + return 0; + } + +} diff --git a/src/com/lushprojects/circuitjs1/client/Scope.java b/src/com/lushprojects/circuitjs1/client/Scope.java index 5fe712e3..ea2b9db6 100644 --- a/src/com/lushprojects/circuitjs1/client/Scope.java +++ b/src/com/lushprojects/circuitjs1/client/Scope.java @@ -40,12 +40,15 @@ class ScopePlot { double lastValue; String color; CircuitElm elm; - // Has a manual scale in "/div" format been put in by the user (as opposed to being - // inferred from a "MaxValue" format or from an automatically calculated scale)? - // Manual scales should be kept to sane values anyway, but this shows if this is a user - // intention we should respect, or if we should try and populate reasonable values from - // the data we have - boolean manScaleSet = false; + // Has a manual scale in "/div" format been put in by the user (as opposed to + // being + // inferred from a "MaxValue" format or from an automatically calculated scale)? + // Manual scales should be kept to sane values anyway, but this shows if this is + // a user + // intention we should respect, or if we should try and populate reasonable + // values from + // the data we have + boolean manScaleSet = false; double manScale = 1.0; // Units per division int manVPosition = 0; // 0 is center of screen. +V_POSITION_STEPS/2 is top of screen double gridMult; @@ -53,79 +56,83 @@ class ScopePlot { boolean acCoupled = false; double acAlpha = 0.9999; // Filter coefficient for AC coupling double acLastOut = 0; // Store y[i-1] term for AC coupling filter - - final static int FLAG_AC=1; - + + final static int FLAG_AC = 1; + ScopePlot(CircuitElm e, int u) { elm = e; units = u; } - + ScopePlot(CircuitElm e, int u, int v, double manS) { elm = e; units = u; value = v; manScale = manS; // ohms can only be positive, so move the v position to the bottom. - // power can be negative for caps and inductors, but still move to the bottom (for backward compatibility) + // power can be negative for caps and inductors, but still move to the bottom + // (for backward compatibility) if (units == Scope.UNITS_OHMS || units == Scope.UNITS_W) - manVPosition = -Scope.V_POSITION_STEPS/2; + manVPosition = -Scope.V_POSITION_STEPS / 2; } int startIndex(int w) { - return ptr + scopePointCount - w; + return ptr + scopePointCount - w; } - + void reset(int spc, int sp, boolean full) { int oldSpc = scopePointCount; scopePointCount = spc; if (scopePlotSpeed != sp) oldSpc = 0; // throw away old data scopePlotSpeed = sp; - // Adjust the time constant of the AC coupled filter in proportion to the number of samples - // we are seeing on the scope (if my maths is right). The constant is empirically determined - acAlpha = 1.0-1.0/(1.15*scopePlotSpeed*scopePointCount); + // Adjust the time constant of the AC coupled filter in proportion to the number + // of samples + // we are seeing on the scope (if my maths is right). The constant is + // empirically determined + acAlpha = 1.0 - 1.0 / (1.15 * scopePlotSpeed * scopePointCount); double oldMin[] = minValues; double oldMax[] = maxValues; - minValues = new double[scopePointCount]; - maxValues = new double[scopePointCount]; - if (oldMin != null && !full) { - // preserve old data if possible - int i; - for (i = 0; i != scopePointCount && i != oldSpc; i++) { - int i1 = (-i) & (scopePointCount-1); - int i2 = (ptr-i) & (oldSpc-1); - minValues[i1] = oldMin[i2]; - maxValues[i1] = oldMax[i2]; - } - } else - lastUpdateTime = CirSim.theSim.t; - ptr = 0; + minValues = new double[scopePointCount]; + maxValues = new double[scopePointCount]; + if (oldMin != null && !full) { + // preserve old data if possible + int i; + for (i = 0; i != scopePointCount && i != oldSpc; i++) { + int i1 = (-i) & (scopePointCount - 1); + int i2 = (ptr - i) & (oldSpc - 1); + minValues[i1] = oldMin[i2]; + maxValues[i1] = oldMax[i2]; + } + } else + lastUpdateTime = CirSim.theSim.t; + ptr = 0; } void timeStep() { if (elm == null) - return; + return; double v = elm.getScopeValue(value); - // AC coupling filter. 1st order IIR high pass - // y[i] = alpha x (y[i-1]+x[i]-x[i-1]) - // We calculate for all iterations (even DC coupled) to prime the data in case they switch to AC later - double newAcOut=acAlpha*(acLastOut+v-lastValue); + // AC coupling filter. 1st order IIR high pass + // y[i] = alpha x (y[i-1]+x[i]-x[i-1]) + // We calculate for all iterations (even DC coupled) to prime the data in case + // they switch to AC later + double newAcOut = acAlpha * (acLastOut + v - lastValue); lastValue = v; acLastOut = newAcOut; if (isAcCoupled()) v = newAcOut; if (v < minValues[ptr]) - minValues[ptr] = v; + minValues[ptr] = v; if (v > maxValues[ptr]) - maxValues[ptr] = v; - if (CirSim.theSim.t-lastUpdateTime >= CirSim.theSim.maxTimeStep * scopePlotSpeed) { - ptr = (ptr+1) & (scopePointCount-1); + maxValues[ptr] = v; + if (CirSim.theSim.t - lastUpdateTime >= CirSim.theSim.maxTimeStep * scopePlotSpeed) { + ptr = (ptr + 1) & (scopePointCount - 1); minValues[ptr] = maxValues[ptr] = v; lastUpdateTime += CirSim.theSim.maxTimeStep * scopePlotSpeed; } } - + String getUnitText(double v) { switch (units) { case Scope.UNITS_V: @@ -140,14 +147,12 @@ String getUnitText(double v) { return null; } - static final String colors[] = { - "#FF0000", "#FF8000", "#FF00FF", "#7F00FF", - "#0000FF", "#0080FF", "#FFFF00", "#00FFFF", - }; - + static final String colors[] = { "#FF0000", "#FF8000", "#FF00FF", "#7F00FF", "#0000FF", "#0080FF", "#FFFF00", + "#00FFFF", }; + void assignColor(int count) { if (count > 0) { - color = colors[(count-1) % 8]; + color = colors[(count - 1) % 8]; return; } switch (units) { @@ -162,23 +167,22 @@ void assignColor(int count) { break; } } - + void setAcCoupled(boolean b) { if (canAcCouple()) { acCoupled = b; - } - else + } else acCoupled = false; } - + boolean canAcCouple() { return units == Scope.UNITS_V; // AC coupling is permitted if the plot is displaying volts } - + boolean isAcCoupled() { return acCoupled; } - + int getPlotFlags() { return (acCoupled ? FLAG_AC : 0); } @@ -186,15 +190,15 @@ int getPlotFlags() { class Scope { final int FLAG_YELM = 32; - + // bunch of other flags go here, see getFlags() final int FLAG_IVALUE = 2048; // Flag to indicate if IVALUE is included in dump final int FLAG_PLOTS = 4096; // new-style dump with multiple plots - final int FLAG_PERPLOTFLAGS = 1<<18; // new-new style dump with plot flags - final int FLAG_PERPLOT_MAN_SCALE = 1<<19; // new-new style dump with manual included in each plot + final int FLAG_PERPLOTFLAGS = 1 << 18; // new-new style dump with plot flags + final int FLAG_PERPLOT_MAN_SCALE = 1 << 19; // new-new style dump with manual included in each plot final int FLAG_MAN_SCALE = 16; // other flags go here too, see getFlags() - + static final int VAL_POWER = 7; static final int VAL_POWER_OLD = 1; static final int VAL_VOLTAGE = 0; @@ -211,8 +215,8 @@ class Scope { static final int UNITS_W = 2; static final int UNITS_OHMS = 3; static final int UNITS_COUNT = 4; - static final double multa[] = {2.0, 2.5, 2.0}; - static final int V_POSITION_STEPS=200; + static final double multa[] = { 2.0, 2.5, 2.0 }; + static final int V_POSITION_STEPS = 200; static final double MIN_MAN_SCALE = 1e-9; int scopePointCount = 128; FFT fft; @@ -235,12 +239,14 @@ class Scope { CirSim sim; Canvas imageCanvas; Context2d imageContext; - int alphaCounter =0; - // scopeTimeStep to check if sim timestep has changed from previous value when redrawing + int alphaCounter = 0; + // scopeTimeStep to check if sim timestep has changed from previous value when + // redrawing double scopeTimeStep; - double scale[]; // Max value to scale the display to show - indexed for each value of UNITS - e.g. UNITS_V, UNITS_A etc. + double scale[]; // Max value to scale the display to show - indexed for each value of UNITS - + // e.g. UNITS_V, UNITS_A etc. boolean reduceRange[]; - double scaleX, scaleY; // for X-Y plots + double scaleX, scaleY; // for X-Y plots int wheelDeltaY; int selectedPlot; ScopePropertiesDialog properties; @@ -250,29 +256,30 @@ class Scope { int manDivisions = 8; // Number of vertical divisions when in manual mode boolean drawGridLines; boolean somethingSelected; - + static double cursorTime; static int cursorUnits; static Scope cursorScope; - + Scope(CirSim s) { - sim = s; - scale = new double[UNITS_COUNT]; - reduceRange = new boolean[UNITS_COUNT]; - - rect = new Rectangle(0, 0, 1, 1); - imageCanvas=Canvas.createIfSupported(); - imageContext=imageCanvas.getContext2d(); + sim = s; + scale = new double[UNITS_COUNT]; + reduceRange = new boolean[UNITS_COUNT]; + + rect = new Rectangle(0, 0, 1, 1); + imageCanvas = Canvas.createIfSupported(); + imageContext = imageCanvas.getContext2d(); allocImage(); - initialize(); + initialize(); } - + void showCurrent(boolean b) { showI = b; if (b && !showingVoltageAndMaybeCurrent()) setValue(0); calcVisiblePlots(); } + void showVoltage(boolean b) { showV = b; if (b && !showingVoltageAndMaybeCurrent()) @@ -280,158 +287,182 @@ void showVoltage(boolean b) { calcVisiblePlots(); } - void showMax (boolean b) { showMax = b; } - void showScale (boolean b) { showScale = b; } - void showMin (boolean b) { showMin = b; } - void showFreq (boolean b) { showFreq = b; } + void showMax(boolean b) { + showMax = b; + } + + void showScale(boolean b) { + showScale = b; + } + + void showMin(boolean b) { + showMin = b; + } + + void showFreq(boolean b) { + showFreq = b; + } + void showFFT(boolean b) { - showFFT = b; - if (!showFFT) - fft = null; + showFFT = b; + if (!showFFT) + fft = null; } - - void setManualScale(boolean value, boolean roundup) { - if (value!=manualScale) + + void setManualScale(boolean value, boolean roundup) { + if (value != manualScale) clear2dView(); - manualScale = value; + manualScale = value; for (ScopePlot p : plots) { if (!p.manScaleSet) { - p.manScale=getManScaleFromMaxScale(p.units, roundup); - p.manVPosition=0; + p.manScale = getManScaleFromMaxScale(p.units, roundup); + p.manVPosition = 0; p.manScaleSet = true; } } } - - void resetGraph() { resetGraph(false); } - + + void resetGraph() { + resetGraph(false); + } + void resetGraph(boolean full) { - scopePointCount = 1; - while (scopePointCount <= rect.width) - scopePointCount *= 2; - if (plots == null) - plots = new Vector(); - showNegative = false; - int i; - for (i = 0; i != plots.size(); i++) - plots.get(i).reset(scopePointCount, speed, full); + scopePointCount = 1; + while (scopePointCount <= rect.width) + scopePointCount *= 2; + if (plots == null) + plots = new Vector(); + showNegative = false; + int i; + for (i = 0; i != plots.size(); i++) + plots.get(i).reset(scopePointCount, speed, full); calcVisiblePlots(); - scopeTimeStep = sim.maxTimeStep; - allocImage(); + scopeTimeStep = sim.maxTimeStep; + allocImage(); } - + void setManualScaleValue(int plotId, double d) { - if (plotId >= visiblePlots.size() ) + if (plotId >= visiblePlots.size()) return; // Shouldn't happen, but just in case... clear2dView(); - visiblePlots.get(plotId).manScale=d; - visiblePlots.get(plotId).manScaleSet=true; + visiblePlots.get(plotId).manScale = d; + visiblePlots.get(plotId).manScaleSet = true; } - + double getScaleValue() { if (visiblePlots.size() == 0) return 0; ScopePlot p = visiblePlots.get(0); return scale[p.units]; } - + String getScaleUnitsText() { if (visiblePlots.size() == 0) return "V"; ScopePlot p = visiblePlots.get(0); return getScaleUnitsText(p.units); } - + static String getScaleUnitsText(int units) { switch (units) { - case UNITS_A: return "A"; - case UNITS_OHMS: return Locale.ohmString; - case UNITS_W: return "W"; - default: return "V"; + case UNITS_A: + return "A"; + case UNITS_OHMS: + return Locale.ohmString; + case UNITS_W: + return "W"; + default: + return "V"; } } - - boolean active() { return plots.size() > 0 && plots.get(0).elm != null; } - + + boolean active() { + return plots.size() > 0 && plots.get(0).elm != null; + } + void initialize() { - resetGraph(); - scale[UNITS_W] = scale[UNITS_OHMS] = scale[UNITS_V] = 5; - scale[UNITS_A] = .1; - scaleX = 5; - scaleY = .1; - speed = 64; - showMax = true; - showV = showI = false; - showScale = showFreq = manualScale = showMin = showElmInfo = false; - showFFT = false; - plot2d = false; - if (!loadDefaults()) { - // set showV and showI appropriately depending on what plots are present - int i; - for (i = 0; i != plots.size(); i++) { - ScopePlot plot = plots.get(i); - if (plot.units == UNITS_V) - showV = true; - if (plot.units == UNITS_A) - showI = true; - } - } + resetGraph(); + scale[UNITS_W] = scale[UNITS_OHMS] = scale[UNITS_V] = 5; + scale[UNITS_A] = .1; + scaleX = 5; + scaleY = .1; + speed = 64; + showMax = true; + showV = showI = false; + showScale = showFreq = manualScale = showMin = showElmInfo = false; + showFFT = false; + plot2d = false; + if (!loadDefaults()) { + // set showV and showI appropriately depending on what plots are present + int i; + for (i = 0; i != plots.size(); i++) { + ScopePlot plot = plots.get(i); + if (plot.units == UNITS_V) + showV = true; + if (plot.units == UNITS_A) + showI = true; + } + } } - + void calcVisiblePlots() { visiblePlots = new Vector(); int i; int vc = 0, ac = 0, oc = 0; if (!plot2d) { - for (i = 0; i != plots.size(); i++) { - ScopePlot plot = plots.get(i); - if (plot.units == UNITS_V) { - if (showV) { - visiblePlots.add(plot); - plot.assignColor(vc++); - } - } else if (plot.units == UNITS_A) { - if (showI) { - visiblePlots.add(plot); - plot.assignColor(ac++); - } - } else { - visiblePlots.add(plot); - plot.assignColor(oc++); - } - } + for (i = 0; i != plots.size(); i++) { + ScopePlot plot = plots.get(i); + if (plot.units == UNITS_V) { + if (showV) { + visiblePlots.add(plot); + plot.assignColor(vc++); + } + } else if (plot.units == UNITS_A) { + if (showI) { + visiblePlots.add(plot); + plot.assignColor(ac++); + } + } else { + visiblePlots.add(plot); + plot.assignColor(oc++); + } + } } else { // In 2D mode the visible plots are the first two plots - for(i =0; (i<2) && (i(); - if (ce instanceof TransistorElm) - setValue(VAL_VCE, ce); - else - setValue(0, ce); - initialize(); + if (ce instanceof TransistorElm) + setValue(VAL_VCE, ce); + else + setValue(0, ce); + initialize(); } - + void addElm(CircuitElm ce) { - if (ce instanceof TransistorElm) - addValue(VAL_VCE, ce); - else - addValue(0, ce); + if (ce instanceof TransistorElm) + addValue(VAL_VCE, ce); + else + addValue(0, ce); } void setValue(int val) { @@ -443,18 +474,14 @@ void setValue(int val) { plot2d = plotXY = false; setValue(val, ce); } - + void addValue(int val, CircuitElm ce) { if (val == 0) { plots.add(new ScopePlot(ce, UNITS_V, VAL_VOLTAGE, getManScaleFromMaxScale(UNITS_V, false))); - + // create plot for current if applicable - if (ce != null && - sim.dotsCheckItem.getState() && - !(ce instanceof OutputElm || - ce instanceof LogicOutputElm || - ce instanceof AudioOutputElm || - ce instanceof ProbeElm)) + if (ce != null && sim.dotsCheckItem.getState() && !(ce instanceof OutputElm || ce instanceof LogicOutputElm + || ce instanceof AudioOutputElm || ce instanceof ProbeElm)) plots.add(new ScopePlot(ce, UNITS_A, VAL_CURRENT, getManScaleFromMaxScale(UNITS_A, false))); } else { int u = ce.getScopeUnits(val); @@ -467,37 +494,41 @@ void addValue(int val, CircuitElm ce) { calcVisiblePlots(); resetGraph(); } - + void setValue(int val, CircuitElm ce) { plots = new Vector(); addValue(val, ce); -// initialize(); + // initialize(); } void setValues(int val, int ival, CircuitElm ce, CircuitElm yelm) { if (ival > 0) { plots = new Vector(); - plots.add(new ScopePlot(ce, ce.getScopeUnits( val), val, getManScaleFromMaxScale(ce.getScopeUnits( val), false))); - plots.add(new ScopePlot(ce, ce.getScopeUnits(ival), ival, getManScaleFromMaxScale(ce.getScopeUnits(ival), false))); + plots.add(new ScopePlot(ce, ce.getScopeUnits(val), val, + getManScaleFromMaxScale(ce.getScopeUnits(val), false))); + plots.add(new ScopePlot(ce, ce.getScopeUnits(ival), ival, + getManScaleFromMaxScale(ce.getScopeUnits(ival), false))); return; } if (yelm != null) { plots = new Vector(); - plots.add(new ScopePlot(ce, ce.getScopeUnits( val), 0, getManScaleFromMaxScale(ce.getScopeUnits( val), false))); - plots.add(new ScopePlot(yelm, ce.getScopeUnits(ival), 0, getManScaleFromMaxScale(ce.getScopeUnits( val), false))); + plots.add( + new ScopePlot(ce, ce.getScopeUnits(val), 0, getManScaleFromMaxScale(ce.getScopeUnits(val), false))); + plots.add(new ScopePlot(yelm, ce.getScopeUnits(ival), 0, + getManScaleFromMaxScale(ce.getScopeUnits(val), false))); return; } setValue(val); } - + void setText(String s) { text = s; } - + String getText() { return text; } - + boolean showingValue(int v) { int i; for (i = 0; i != plots.size(); i++) { @@ -509,7 +540,8 @@ boolean showingValue(int v) { } // returns true if we have a plot of voltage and nothing else (except current). - // The default case is a plot of voltage and current, so we're basically checking if that case is true. + // The default case is a plot of voltage and current, so we're basically + // checking if that case is true. boolean showingVoltageAndMaybeCurrent() { int i; boolean gotv = false; @@ -522,24 +554,22 @@ else if (sp.value != VAL_CURRENT) } return gotv; } - void combine(Scope s) { /* - // if voltage and current are shown, remove current - if (plots.size() == 2 && plots.get(0).elm == plots.get(1).elm) - plots.remove(1); - if (s.plots.size() == 2 && s.plots.get(0).elm == s.plots.get(1).elm) - plots.add(s.plots.get(0)); - else - */ + * // if voltage and current are shown, remove current if (plots.size() == 2 && + * plots.get(0).elm == plots.get(1).elm) plots.remove(1); if (s.plots.size() == + * 2 && s.plots.get(0).elm == s.plots.get(1).elm) plots.add(s.plots.get(0)); + * else + */ plots = visiblePlots; plots.addAll(s.visiblePlots); s.plots.removeAllElements(); calcVisiblePlots(); } - // separate this scope's plots into separate scopes and return them in arr[pos], arr[pos+1], etc. return new length of array. + // separate this scope's plots into separate scopes and return them in arr[pos], + // arr[pos+1], etc. return new length of array. int separate(Scope arr[], int pos) { int i; ScopePlot lastPlot = null; @@ -567,101 +597,98 @@ void removePlot(int plot) { calcVisiblePlots(); } } - + // called for each timestep void timeStep() { int i; for (i = 0; i != plots.size(); i++) plots.get(i).timeStep(); - int x=0; - int y=0; - + int x = 0; + int y = 0; + // For 2d plots we draw here rather than in the drawing routine - if (plot2d && imageContext!=null && plots.size()>=2) { - double v = plots.get(0).lastValue; - double yval = plots.get(1).lastValue; - if (!isManualScale()) { - boolean newscale = false; - while (v > scaleX || v < -scaleX) { - scaleX *= 2; - newscale = true; - } - while (yval > scaleY || yval < -scaleY) { - scaleY *= 2; - newscale = true; - } - if (newscale) - clear2dView(); - double xa = v /scaleX; - double ya = yval/scaleY; - x = (int) (rect.width *(1+xa)*.499); - y = (int) (rect.height*(1-ya)*.499); - } else { - double gridPx = calc2dGridPx(rect.width, rect.height); - x=(int)(rect.width*.499+(v/plots.get(0).manScale)*gridPx+gridPx*manDivisions*(double)(plots.get(0).manVPosition)/(double)(V_POSITION_STEPS)); - y=(int)(rect.height*.499-(yval/plots.get(1).manScale)*gridPx-gridPx*manDivisions*(double)(plots.get(1).manVPosition)/(double)(V_POSITION_STEPS)); - - } - drawTo(x, y); - } + if (plot2d && imageContext != null && plots.size() >= 2) { + double v = plots.get(0).lastValue; + double yval = plots.get(1).lastValue; + if (!isManualScale()) { + boolean newscale = false; + while (v > scaleX || v < -scaleX) { + scaleX *= 2; + newscale = true; + } + while (yval > scaleY || yval < -scaleY) { + scaleY *= 2; + newscale = true; + } + if (newscale) + clear2dView(); + double xa = v / scaleX; + double ya = yval / scaleY; + x = (int) (rect.width * (1 + xa) * .499); + y = (int) (rect.height * (1 - ya) * .499); + } else { + double gridPx = calc2dGridPx(rect.width, rect.height); + x = (int) (rect.width * .499 + (v / plots.get(0).manScale) * gridPx + + gridPx * manDivisions * (double) (plots.get(0).manVPosition) / (double) (V_POSITION_STEPS)); + y = (int) (rect.height * .499 - (yval / plots.get(1).manScale) * gridPx + - gridPx * manDivisions * (double) (plots.get(1).manVPosition) / (double) (V_POSITION_STEPS)); + + } + drawTo(x, y); + } } double calc2dGridPx(int width, int height) { - int m = width 0) { - g.setColor("#880000"); - g.drawLine(x, 0, x, rect.height); - } - g.setColor("#FF0000"); - g.drawString(s, x + 2, rect.height); - } + // Draw x-grid lines and label the frequencies in the FFT that they point to. + int prevEnd = 0; + int divs = 20; + double maxFrequency = 1 / (sim.maxTimeStep * speed * divs * 2); + for (int i = 0; i < divs; i++) { + int x = rect.width * i / divs; + if (x < prevEnd) + continue; + String s = ((int) Math.round(i * maxFrequency)) + "Hz"; + int sWidth = (int) Math.ceil(g.context.measureText(s).getWidth()); + prevEnd = x + sWidth + 4; + if (i > 0) { + g.setColor("#880000"); + g.drawLine(x, 0, x, rect.height); + } + g.setColor("#FF0000"); + g.drawString(s, x + 2, rect.height); + } } void drawFFT(Graphics g) { - if (fft == null || fft.getSize() != scopePointCount) - fft = new FFT(scopePointCount); - double[] real = new double[scopePointCount]; - double[] imag = new double[scopePointCount]; - ScopePlot plot = (visiblePlots.size() == 0) ? plots.firstElement() : visiblePlots.firstElement(); - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - int ptr = plot.ptr; - for (int i = 0; i < scopePointCount; i++) { - int ii = (ptr - i + scopePointCount) & (scopePointCount - 1); - // need to average max and min or else it could cause average of function to be > 0, which - // produces spike at 0 Hz that hides rest of spectrum - real[i] = .5*(maxV[ii]+minV[ii]); - imag[i] = 0; - } - fft.fft(real, imag); - double maxM = 1e-8; - for (int i = 0; i < scopePointCount / 2; i++) { - double m = fft.magnitude(real[i], imag[i]); - if (m > maxM) - maxM = m; - } - int prevX = 0; - g.setColor("#FF0000"); - if (!logSpectrum) { - int prevHeight = 0; - int y = (rect.height - 1) - 12; - for (int i = 0; i < scopePointCount / 2; i++) { - int x = 2 * i * rect.width / scopePointCount; - // rect.width may be greater than or less than scopePointCount/2, - // so x may be greater than or equal to prevX. - double magnitude = fft.magnitude(real[i], imag[i]); - int height = (int) ((magnitude * y) / maxM); - if (x != prevX) - g.drawLine(prevX, y - prevHeight, x, y - height); - prevHeight = height; - prevX = x; - } - } else { - int y0 = 5; - int prevY = 0; - double ymult = rect.height/10; - double val0 = Math.log(scale[plot.units])*ymult; - for (int i = 0; i < scopePointCount / 2; i++) { - int x = 2 * i * rect.width / scopePointCount; - // rect.width may be greater than or less than scopePointCount/2, - // so x may be greater than or equal to prevX. - double val = Math.log(fft.magnitude(real[i], imag[i])); - int y = y0-(int) (val*ymult-val0); - if (x != prevX) - g.drawLine(prevX, prevY, x, y); - prevY = y; - prevX = x; - } - } + if (fft == null || fft.getSize() != scopePointCount) + fft = new FFT(scopePointCount); + double[] real = new double[scopePointCount]; + double[] imag = new double[scopePointCount]; + ScopePlot plot = (visiblePlots.size() == 0) ? plots.firstElement() : visiblePlots.firstElement(); + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + int ptr = plot.ptr; + for (int i = 0; i < scopePointCount; i++) { + int ii = (ptr - i + scopePointCount) & (scopePointCount - 1); + // need to average max and min or else it could cause average of function to be + // > 0, which + // produces spike at 0 Hz that hides rest of spectrum + real[i] = .5 * (maxV[ii] + minV[ii]); + imag[i] = 0; + } + fft.fft(real, imag); + double maxM = 1e-8; + for (int i = 0; i < scopePointCount / 2; i++) { + double m = fft.magnitude(real[i], imag[i]); + if (m > maxM) + maxM = m; + } + int prevX = 0; + g.setColor("#FF0000"); + if (!logSpectrum) { + int prevHeight = 0; + int y = (rect.height - 1) - 12; + for (int i = 0; i < scopePointCount / 2; i++) { + int x = 2 * i * rect.width / scopePointCount; + // rect.width may be greater than or less than scopePointCount/2, + // so x may be greater than or equal to prevX. + double magnitude = fft.magnitude(real[i], imag[i]); + int height = (int) ((magnitude * y) / maxM); + if (x != prevX) + g.drawLine(prevX, y - prevHeight, x, y - height); + prevHeight = height; + prevX = x; + } + } else { + int y0 = 5; + int prevY = 0; + double ymult = rect.height / 10; + double val0 = Math.log(scale[plot.units]) * ymult; + for (int i = 0; i < scopePointCount / 2; i++) { + int x = 2 * i * rect.width / scopePointCount; + // rect.width may be greater than or less than scopePointCount/2, + // so x may be greater than or equal to prevX. + double val = Math.log(fft.magnitude(real[i], imag[i])); + int y = y0 - (int) (val * ymult - val0); + if (x != prevX) + g.drawLine(prevX, prevY, x, y); + prevY = y; + prevX = x; + } + } } - + void drawSettingsWheel(Graphics g) { final int outR = 8; - final int inR= 5; + final int inR = 5; final int inR45 = 4; final int outR45 = 6; if (showSettingsWheel()) { @@ -771,122 +804,120 @@ void drawSettingsWheel(Graphics g) { g.setColor(CircuitElm.selectColor); else g.setColor(Color.dark_gray); - g.context.translate(rect.x+18, rect.y+rect.height-18); - CircuitElm.drawThickCircle(g,0, 0, inR); + g.context.translate(rect.x + 18, rect.y + rect.height - 18); + CircuitElm.drawThickCircle(g, 0, 0, inR); CircuitElm.drawThickLine(g, -outR, 0, -inR, 0); CircuitElm.drawThickLine(g, outR, 0, inR, 0); CircuitElm.drawThickLine(g, 0, -outR, 0, -inR); CircuitElm.drawThickLine(g, 0, outR, 0, inR); - CircuitElm.drawThickLine(g, -outR45, -outR45,-inR45,-inR45); - CircuitElm.drawThickLine(g, outR45, -outR45,inR45,-inR45); - CircuitElm.drawThickLine(g, -outR45, outR45,-inR45,inR45); - CircuitElm.drawThickLine(g, outR45, outR45,inR45,inR45); - g.context.restore(); + CircuitElm.drawThickLine(g, -outR45, -outR45, -inR45, -inR45); + CircuitElm.drawThickLine(g, outR45, -outR45, inR45, -inR45); + CircuitElm.drawThickLine(g, -outR45, outR45, -inR45, inR45); + CircuitElm.drawThickLine(g, outR45, outR45, inR45, inR45); + g.context.restore(); } } void draw2d(Graphics g) { - if (imageContext==null) - return; - g.context.save(); - g.context.translate(rect.x, rect.y); - g.clipRect(0, 0, rect.width, rect.height); - - alphaCounter++; - - if (alphaCounter>2) { - // fade out plot - alphaCounter=0; - imageContext.setGlobalAlpha(0.01); - if (sim.printableCheckItem.getState()) { - imageContext.setFillStyle("#ffffff"); - } else { - imageContext.setFillStyle("#000000"); - } - imageContext.fillRect(0,0,rect.width,rect.height); - imageContext.setGlobalAlpha(1.0); - } - - g.context.drawImage(imageContext.getCanvas(), 0.0, 0.0); -// g.drawImage(image, r.x, r.y, null); - g.setColor(CircuitElm.whiteColor); - g.fillOval(draw_ox-2, draw_oy-2, 5, 5); - // Axis - g.setColor(CircuitElm.positiveColor); - g.drawLine(0, rect.height/2, rect.width-1, rect.height/2); - if (!plotXY) - g.setColor(Color.yellow); - g.drawLine(rect.width/2, 0, rect.width/2, rect.height-1); - if (isManualScale()) { - double gridPx=calc2dGridPx(rect.width, rect.height); - g.setColor("#404040"); - for(int i=-manDivisions; i<=manDivisions; i++) { - if (i!=0) - g.drawLine((int)(gridPx*i)+rect.width/2, 0,(int)(gridPx*i)+rect.width/2, rect.height); - g.drawLine(0, (int)(gridPx*i)+rect.height/2,rect.width, (int)(gridPx*i)+rect.height/2); - } - } - textY=10; + if (imageContext == null) + return; + g.context.save(); + g.context.translate(rect.x, rect.y); + g.clipRect(0, 0, rect.width, rect.height); + + alphaCounter++; + + if (alphaCounter > 2) { + // fade out plot + alphaCounter = 0; + imageContext.setGlobalAlpha(0.01); + if (sim.printableCheckItem.getState()) { + imageContext.setFillStyle("#ffffff"); + } else { + imageContext.setFillStyle("#000000"); + } + imageContext.fillRect(0, 0, rect.width, rect.height); + imageContext.setGlobalAlpha(1.0); + } + + g.context.drawImage(imageContext.getCanvas(), 0.0, 0.0); + // g.drawImage(image, r.x, r.y, null); g.setColor(CircuitElm.whiteColor); - if (text != null) { - drawInfoText(g, text); - } - if (showScale && plots.size()>=2 && isManualScale()) { - ScopePlot px = plots.get(0); - String sx=px.getUnitText(px.manScale); - ScopePlot py = plots.get(1); - String sy=py.getUnitText(py.manScale); - drawInfoText(g,"X="+sx+"/div, Y="+sy+"/div"); - } - g.context.restore(); - drawSettingsWheel(g); - if ( !sim.dialogIsShowing() && rect.contains(sim.mouseCursorX, sim.mouseCursorY) && plots.size()>=2) { - double gridPx=calc2dGridPx(rect.width, rect.height); - String info[] = new String [2]; - ScopePlot px = plots.get(0); - ScopePlot py = plots.get(1); - double xValue; - double yValue; - if (isManualScale()) { - xValue = px.manScale*((double)(sim.mouseCursorX-rect.x-rect.width/2)/gridPx-manDivisions*px.manVPosition/(double)(V_POSITION_STEPS)); - yValue = py.manScale*((double)(-sim.mouseCursorY+rect.y+rect.height/2)/gridPx-manDivisions*py.manVPosition/(double)(V_POSITION_STEPS)); - } else { - xValue = ((double)(sim.mouseCursorX-rect.x)/(0.499*(double)(rect.width))-1.0)*scaleX; - yValue = -((double)(sim.mouseCursorY-rect.y)/(0.499*(double)(rect.height))-1.0)*scaleY; - } - info[0]=px.getUnitText(xValue); - info[1]=py.getUnitText(yValue); - - drawCursorInfo(g, info, 2, sim.mouseCursorX, true); - - } - } - - - + g.fillOval(draw_ox - 2, draw_oy - 2, 5, 5); + // Axis + g.setColor(CircuitElm.positiveColor); + g.drawLine(0, rect.height / 2, rect.width - 1, rect.height / 2); + if (!plotXY) + g.setColor(Color.yellow); + g.drawLine(rect.width / 2, 0, rect.width / 2, rect.height - 1); + if (isManualScale()) { + double gridPx = calc2dGridPx(rect.width, rect.height); + g.setColor("#404040"); + for (int i = -manDivisions; i <= manDivisions; i++) { + if (i != 0) + g.drawLine((int) (gridPx * i) + rect.width / 2, 0, (int) (gridPx * i) + rect.width / 2, + rect.height); + g.drawLine(0, (int) (gridPx * i) + rect.height / 2, rect.width, (int) (gridPx * i) + rect.height / 2); + } + } + textY = 10; + g.setColor(CircuitElm.whiteColor); + if (text != null) { + drawInfoText(g, text); + } + if (showScale && plots.size() >= 2 && isManualScale()) { + ScopePlot px = plots.get(0); + String sx = px.getUnitText(px.manScale); + ScopePlot py = plots.get(1); + String sy = py.getUnitText(py.manScale); + drawInfoText(g, "X=" + sx + "/div, Y=" + sy + "/div"); + } + g.context.restore(); + drawSettingsWheel(g); + if (!sim.dialogIsShowing() && rect.contains(sim.mouseCursorX, sim.mouseCursorY) && plots.size() >= 2) { + double gridPx = calc2dGridPx(rect.width, rect.height); + String info[] = new String[2]; + ScopePlot px = plots.get(0); + ScopePlot py = plots.get(1); + double xValue; + double yValue; + if (isManualScale()) { + xValue = px.manScale * ((double) (sim.mouseCursorX - rect.x - rect.width / 2) / gridPx + - manDivisions * px.manVPosition / (double) (V_POSITION_STEPS)); + yValue = py.manScale * ((double) (-sim.mouseCursorY + rect.y + rect.height / 2) / gridPx + - manDivisions * py.manVPosition / (double) (V_POSITION_STEPS)); + } else { + xValue = ((double) (sim.mouseCursorX - rect.x) / (0.499 * (double) (rect.width)) - 1.0) * scaleX; + yValue = -((double) (sim.mouseCursorY - rect.y) / (0.499 * (double) (rect.height)) - 1.0) * scaleY; + } + info[0] = px.getUnitText(xValue); + info[1] = py.getUnitText(yValue); + + drawCursorInfo(g, info, 2, sim.mouseCursorX, true); + + } + } + boolean showSettingsWheel() { return rect.height > 100 && rect.width > 100; } - + boolean cursorInSettingsWheel() { - return showSettingsWheel() && - sim.mouseCursorX >= rect.x && - sim.mouseCursorX <= rect.x + 36 && - sim.mouseCursorY >= rect.y + rect.height - 36 && - sim.mouseCursorY <= rect.y + rect.height; + return showSettingsWheel() && sim.mouseCursorX >= rect.x && sim.mouseCursorX <= rect.x + 36 + && sim.mouseCursorY >= rect.y + rect.height - 36 && sim.mouseCursorY <= rect.y + rect.height; } - + // does another scope have something selected? void checkForSelectionElsewhere() { // if mouse is here, then selection is already set by checkForSelection() if (cursorScope == this) return; - + if (cursorScope == null || visiblePlots.size() == 0) { selectedPlot = -1; return; } - + // find a plot with same units as selected plot int i; for (i = 0; i != visiblePlots.size(); i++) { @@ -896,350 +927,352 @@ void checkForSelectionElsewhere() { return; } } - + // default if we can't find anything with matching units selectedPlot = 0; } - + void draw(Graphics g) { if (plots.size() == 0) return; - - // reset if timestep changed - if (scopeTimeStep != sim.maxTimeStep) { - scopeTimeStep = sim.maxTimeStep; - resetGraph(); - } - - - if (plot2d) { - draw2d(g); - return; - } - - drawSettingsWheel(g); - g.context.save(); - g.setColor(Color.red); - g.context.translate(rect.x, rect.y); - g.clipRect(0, 0, rect.width, rect.height); - - if (showFFT) { - drawFFTVerticalGridLines(g); - drawFFT(g); - } - - int i; - for (i = 0; i != UNITS_COUNT; i++) { - reduceRange[i] = false; - if (maxScale && !manualScale) - scale[i] = 1e-4; - } - - int si; - somethingSelected = false; // is one of our plots selected? - - for (si = 0; si != visiblePlots.size(); si++) { - ScopePlot plot = visiblePlots.get(si); - calcPlotScale(plot); - if (sim.scopeSelected == -1 && plot.elm !=null && plot.elm.isMouseElm()) - somethingSelected = true; - reduceRange[plot.units] = true; - } - - boolean sel = sim.scopeMenuIsSelected(this); - - checkForSelectionElsewhere(); - if (selectedPlot >= 0) - somethingSelected = true; - - drawGridLines = true; - boolean allPlotsSameUnits = true; - for (i = 1; i < visiblePlots.size(); i++) { - if (visiblePlots.get(i).units != visiblePlots.get(0).units) - allPlotsSameUnits = false; // Don't draw horizontal grid lines unless all plots are in same units - } - - if ((allPlotsSameUnits || showMax || showMin) && visiblePlots.size() > 0) - calcMaxAndMin(visiblePlots.firstElement().units); - - // draw volt plots on top (last), then current plots underneath, then everything else - for (i = 0; i != visiblePlots.size(); i++) { - if (visiblePlots.get(i).units > UNITS_A && i != selectedPlot) - drawPlot(g, visiblePlots.get(i), allPlotsSameUnits, false, sel); - } - for (i = 0; i != visiblePlots.size(); i++) { - if (visiblePlots.get(i).units == UNITS_A && i != selectedPlot) - drawPlot(g, visiblePlots.get(i), allPlotsSameUnits, false, sel); - } - for (i = 0; i != visiblePlots.size(); i++) { - if (visiblePlots.get(i).units == UNITS_V && i != selectedPlot) - drawPlot(g, visiblePlots.get(i), allPlotsSameUnits, false, sel); - } - // draw selection on top. only works if selection chosen from scope - if (selectedPlot >= 0 && selectedPlot < visiblePlots.size()) - drawPlot(g, visiblePlots.get(selectedPlot), allPlotsSameUnits, true, sel); - - drawInfoTexts(g); - - g.restore(); - - drawCursor(g); - - if (plots.get(0).ptr > 5 && !manualScale) { - for (i = 0; i != UNITS_COUNT; i++) - if (scale[i] > 1e-4 && reduceRange[i]) - scale[i] /= 2; - } - - if ( (properties != null ) && properties.isShowing() ) - properties.refreshDraw(); + + // reset if timestep changed + if (scopeTimeStep != sim.maxTimeStep) { + scopeTimeStep = sim.maxTimeStep; + resetGraph(); + } + + if (plot2d) { + draw2d(g); + return; + } + + drawSettingsWheel(g); + g.context.save(); + g.setColor(Color.red); + g.context.translate(rect.x, rect.y); + g.clipRect(0, 0, rect.width, rect.height); + + if (showFFT) { + drawFFTVerticalGridLines(g); + drawFFT(g); + } + + int i; + for (i = 0; i != UNITS_COUNT; i++) { + reduceRange[i] = false; + if (maxScale && !manualScale) + scale[i] = 1e-4; + } + + int si; + somethingSelected = false; // is one of our plots selected? + + for (si = 0; si != visiblePlots.size(); si++) { + ScopePlot plot = visiblePlots.get(si); + calcPlotScale(plot); + if (sim.scopeSelected == -1 && plot.elm != null && plot.elm.isMouseElm()) + somethingSelected = true; + reduceRange[plot.units] = true; + } + + boolean sel = sim.scopeMenuIsSelected(this); + + checkForSelectionElsewhere(); + if (selectedPlot >= 0) + somethingSelected = true; + + drawGridLines = true; + boolean allPlotsSameUnits = true; + for (i = 1; i < visiblePlots.size(); i++) { + if (visiblePlots.get(i).units != visiblePlots.get(0).units) + allPlotsSameUnits = false; // Don't draw horizontal grid lines unless all plots are in same units + } + + if ((allPlotsSameUnits || showMax || showMin) && visiblePlots.size() > 0) + calcMaxAndMin(visiblePlots.firstElement().units); + + // draw volt plots on top (last), then current plots underneath, then everything + // else + for (i = 0; i != visiblePlots.size(); i++) { + if (visiblePlots.get(i).units > UNITS_A && i != selectedPlot) + drawPlot(g, visiblePlots.get(i), allPlotsSameUnits, false, sel); + } + for (i = 0; i != visiblePlots.size(); i++) { + if (visiblePlots.get(i).units == UNITS_A && i != selectedPlot) + drawPlot(g, visiblePlots.get(i), allPlotsSameUnits, false, sel); + } + for (i = 0; i != visiblePlots.size(); i++) { + if (visiblePlots.get(i).units == UNITS_V && i != selectedPlot) + drawPlot(g, visiblePlots.get(i), allPlotsSameUnits, false, sel); + } + // draw selection on top. only works if selection chosen from scope + if (selectedPlot >= 0 && selectedPlot < visiblePlots.size()) + drawPlot(g, visiblePlots.get(selectedPlot), allPlotsSameUnits, true, sel); + + drawInfoTexts(g); + + g.restore(); + + drawCursor(g); + + if (plots.get(0).ptr > 5 && !manualScale) { + for (i = 0; i != UNITS_COUNT; i++) + if (scale[i] > 1e-4 && reduceRange[i]) + scale[i] /= 2; + } + + if ((properties != null) && properties.isShowing()) + properties.refreshDraw(); } - // calculate maximum and minimum values for all plots of given units void calcMaxAndMin(int units) { maxValue = -1e8; minValue = 1e8; - int i; - int si; - for (si = 0; si != visiblePlots.size(); si++) { - ScopePlot plot = visiblePlots.get(si); - if (plot.units != units) - continue; - int ipa = plot.startIndex(rect.width); - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); - if (maxV[ip] > maxValue) - maxValue = maxV[ip]; - if (minV[ip] < minValue) - minValue = minV[ip]; - } - } + int i; + int si; + for (si = 0; si != visiblePlots.size(); si++) { + ScopePlot plot = visiblePlots.get(si); + if (plot.units != units) + continue; + int ipa = plot.startIndex(rect.width); + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + for (i = 0; i != rect.width; i++) { + int ip = (i + ipa) & (scopePointCount - 1); + if (maxV[ip] > maxValue) + maxValue = maxV[ip]; + if (minV[ip] < minValue) + minValue = minV[ip]; + } + } } - + // adjust scale of a plot void calcPlotScale(ScopePlot plot) { if (manualScale) return; - int i; - int ipa = plot.startIndex(rect.width); - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - double max = 0; - double gridMax = scale[plot.units]; - for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); - if (maxV[ip] > max) - max = maxV[ip]; - if (minV[ip] < -max) - max = -minV[ip]; - } - // scale fixed at maximum? - if (maxScale) - gridMax = Math.max(max, gridMax); - else - // adjust in powers of two - while (max > gridMax) - gridMax *= 2; - scale[plot.units] = gridMax; + int i; + int ipa = plot.startIndex(rect.width); + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + double max = 0; + double gridMax = scale[plot.units]; + for (i = 0; i != rect.width; i++) { + int ip = (i + ipa) & (scopePointCount - 1); + if (maxV[ip] > max) + max = maxV[ip]; + if (minV[ip] < -max) + max = -minV[ip]; + } + // scale fixed at maximum? + if (maxScale) + gridMax = Math.max(max, gridMax); + else + // adjust in powers of two + while (max > gridMax) + gridMax *= 2; + scale[plot.units] = gridMax; } - + double calcGridStepX() { - int multptr=0; - double gsx = 1e-15; + int multptr = 0; + double gsx = 1e-15; - double ts = sim.maxTimeStep*speed; - while (gsx < ts*20) { - gsx *=multa[(multptr++)%3]; - } - return gsx; + double ts = sim.maxTimeStep * speed; + while (gsx < ts * 20) { + gsx *= multa[(multptr++) % 3]; + } + return gsx; } - double getGridMaxFromManScale(ScopePlot plot) { - return ((double)(manDivisions)/2+0.05)*plot.manScale; + return ((double) (manDivisions) / 2 + 0.05) * plot.manScale; } - + void drawPlot(Graphics g, ScopePlot plot, boolean allPlotsSameUnits, boolean selected, boolean allSelected) { if (plot.elm == null) return; - int i; - String col; - - double gridMid, positionOffset; - int multptr=0; - int x = 0; - final int maxy = (rect.height-1)/2; - - String color = (somethingSelected) ? "#A0A0A0" : plot.color; - if (allSelected || (sim.scopeSelected == -1 && plot.elm.isMouseElm())) - color = CircuitElm.selectColor.getHexValue(); + int i; + String col; + + double gridMid, positionOffset; + int multptr = 0; + int x = 0; + final int maxy = (rect.height - 1) / 2; + + String color = (somethingSelected) ? "#A0A0A0" : plot.color; + if (allSelected || (sim.scopeSelected == -1 && plot.elm.isMouseElm())) + color = CircuitElm.selectColor.getHexValue(); else if (selected) color = plot.color; - int ipa = plot.startIndex(rect.width); - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - double gridMax; - - - // Calculate the max value (positive) to show and the value at the mid point of the grid - if (!isManualScale()) { - gridMax = scale[plot.units]; - gridMid = 0; - positionOffset = 0; - if (allPlotsSameUnits) { - // if we don't have overlapping scopes of different units, we can move zero around. - // Put it at the bottom if the scope is never negative. - double mx = gridMax; - double mn = 0; - if (maxScale) { - // scale is maxed out, so fix boundaries of scope at maximum and minimum. - mx = maxValue; - mn = minValue; - } else if (showNegative || minValue < (mx+mn)*.5 - (mx-mn)*.55) { - mn = -gridMax; - showNegative = true; - } - gridMid = (mx+mn)*.5; - gridMax = (mx-mn)*.55; // leave space at top and bottom - } - } else { - gridMid =0; - gridMax = getGridMaxFromManScale(plot); - positionOffset = gridMax*2.0*(double)(plot.manVPosition)/(double)(V_POSITION_STEPS); - } - plot.plotOffset = -gridMid+positionOffset; - - plot.gridMult = maxy/gridMax; - - int minRangeLo = -10-(int) (gridMid*plot.gridMult); - int minRangeHi = 10-(int) (gridMid*plot.gridMult); - if (!isManualScale()) { - gridStepY = 1e-8; - while (gridStepY < 20*gridMax/maxy) { - gridStepY *=multa[(multptr++)%3]; - } - } else { - gridStepY = plot.manScale; - } - - String minorDiv = "#404040"; - String majorDiv = "#A0A0A0"; - if (sim.printableCheckItem.getState()) { - minorDiv = "#D0D0D0"; - majorDiv = "#808080"; - curColor = "#A0A000"; - } - if (allSelected) - majorDiv = CircuitElm.selectColor.getHexValue(); - - // Vertical (T) gridlines - double ts = sim.maxTimeStep*speed; - gridStepX = calcGridStepX(); - - boolean highlightCenter = !isManualScale(); - - if (drawGridLines) { - // horizontal gridlines - - // don't show hgridlines if lines are too close together (except for center line) - boolean showHGridLines = (gridStepY != 0) && (isManualScale() || allPlotsSameUnits); // Will only show center line if we have mixed units - for (int ll = -100; ll <= 100; ll++) { - if (ll != 0 && !showHGridLines) - continue; - int yl = maxy-(int) ((ll*gridStepY-gridMid)*plot.gridMult); - if (yl < 0 || yl >= rect.height-1) - continue; - col = ll == 0 && highlightCenter ? majorDiv : minorDiv; - g.setColor(col); - g.drawLine(0,yl,rect.width-1,yl); - } - - // vertical gridlines - double tstart = sim.t-sim.maxTimeStep*speed*rect.width; - double tx = sim.t-(sim.t % gridStepX); - - for (int ll = 0; ; ll++) { - double tl = tx-gridStepX*ll; - int gx = (int) ((tl-tstart)/ts); - if (gx < 0) - break; - if (gx >= rect.width) - continue; - if (tl < 0) - continue; - col = minorDiv; - // first = 0; - if (((tl+gridStepX/4) % (gridStepX*10)) < gridStepX) { - col = majorDiv; - } - g.setColor(col); - g.drawLine(gx,0,gx,rect.height-1); - } - } - - // only need gridlines drawn once - drawGridLines = false; - - g.setColor(color); - - if (isManualScale()) { - // draw zero point - int y0= maxy-(int) (plot.gridMult*plot.plotOffset); - g.drawLine(0, y0, 8, y0); - g.drawString("0", 0, y0-2); - } - - int ox = -1, oy = -1; - for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); - int minvy = (int) (plot.gridMult*(minV[ip]+plot.plotOffset)); - int maxvy = (int) (plot.gridMult*(maxV[ip]+plot.plotOffset)); - if (minvy <= maxy) { - if (minvy < minRangeLo || maxvy > minRangeHi) { - // we got a value outside min range, so we don't need to rescale later - reduceRange[plot.units] = false; - minRangeLo = -1000; - minRangeHi = 1000; // avoid triggering this test again - } - if (ox != -1) { - if (minvy == oy && maxvy == oy) - continue; - g.drawLine(ox, maxy-oy, x+i, maxy-oy); - ox = oy = -1; - } - if (minvy == maxvy) { - ox = x+i; - oy = minvy; - continue; - } - g.drawLine(x+i, maxy-minvy, x+i, maxy-maxvy); - } - } // for (i=0...) - if (ox != -1) - g.drawLine(ox, maxy-oy, x+i-1, maxy-oy); // Horizontal - + int ipa = plot.startIndex(rect.width); + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + double gridMax; + + // Calculate the max value (positive) to show and the value at the mid point of + // the grid + if (!isManualScale()) { + gridMax = scale[plot.units]; + gridMid = 0; + positionOffset = 0; + if (allPlotsSameUnits) { + // if we don't have overlapping scopes of different units, we can move zero + // around. + // Put it at the bottom if the scope is never negative. + double mx = gridMax; + double mn = 0; + if (maxScale) { + // scale is maxed out, so fix boundaries of scope at maximum and minimum. + mx = maxValue; + mn = minValue; + } else if (showNegative || minValue < (mx + mn) * .5 - (mx - mn) * .55) { + mn = -gridMax; + showNegative = true; + } + gridMid = (mx + mn) * .5; + gridMax = (mx - mn) * .55; // leave space at top and bottom + } + } else { + gridMid = 0; + gridMax = getGridMaxFromManScale(plot); + positionOffset = gridMax * 2.0 * (double) (plot.manVPosition) / (double) (V_POSITION_STEPS); + } + plot.plotOffset = -gridMid + positionOffset; + + plot.gridMult = maxy / gridMax; + + int minRangeLo = -10 - (int) (gridMid * plot.gridMult); + int minRangeHi = 10 - (int) (gridMid * plot.gridMult); + if (!isManualScale()) { + gridStepY = 1e-8; + while (gridStepY < 20 * gridMax / maxy) { + gridStepY *= multa[(multptr++) % 3]; + } + } else { + gridStepY = plot.manScale; + } + + String minorDiv = "#404040"; + String majorDiv = "#A0A0A0"; + if (sim.printableCheckItem.getState()) { + minorDiv = "#D0D0D0"; + majorDiv = "#808080"; + curColor = "#A0A000"; + } + if (allSelected) + majorDiv = CircuitElm.selectColor.getHexValue(); + + // Vertical (T) gridlines + double ts = sim.maxTimeStep * speed; + gridStepX = calcGridStepX(); + + boolean highlightCenter = !isManualScale(); + + if (drawGridLines) { + // horizontal gridlines + + // don't show hgridlines if lines are too close together (except for center + // line) + boolean showHGridLines = (gridStepY != 0) && (isManualScale() || allPlotsSameUnits); // Will only show + // center line if we + // have mixed units + for (int ll = -100; ll <= 100; ll++) { + if (ll != 0 && !showHGridLines) + continue; + int yl = maxy - (int) ((ll * gridStepY - gridMid) * plot.gridMult); + if (yl < 0 || yl >= rect.height - 1) + continue; + col = ll == 0 && highlightCenter ? majorDiv : minorDiv; + g.setColor(col); + g.drawLine(0, yl, rect.width - 1, yl); + } + + // vertical gridlines + double tstart = sim.t - sim.maxTimeStep * speed * rect.width; + double tx = sim.t - (sim.t % gridStepX); + + for (int ll = 0;; ll++) { + double tl = tx - gridStepX * ll; + int gx = (int) ((tl - tstart) / ts); + if (gx < 0) + break; + if (gx >= rect.width) + continue; + if (tl < 0) + continue; + col = minorDiv; + // first = 0; + if (((tl + gridStepX / 4) % (gridStepX * 10)) < gridStepX) { + col = majorDiv; + } + g.setColor(col); + g.drawLine(gx, 0, gx, rect.height - 1); + } + } + + // only need gridlines drawn once + drawGridLines = false; + + g.setColor(color); + + if (isManualScale()) { + // draw zero point + int y0 = maxy - (int) (plot.gridMult * plot.plotOffset); + g.drawLine(0, y0, 8, y0); + g.drawString("0", 0, y0 - 2); + } + + int ox = -1, oy = -1; + for (i = 0; i != rect.width; i++) { + int ip = (i + ipa) & (scopePointCount - 1); + int minvy = (int) (plot.gridMult * (minV[ip] + plot.plotOffset)); + int maxvy = (int) (plot.gridMult * (maxV[ip] + plot.plotOffset)); + if (minvy <= maxy) { + if (minvy < minRangeLo || maxvy > minRangeHi) { + // we got a value outside min range, so we don't need to rescale later + reduceRange[plot.units] = false; + minRangeLo = -1000; + minRangeHi = 1000; // avoid triggering this test again + } + if (ox != -1) { + if (minvy == oy && maxvy == oy) + continue; + g.drawLine(ox, maxy - oy, x + i, maxy - oy); + ox = oy = -1; + } + if (minvy == maxvy) { + ox = x + i; + oy = minvy; + continue; + } + g.drawLine(x + i, maxy - minvy, x + i, maxy - maxvy); + } + } // for (i=0...) + if (ox != -1) + g.drawLine(ox, maxy - oy, x + i - 1, maxy - oy); // Horizontal + } static void clearCursorInfo() { cursorScope = null; cursorTime = -1; } - + void selectScope(int mouseX, int mouseY) { if (!rect.contains(mouseX, mouseY)) return; if (plot2d || visiblePlots.size() == 0) cursorTime = -1; else - cursorTime = sim.t-sim.maxTimeStep*speed*(rect.x+rect.width-mouseX); - checkForSelection(mouseX, mouseY); - cursorScope = this; + cursorTime = sim.t - sim.maxTimeStep * speed * (rect.x + rect.width - mouseX); + checkForSelection(mouseX, mouseY); + cursorScope = this; } - + // find selected plot void checkForSelection(int mouseX, int mouseY) { if (sim.dialogIsShowing()) @@ -1253,26 +1286,26 @@ void checkForSelection(int mouseX, int mouseY) { return; } int ipa = plots.get(0).startIndex(rect.width); - int ip = (mouseX-rect.x+ipa) & (scopePointCount-1); - int maxy = (rect.height-1)/2; - int y = maxy; - int i; - int bestdist = 10000; - int best = -1; - for (i = 0; i != visiblePlots.size(); i++) { - ScopePlot plot = visiblePlots.get(i); - int maxvy = (int) (plot.gridMult*(plot.maxValues[ip]+plot.plotOffset)); - int dist = Math.abs(mouseY-(rect.y+y-maxvy)); - if (dist < bestdist) { - bestdist = dist; - best = i; - } - } - selectedPlot = best; - if (selectedPlot >= 0) - cursorUnits = visiblePlots.get(selectedPlot).units; + int ip = (mouseX - rect.x + ipa) & (scopePointCount - 1); + int maxy = (rect.height - 1) / 2; + int y = maxy; + int i; + int bestdist = 10000; + int best = -1; + for (i = 0; i != visiblePlots.size(); i++) { + ScopePlot plot = visiblePlots.get(i); + int maxvy = (int) (plot.gridMult * (plot.maxValues[ip] + plot.plotOffset)); + int dist = Math.abs(mouseY - (rect.y + y - maxvy)); + if (dist < bestdist) { + bestdist = dist; + best = i; + } + } + selectedPlot = best; + if (selectedPlot >= 0) + cursorUnits = visiblePlots.get(selectedPlot).units; } - + void drawCursor(Graphics g) { if (sim.dialogIsShowing()) return; @@ -1282,34 +1315,35 @@ void drawCursor(Graphics g) { int cursorX = -1; int ct = 0; if (cursorTime >= 0) { - cursorX = -(int) ((sim.t-cursorTime)/(sim.maxTimeStep*speed) - rect.x - rect.width); + cursorX = -(int) ((sim.t - cursorTime) / (sim.maxTimeStep * speed) - rect.x - rect.width); if (cursorX >= rect.x) { int ipa = plots.get(0).startIndex(rect.width); - int ip = (cursorX-rect.x+ipa) & (scopePointCount-1); - int maxy = (rect.height-1)/2; + int ip = (cursorX - rect.x + ipa) & (scopePointCount - 1); + int maxy = (rect.height - 1) / 2; int y = maxy; if (visiblePlots.size() > 0) { ScopePlot plot = visiblePlots.get(selectedPlot >= 0 ? selectedPlot : 0); info[ct++] = plot.getUnitText(plot.maxValues[ip]); - int maxvy = (int) (plot.gridMult*(plot.maxValues[ip]+plot.plotOffset)); + int maxvy = (int) (plot.gridMult * (plot.maxValues[ip] + plot.plotOffset)); g.setColor(plot.color); - g.fillOval(cursorX-2, rect.y+y-maxvy-2, 5, 5); + g.fillOval(cursorX - 2, rect.y + y - maxvy - 2, 5, 5); } } } - - // show FFT even if there's no plots (in which case cursorTime/cursorX will be invalid) - if (showFFT && cursorScope == this) { - double maxFrequency = 1 / (sim.maxTimeStep * speed * 2); - if (cursorX < 0) - cursorX = sim.mouseCursorX; - info[ct++] = CircuitElm.getUnitText(maxFrequency*(sim.mouseCursorX-rect.x)/rect.width, "Hz"); - } else if (cursorX < rect.x) - return; - + + // show FFT even if there's no plots (in which case cursorTime/cursorX will be + // invalid) + if (showFFT && cursorScope == this) { + double maxFrequency = 1 / (sim.maxTimeStep * speed * 2); + if (cursorX < 0) + cursorX = sim.mouseCursorX; + info[ct++] = CircuitElm.getUnitText(maxFrequency * (sim.mouseCursorX - rect.x) / rect.width, "Hz"); + } else if (cursorX < rect.x) + return; + if (visiblePlots.size() > 0) info[ct++] = CircuitElm.getTimeText(cursorTime); - + if (cursorScope != this) { // don't show cursor info if not enough room, or stacked with selected one // (position == -1 for embedded scopes) @@ -1320,31 +1354,31 @@ void drawCursor(Graphics g) { } drawCursorInfo(g, info, ct, cursorX, false); } - + void drawCursorInfo(Graphics g, String[] info, int ct, int x, Boolean drawY) { - int szw = 0, szh = 15*ct; + int szw = 0, szh = 15 * ct; int i; for (i = 0; i != ct; i++) { - int w=(int)g.context.measureText(info[i]).getWidth(); + int w = (int) g.context.measureText(info[i]).getWidth(); if (w > szw) szw = w; } g.setColor(CircuitElm.whiteColor); - g.drawLine(x, rect.y, x, rect.y+rect.height); + g.drawLine(x, rect.y, x, rect.y + rect.height); if (drawY) - g.drawLine(rect.x, sim.mouseCursorY, rect.x+rect.width, sim.mouseCursorY); + g.drawLine(rect.x, sim.mouseCursorY, rect.x + rect.width, sim.mouseCursorY); g.setColor(sim.printableCheckItem.getState() ? Color.white : Color.black); int bx = x; - if (bx < szw/2) - bx = szw/2; - g.fillRect(bx-szw/2, rect.y-szh, szw, szh); + if (bx < szw / 2) + bx = szw / 2; + g.fillRect(bx - szw / 2, rect.y - szh, szw, szh); g.setColor(CircuitElm.whiteColor); for (i = 0; i != ct; i++) { - int w=(int)g.context.measureText(info[i]).getWidth(); - g.drawString(info[i], bx-w/2, rect.y-2-(ct-1-i)*15); + int w = (int) g.context.measureText(info[i]).getWidth(); + g.drawString(info[i], bx - w / 2, rect.y - 2 - (ct - 1 - i) * 15); } - + } boolean canShowRMS() { @@ -1353,7 +1387,7 @@ boolean canShowRMS() { ScopePlot plot = visiblePlots.firstElement(); return (plot.units == Scope.UNITS_V || plot.units == Scope.UNITS_A); } - + // calc RMS and display it void drawRMS(Graphics g) { if (!canShowRMS()) { @@ -1366,15 +1400,15 @@ void drawRMS(Graphics g) { ScopePlot plot = visiblePlots.firstElement(); int i; double avg = 0; - int ipa = plot.ptr+scopePointCount-rect.width; - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - double mid = (maxValue+minValue)/2; + int ipa = plot.ptr + scopePointCount - rect.width; + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + double mid = (maxValue + minValue) / 2; int state = -1; - + // skip zeroes for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); + int ip = (i + ipa) & (scopePointCount - 1); if (maxV[ip] != 0) { if (maxV[ip] > mid) state = 1; @@ -1387,19 +1421,19 @@ void drawRMS(Graphics g) { int waveCount = 0; double endAvg = 0; for (; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); + int ip = (i + ipa) & (scopePointCount - 1); boolean sw = false; - + // switching polarity? if (state == 1) { if (maxV[ip] < mid) sw = true; } else if (minV[ip] > mid) sw = true; - + if (sw) { state = -state; - + // completed a full cycle? if (firstState == state) { if (waveCount == 0) { @@ -1413,70 +1447,69 @@ void drawRMS(Graphics g) { } } if (waveCount > 0) { - double m = (maxV[ip]+minV[ip])*.5; - avg += m*m; + double m = (maxV[ip] + minV[ip]) * .5; + avg += m * m; } } double rms; if (waveCount > 1) { - rms = Math.sqrt(endAvg/(end-start)); + rms = Math.sqrt(endAvg / (end - start)); drawInfoText(g, plot.getUnitText(rms) + "rms"); } } - + void drawScale(ScopePlot plot, Graphics g) { - if (!isManualScale()) { - if ( gridStepY!=0 && (!(showV && showI))) { - String vScaleText=" V=" + plot.getUnitText(gridStepY)+"/div"; - drawInfoText(g, "H="+CircuitElm.getUnitText(gridStepX, "s")+"/div" + vScaleText); - } - } else { - if (rect.y + rect.height <= textY+5) - return; - double x = 0; - String hs = "H="+CircuitElm.getUnitText(gridStepX, "s")+"/div"; - g.drawString(hs, 0, textY); - x+=g.measureWidth(hs); - final double bulletWidth = 17; - for (int i=0; i rect.width) { - x=0; - textY += 15; - if (rect.y + rect.height <= textY+5) - return; - } - g.setColor(p.color); - g.fillOval((int)x+7, textY-9, 8, 8); - x+=bulletWidth; - g.setColor(CircuitElm.whiteColor); - g.drawString(vScaleText, (int)x, textY); - x+=vScaleWidth; - } - } - textY += 15; - } - - + if (!isManualScale()) { + if (gridStepY != 0 && (!(showV && showI))) { + String vScaleText = " V=" + plot.getUnitText(gridStepY) + "/div"; + drawInfoText(g, "H=" + CircuitElm.getUnitText(gridStepX, "s") + "/div" + vScaleText); + } + } else { + if (rect.y + rect.height <= textY + 5) + return; + double x = 0; + String hs = "H=" + CircuitElm.getUnitText(gridStepX, "s") + "/div"; + g.drawString(hs, 0, textY); + x += g.measureWidth(hs); + final double bulletWidth = 17; + for (int i = 0; i < visiblePlots.size(); i++) { + ScopePlot p = visiblePlots.get(i); + String s = p.getUnitText(p.manScale); + if (p != null) { + String vScaleText = "=" + s + "/div"; + double vScaleWidth = g.measureWidth(vScaleText); + if (x + bulletWidth + vScaleWidth > rect.width) { + x = 0; + textY += 15; + if (rect.y + rect.height <= textY + 5) + return; + } + g.setColor(p.color); + g.fillOval((int) x + 7, textY - 9, 8, 8); + x += bulletWidth; + g.setColor(CircuitElm.whiteColor); + g.drawString(vScaleText, (int) x, textY); + x += vScaleWidth; + } + } + textY += 15; + } + } - + void drawAverage(Graphics g) { ScopePlot plot = visiblePlots.firstElement(); int i; double avg = 0; - int ipa = plot.ptr+scopePointCount-rect.width; - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - double mid = (maxValue+minValue)/2; + int ipa = plot.ptr + scopePointCount - rect.width; + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + double mid = (maxValue + minValue) / 2; int state = -1; - + // skip zeroes for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); + int ip = (i + ipa) & (scopePointCount - 1); if (maxV[ip] != 0) { if (maxV[ip] > mid) state = 1; @@ -1489,19 +1522,19 @@ void drawAverage(Graphics g) { int waveCount = 0; double endAvg = 0; for (; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); + int ip = (i + ipa) & (scopePointCount - 1); boolean sw = false; - + // switching polarity? if (state == 1) { if (maxV[ip] < mid) sw = true; } else if (minV[ip] > mid) sw = true; - + if (sw) { state = -state; - + // completed a full cycle? if (firstState == state) { if (waveCount == 0) { @@ -1515,12 +1548,12 @@ void drawAverage(Graphics g) { } } if (waveCount > 0) { - double m = (maxV[ip]+minV[ip])*.5; + double m = (maxV[ip] + minV[ip]) * .5; avg += m; } } if (waveCount > 1) { - avg = (endAvg/(end-start)); + avg = (endAvg / (end - start)); drawInfoText(g, plot.getUnitText(avg) + Locale.LS(" average")); } } @@ -1528,15 +1561,15 @@ void drawAverage(Graphics g) { void drawDutyCycle(Graphics g) { ScopePlot plot = visiblePlots.firstElement(); int i; - int ipa = plot.ptr+scopePointCount-rect.width; - double maxV[] = plot.maxValues; - double minV[] = plot.minValues; - double mid = (maxValue+minValue)/2; + int ipa = plot.ptr + scopePointCount - rect.width; + double maxV[] = plot.maxValues; + double minV[] = plot.minValues; + double mid = (maxValue + minValue) / 2; int state = -1; - + // skip zeroes for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); + int ip = (i + ipa) & (scopePointCount - 1); if (maxV[ip] != 0) { if (maxV[ip] > mid) state = 1; @@ -1550,19 +1583,19 @@ void drawDutyCycle(Graphics g) { int dutyLen = 0; int middle = 0; for (; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); + int ip = (i + ipa) & (scopePointCount - 1); boolean sw = false; - + // switching polarity? if (state == 1) { if (maxV[ip] < mid) sw = true; } else if (minV[ip] > mid) sw = true; - + if (sw) { state = -state; - + // completed a full cycle? if (firstState == state) { if (waveCount == 0) { @@ -1570,7 +1603,7 @@ void drawDutyCycle(Graphics g) { } else { end = start; start = i; - dutyLen = end-middle; + dutyLen = end - middle; } waveCount++; } else @@ -1578,7 +1611,7 @@ void drawDutyCycle(Graphics g) { } } if (waveCount > 1) { - int duty = 100*dutyLen/(end-start); + int duty = 100 * dutyLen / (end - start); drawInfoText(g, Locale.LS("Duty cycle ") + duty + "%"); } } @@ -1590,31 +1623,31 @@ void drawFrequency(Graphics g) { double avg = 0; int i; ScopePlot plot = visiblePlots.firstElement(); - int ipa = plot.ptr+scopePointCount-rect.width; - double minV[] = plot.minValues; - double maxV[] = plot.maxValues; + int ipa = plot.ptr + scopePointCount - rect.width; + double minV[] = plot.minValues; + double maxV[] = plot.maxValues; for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); - avg += minV[ip]+maxV[ip]; + int ip = (i + ipa) & (scopePointCount - 1); + avg += minV[ip] + maxV[ip]; } - avg /= i*2; + avg /= i * 2; int state = 0; - double thresh = avg*.05; + double thresh = avg * .05; int oi = 0; double avperiod = 0; int periodct = -1; double avperiod2 = 0; // count period lengths for (i = 0; i != rect.width; i++) { - int ip = (i+ipa) & (scopePointCount-1); - double q = maxV[ip]-avg; + int ip = (i + ipa) & (scopePointCount - 1); + double q = maxV[ip] - avg; int os = state; if (q < thresh) state = 1; else if (q > -thresh) state = 2; if (state == 2 && os == 1) { - int pd = i-oi; + int pd = i - oi; oi = i; // short periods can't be counted properly if (pd < 12) @@ -1622,15 +1655,15 @@ else if (q > -thresh) // skip first period, it might be too short if (periodct >= 0) { avperiod += pd; - avperiod2 += pd*pd; + avperiod2 += pd * pd; } periodct++; } } avperiod /= periodct; avperiod2 /= periodct; - double periodstd = Math.sqrt(avperiod2-avperiod*avperiod); - double freq = 1/(avperiod*sim.maxTimeStep*speed); + double periodstd = Math.sqrt(avperiod2 - avperiod * avperiod); + double freq = 1 / (avperiod * sim.maxTimeStep * speed); // don't show freq if standard deviation is too great if (periodct < 1 || periodstd > 2) freq = 0; @@ -1646,71 +1679,71 @@ void drawElmInfo(Graphics g) { for (i = 0; info[i] != null; i++) drawInfoText(g, info[i]); } - + int textY; - + void drawInfoText(Graphics g, String text) { - if (rect.y + rect.height <= textY+5) + if (rect.y + rect.height <= textY + 5) return; g.drawString(text, 0, textY); textY += 15; } - + void drawInfoTexts(Graphics g) { - g.setColor(CircuitElm.whiteColor); - textY = 10; - - if (visiblePlots.size() == 0) { - if (showElmInfo) - drawElmInfo(g); - return; - } - ScopePlot plot = visiblePlots.firstElement(); - if (showScale) - drawScale(plot, g); -// if (showMax || showMin) -// calcMaxAndMin(plot.units); - if (showMax) - drawInfoText(g, "Max="+plot.getUnitText(maxValue)); - if (showMin) { - int ym=rect.height-5; - g.drawString("Min="+plot.getUnitText(minValue), 0, ym); - } - if (showRMS) - drawRMS(g); - if (showAverage) - drawAverage(g); - if (showDutyCycle) - drawDutyCycle(g); - String t = getScopeLabelOrText(true); - if (t != null && t!= "") - drawInfoText(g, t); - if (showFreq) - drawFrequency(g); - if (showElmInfo) - drawElmInfo(g); + g.setColor(CircuitElm.whiteColor); + textY = 10; + + if (visiblePlots.size() == 0) { + if (showElmInfo) + drawElmInfo(g); + return; + } + ScopePlot plot = visiblePlots.firstElement(); + if (showScale) + drawScale(plot, g); + // if (showMax || showMin) + // calcMaxAndMin(plot.units); + if (showMax) + drawInfoText(g, "Max=" + plot.getUnitText(maxValue)); + if (showMin) { + int ym = rect.height - 5; + g.drawString("Min=" + plot.getUnitText(minValue), 0, ym); + } + if (showRMS) + drawRMS(g); + if (showAverage) + drawAverage(g); + if (showDutyCycle) + drawDutyCycle(g); + String t = getScopeLabelOrText(true); + if (t != null && t != "") + drawInfoText(g, t); + if (showFreq) + drawFrequency(g); + if (showElmInfo) + drawElmInfo(g); } String getScopeText() { - // stacked scopes? don't show text + // stacked scopes? don't show text if (stackCount != 1) return null; - - // multiple elms? don't show text (unless one is selected) + + // multiple elms? don't show text (unless one is selected) if (selectedPlot < 0 && getSingleElm() == null) return null; - + // no visible plots? if (visiblePlots.size() == 0) return null; - + ScopePlot plot = visiblePlots.firstElement(); if (selectedPlot >= 0 && visiblePlots.size() > selectedPlot) plot = visiblePlots.get(selectedPlot); if (plot.elm == null) - return ""; + return ""; else - return plot.elm.getScopeText(plot.value); + return plot.elm.getScopeText(plot.value); } String getScopeLabelOrText() { @@ -1718,21 +1751,22 @@ String getScopeLabelOrText() { } String getScopeLabelOrText(boolean forInfo) { - String t = text; - if (t == null) { - // if we're drawing the info and showElmInfo is true, return null so we don't print redundant info. - // But don't do that if we're getting the scope label to generate "Add to Existing Scope" menu. - if (forInfo && showElmInfo) - return null; - t = getScopeText(); - if (t==null) - return ""; - return Locale.LS(t); - } - else - return t; + String t = text; + if (t == null) { + // if we're drawing the info and showElmInfo is true, return null so we don't + // print redundant info. + // But don't do that if we're getting the scope label to generate "Add to + // Existing Scope" menu. + if (forInfo && showElmInfo) + return null; + t = getScopeText(); + if (t == null) + return ""; + return Locale.LS(t); + } else + return t; } - + void setSpeed(int sp) { if (sp < 1) sp = 1; @@ -1741,12 +1775,12 @@ void setSpeed(int sp) { speed = sp; resetGraph(); } - + void properties() { properties = new ScopePropertiesDialog(sim, this); CirSim.dialogShowing = properties; } - + void speedUp() { if (speed > 1) { speed /= 2; @@ -1757,13 +1791,13 @@ void speedUp() { void slowDown() { if (speed < 1024) speed *= 2; - resetGraph(); + resetGraph(); } - + void setPlotPosition(int plot, int v) { visiblePlots.get(plot).manVPosition = v; } - + // get scope element, returning null if there's more than one CircuitElm getSingleElm() { CircuitElm elm = plots.get(0).elm; @@ -1774,229 +1808,222 @@ CircuitElm getSingleElm() { } return elm; } - + boolean canMenu() { - return (plots.get(0).elm != null); + return (plots.get(0).elm != null); } - + boolean canShowResistance() { - CircuitElm elm = getSingleElm(); - return elm != null && elm.canShowValueInScope(VAL_R); + CircuitElm elm = getSingleElm(); + return elm != null && elm.canShowValueInScope(VAL_R); } - + boolean isShowingVceAndIc() { return plot2d && plots.size() == 2 && plots.get(0).value == VAL_VCE && plots.get(1).value == VAL_IC; } int getFlags() { - int flags = (showI ? 1 : 0) | (showV ? 2 : 0) | - (showMax ? 0 : 4) | // showMax used to be always on - (showFreq ? 8 : 0) | - // In this version we always dump manual settings using the PERPLOT format - (isManualScale() ? (FLAG_MAN_SCALE | FLAG_PERPLOT_MAN_SCALE): 0) | - (plot2d ? 64 : 0) | - (plotXY ? 128 : 0) | (showMin ? 256 : 0) | (showScale? 512:0) | - (showFFT ? 1024 : 0) | (maxScale ? 8192 : 0) | (showRMS ? 16384 : 0) | - (showDutyCycle ? 32768 : 0) | (logSpectrum ? 65536 : 0) | - (showAverage ? (1<<17) : 0) | (showElmInfo ? (1<<20) : 0); + int flags = (showI ? 1 : 0) | (showV ? 2 : 0) | (showMax ? 0 : 4) | // showMax used to be always on + (showFreq ? 8 : 0) | + // In this version we always dump manual settings using the PERPLOT format + (isManualScale() ? (FLAG_MAN_SCALE | FLAG_PERPLOT_MAN_SCALE) : 0) | (plot2d ? 64 : 0) + | (plotXY ? 128 : 0) | (showMin ? 256 : 0) | (showScale ? 512 : 0) | (showFFT ? 1024 : 0) + | (maxScale ? 8192 : 0) | (showRMS ? 16384 : 0) | (showDutyCycle ? 32768 : 0) + | (logSpectrum ? 65536 : 0) | (showAverage ? (1 << 17) : 0) | (showElmInfo ? (1 << 20) : 0); flags |= FLAG_PLOTS; // 4096 int allPlotFlags = 0; for (ScopePlot p : plots) { allPlotFlags |= p.getPlotFlags(); - + } - // If none of our plots has a flag set we will use the old format with no plot flags, or + // If none of our plots has a flag set we will use the old format with no plot + // flags, or // else we will set FLAG_PLOTFLAGS and include flags in all plots - flags |= (allPlotFlags !=0) ? FLAG_PERPLOTFLAGS :0; // (1<<18) + flags |= (allPlotFlags != 0) ? FLAG_PERPLOTFLAGS : 0; // (1<<18) return flags; } - - String dump() { ScopePlot vPlot = plots.get(0); - + CircuitElm elm = vPlot.elm; - if (elm == null) - return null; - int flags = getFlags(); - int eno = sim.locateElm(elm); - if (eno < 0) - return null; - String x = "o " + eno + " " + - vPlot.scopePlotSpeed + " " + vPlot.value + " " - + exportAsDecOrHex(flags, FLAG_PERPLOTFLAGS) + " " + - scale[UNITS_V] + " " + scale[UNITS_A] + " " + position + " " + - plots.size(); - int i; - for (i = 0; i < plots.size(); i++) { - ScopePlot p = plots.get(i); - if ((flags & FLAG_PERPLOTFLAGS) !=0) - x += " " + Integer.toHexString(p.getPlotFlags()); // NB always export in Hex (no prefix) - if (i > 0) - x += " " + sim.locateElm(p.elm) + " " + p.value; - // dump scale if units are not V or A - if (p.units > UNITS_A) - x += " " + scale[p.units]; - if (isManualScale()) {// In this version we always dump manual settings using the PERPLOT format - x += " " + p.manScale + " " - + p.manVPosition; - } - } - if (text != null) - x += " " + CustomLogicModel.escape(text); - return x; + if (elm == null) + return null; + int flags = getFlags(); + int eno = sim.locateElm(elm); + if (eno < 0) + return null; + String x = "o " + eno + " " + vPlot.scopePlotSpeed + " " + vPlot.value + " " + + exportAsDecOrHex(flags, FLAG_PERPLOTFLAGS) + " " + scale[UNITS_V] + " " + scale[UNITS_A] + " " + + position + " " + plots.size(); + int i; + for (i = 0; i < plots.size(); i++) { + ScopePlot p = plots.get(i); + if ((flags & FLAG_PERPLOTFLAGS) != 0) + x += " " + Integer.toHexString(p.getPlotFlags()); // NB always export in Hex (no prefix) + if (i > 0) + x += " " + sim.locateElm(p.elm) + " " + p.value; + // dump scale if units are not V or A + if (p.units > UNITS_A) + x += " " + scale[p.units]; + if (isManualScale()) {// In this version we always dump manual settings using the PERPLOT format + x += " " + p.manScale + " " + p.manVPosition; + } + } + if (text != null) + x += " " + CustomLogicModel.escape(text); + return x; } - + void undump(StringTokenizer st) { - initialize(); - int e = new Integer(st.nextToken()).intValue(); - if (e == -1) - return; - CircuitElm ce = sim.getElm(e); - setElm(ce); - speed = new Integer(st.nextToken()).intValue(); - int value = new Integer(st.nextToken()).intValue(); - - // fix old value for VAL_POWER which doesn't work for transistors (because it's the same as VAL_IB) - if (!(ce instanceof TransistorElm) && value == VAL_POWER_OLD) - value = VAL_POWER; - - int flags = importDecOrHex(st.nextToken()); - scale[UNITS_V] = new Double(st.nextToken()).doubleValue(); - scale[UNITS_A] = new Double(st.nextToken()).doubleValue(); - if (scale[UNITS_V] == 0) - scale[UNITS_V] = .5; - if (scale[UNITS_A] == 0) - scale[UNITS_A] = 1; - scaleX = scale[UNITS_V]; - scaleY = scale[UNITS_A]; - scale[UNITS_OHMS] = scale[UNITS_W] = scale[UNITS_V]; - text = null; - boolean plot2dFlag = (flags & 64) != 0; - boolean hasPlotFlags = (flags & FLAG_PERPLOTFLAGS) != 0; - if ((flags & FLAG_PLOTS) != 0) { - // new-style dump - try { - position = Integer.parseInt(st.nextToken()); - int sz = Integer.parseInt(st.nextToken()); - int i; - int u = ce.getScopeUnits(value); + initialize(); + int e = Integer.valueOf(st.nextToken()).intValue(); + if (e == -1) + return; + CircuitElm ce = sim.getElm(e); + setElm(ce); + speed = Integer.valueOf(st.nextToken()).intValue(); + int value = Integer.valueOf(st.nextToken()).intValue(); + + // fix old value for VAL_POWER which doesn't work for transistors (because it's + // the same as VAL_IB) + if (!(ce instanceof TransistorElm) && value == VAL_POWER_OLD) + value = VAL_POWER; + + int flags = importDecOrHex(st.nextToken()); + scale[UNITS_V] = Double.valueOf(st.nextToken()).doubleValue(); + scale[UNITS_A] = Double.valueOf(st.nextToken()).doubleValue(); + if (scale[UNITS_V] == 0) + scale[UNITS_V] = .5; + if (scale[UNITS_A] == 0) + scale[UNITS_A] = 1; + scaleX = scale[UNITS_V]; + scaleY = scale[UNITS_A]; + scale[UNITS_OHMS] = scale[UNITS_W] = scale[UNITS_V]; + text = null; + boolean plot2dFlag = (flags & 64) != 0; + boolean hasPlotFlags = (flags & FLAG_PERPLOTFLAGS) != 0; + if ((flags & FLAG_PLOTS) != 0) { + // new-style dump + try { + position = Integer.parseInt(st.nextToken()); + int sz = Integer.parseInt(st.nextToken()); + int i; + int u = ce.getScopeUnits(value); if (u > UNITS_A) scale[u] = Double.parseDouble(st.nextToken()); - setValue(value); - // setValue(0) creates an extra plot for current, so remove that - while (plots.size() > 1) - plots.removeElementAt(1); - - - int plotFlags = 0; - for (i = 0; i != sz; i++) { - if (hasPlotFlags) - plotFlags=Integer.parseInt(st.nextToken(), 16); // Import in hex (no prefix) - if (i!=0) { - int ne = Integer.parseInt(st.nextToken()); - int val = Integer.parseInt(st.nextToken()); - CircuitElm elm = sim.getElm(ne); - u = elm.getScopeUnits(val); - if (u > UNITS_A) - scale[u] = Double.parseDouble(st.nextToken()); - plots.add(new ScopePlot(elm, u, val, getManScaleFromMaxScale(u, false))); - } - ScopePlot p = plots.get(i); - p.acCoupled = (plotFlags & ScopePlot.FLAG_AC) != 0; - if ( (flags & FLAG_PERPLOT_MAN_SCALE) != 0) { - p.manScaleSet = true; - p.manScale=Double.parseDouble(st.nextToken()); - p.manVPosition=Integer.parseInt(st.nextToken()); - } - } - while (st.hasMoreTokens()) { - if (text == null) - text = st.nextToken(); - else - text += " " + st.nextToken(); - } - } catch (Exception ee) { - } - } else { - // old-style dump - CircuitElm yElm = null; - int ivalue = 0; - try { - position = new Integer(st.nextToken()).intValue(); - int ye = -1; - if ((flags & FLAG_YELM) != 0) { - ye = new Integer(st.nextToken()).intValue(); - if (ye != -1) - yElm = sim.getElm(ye); - // sinediode.txt has yElm set to something even though there's no xy plot...? - if (!plot2dFlag) - yElm = null; - } - if ((flags & FLAG_IVALUE) !=0) { - ivalue = new Integer(st.nextToken()).intValue(); - } - while (st.hasMoreTokens()) { - if (text == null) - text = st.nextToken(); - else - text += " " + st.nextToken(); - } - } catch (Exception ee) { - } - setValues(value, ivalue, sim.getElm(e), yElm); - } - if (text != null) - text = CustomLogicModel.unescape(text); - plot2d = plot2dFlag; - setFlags(flags); + setValue(value); + // setValue(0) creates an extra plot for current, so remove that + while (plots.size() > 1) + plots.removeElementAt(1); + + int plotFlags = 0; + for (i = 0; i != sz; i++) { + if (hasPlotFlags) + plotFlags = Integer.parseInt(st.nextToken(), 16); // Import in hex (no prefix) + if (i != 0) { + int ne = Integer.parseInt(st.nextToken()); + int val = Integer.parseInt(st.nextToken()); + CircuitElm elm = sim.getElm(ne); + u = elm.getScopeUnits(val); + if (u > UNITS_A) + scale[u] = Double.parseDouble(st.nextToken()); + plots.add(new ScopePlot(elm, u, val, getManScaleFromMaxScale(u, false))); + } + ScopePlot p = plots.get(i); + p.acCoupled = (plotFlags & ScopePlot.FLAG_AC) != 0; + if ((flags & FLAG_PERPLOT_MAN_SCALE) != 0) { + p.manScaleSet = true; + p.manScale = Double.parseDouble(st.nextToken()); + p.manVPosition = Integer.parseInt(st.nextToken()); + } + } + while (st.hasMoreTokens()) { + if (text == null) + text = st.nextToken(); + else + text += " " + st.nextToken(); + } + } catch (Exception ee) { + } + } else { + // old-style dump + CircuitElm yElm = null; + int ivalue = 0; + try { + position = Integer.valueOf(st.nextToken()).intValue(); + int ye = -1; + if ((flags & FLAG_YELM) != 0) { + ye = Integer.valueOf(st.nextToken()).intValue(); + if (ye != -1) + yElm = sim.getElm(ye); + // sinediode.txt has yElm set to something even though there's no xy plot...? + if (!plot2dFlag) + yElm = null; + } + if ((flags & FLAG_IVALUE) != 0) { + ivalue = Integer.valueOf(st.nextToken()).intValue(); + } + while (st.hasMoreTokens()) { + if (text == null) + text = st.nextToken(); + else + text += " " + st.nextToken(); + } + } catch (Exception ee) { + } + setValues(value, ivalue, sim.getElm(e), yElm); + } + if (text != null) + text = CustomLogicModel.unescape(text); + plot2d = plot2dFlag; + setFlags(flags); } - + void setFlags(int flags) { - showI = (flags & 1) != 0; - showV = (flags & 2) != 0; - showMax = (flags & 4) == 0; - showFreq = (flags & 8) != 0; - manualScale = (flags & FLAG_MAN_SCALE) != 0; - plotXY = (flags & 128) != 0; - showMin = (flags & 256) != 0; - showScale = (flags & 512) !=0; - showFFT((flags & 1024) != 0); - maxScale = (flags & 8192) != 0; - showRMS = (flags & 16384) != 0; - showDutyCycle = (flags & 32768) != 0; - logSpectrum = (flags & 65536) != 0; - showAverage = (flags & (1<<17)) != 0; - showElmInfo = (flags & (1<<20)) != 0; + showI = (flags & 1) != 0; + showV = (flags & 2) != 0; + showMax = (flags & 4) == 0; + showFreq = (flags & 8) != 0; + manualScale = (flags & FLAG_MAN_SCALE) != 0; + plotXY = (flags & 128) != 0; + showMin = (flags & 256) != 0; + showScale = (flags & 512) != 0; + showFFT((flags & 1024) != 0); + maxScale = (flags & 8192) != 0; + showRMS = (flags & 16384) != 0; + showDutyCycle = (flags & 32768) != 0; + logSpectrum = (flags & 65536) != 0; + showAverage = (flags & (1 << 17)) != 0; + showElmInfo = (flags & (1 << 20)) != 0; } - + void saveAsDefault() { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return; + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return; ScopePlot vPlot = plots.get(0); - int flags = getFlags(); - - // store current scope settings as default. 1 is a version code - stor.setItem("scopeDefaults", "1 " + flags + " " + vPlot.scopePlotSpeed); - CirSim.console("saved defaults " + flags); + int flags = getFlags(); + + // store current scope settings as default. 1 is a version code + stor.setItem("scopeDefaults", "1 " + flags + " " + vPlot.scopePlotSpeed); + CirSim.console("saved defaults " + flags); } boolean loadDefaults() { - Storage stor = Storage.getLocalStorageIfSupported(); - if (stor == null) - return false; - String str = stor.getItem("scopeDefaults"); - if (str == null) - return false; - String arr[] = str.split(" "); - int flags = Integer.parseInt(arr[1]); - setFlags(flags); - speed = Integer.parseInt(arr[2]); - return true; + Storage stor = Storage.getLocalStorageIfSupported(); + if (stor == null) + return false; + String str = stor.getItem("scopeDefaults"); + if (str == null) + return false; + String arr[] = str.split(" "); + int flags = Integer.parseInt(arr[1]); + setFlags(flags); + speed = Integer.parseInt(arr[2]); + return true; } - + void allocImage() { if (imageCanvas != null) { imageCanvas.setWidth(rect.width + "PX"); @@ -2006,120 +2033,119 @@ void allocImage() { clear2dView(); } } - + void handleMenu(String mi, boolean state) { if (mi == "maxscale") - maxScale(); - if (mi == "showvoltage") - showVoltage(state); - if (mi == "showcurrent") - showCurrent(state); - if (mi=="showscale") - showScale(state); - if (mi == "showpeak") - showMax(state); - if (mi == "shownegpeak") - showMin(state); - if (mi == "showfreq") - showFreq(state); - if (mi == "showfft") - showFFT(state); - if (mi == "logspectrum") - logSpectrum = state; - if (mi == "showrms") - showRMS = state; - if (mi == "showaverage") - showAverage = state; - if (mi == "showduty") - showDutyCycle = state; - if (mi == "showelminfo") - showElmInfo = state; - if (mi == "showpower") - setValue(VAL_POWER); - if (mi == "showib") - setValue(VAL_IB); - if (mi == "showic") - setValue(VAL_IC); - if (mi == "showie") - setValue(VAL_IE); - if (mi == "showvbe") - setValue(VAL_VBE); - if (mi == "showvbc") - setValue(VAL_VBC); - if (mi == "showvce") - setValue(VAL_VCE); - if (mi == "showvcevsic") { - plot2d = true; - plotXY = false; - setValues(VAL_VCE, VAL_IC, getElm(), null); - resetGraph(); - } - - if (mi == "showvvsi") { - plot2d = state; - plotXY = false; - resetGraph(); - } - if (mi == "manualscale") - setManualScale(state, true); - if (mi == "plotxy") { - plotXY = plot2d = state; - if (plot2d) - plots = visiblePlots; - if (plot2d && plots.size() == 1) - selectY(); - resetGraph(); - } - if (mi == "showresistance") - setValue(VAL_R); - } - -// void select() { -// sim.setMouseElm(elm); -// if (plotXY) { -// sim.plotXElm = elm; -// sim.plotYElm = yElm; -// } -// } + maxScale(); + if (mi == "showvoltage") + showVoltage(state); + if (mi == "showcurrent") + showCurrent(state); + if (mi == "showscale") + showScale(state); + if (mi == "showpeak") + showMax(state); + if (mi == "shownegpeak") + showMin(state); + if (mi == "showfreq") + showFreq(state); + if (mi == "showfft") + showFFT(state); + if (mi == "logspectrum") + logSpectrum = state; + if (mi == "showrms") + showRMS = state; + if (mi == "showaverage") + showAverage = state; + if (mi == "showduty") + showDutyCycle = state; + if (mi == "showelminfo") + showElmInfo = state; + if (mi == "showpower") + setValue(VAL_POWER); + if (mi == "showib") + setValue(VAL_IB); + if (mi == "showic") + setValue(VAL_IC); + if (mi == "showie") + setValue(VAL_IE); + if (mi == "showvbe") + setValue(VAL_VBE); + if (mi == "showvbc") + setValue(VAL_VBC); + if (mi == "showvce") + setValue(VAL_VCE); + if (mi == "showvcevsic") { + plot2d = true; + plotXY = false; + setValues(VAL_VCE, VAL_IC, getElm(), null); + resetGraph(); + } + + if (mi == "showvvsi") { + plot2d = state; + plotXY = false; + resetGraph(); + } + if (mi == "manualscale") + setManualScale(state, true); + if (mi == "plotxy") { + plotXY = plot2d = state; + if (plot2d) + plots = visiblePlots; + if (plot2d && plots.size() == 1) + selectY(); + resetGraph(); + } + if (mi == "showresistance") + setValue(VAL_R); + } + + // void select() { + // sim.setMouseElm(elm); + // if (plotXY) { + // sim.plotXElm = elm; + // sim.plotYElm = yElm; + // } + // } void selectY() { CircuitElm yElm = (plots.size() == 2) ? plots.get(1).elm : null; - int e = (yElm == null) ? -1 : sim.locateElm(yElm); - int firstE = e; - while (true) { - for (e++; e < sim.elmList.size(); e++) { - CircuitElm ce = sim.getElm(e); - if ((ce instanceof OutputElm || ce instanceof ProbeElm) && - ce != plots.get(0).elm) { - yElm = ce; - if (plots.size() == 1) - plots.add(new ScopePlot(yElm, UNITS_V)); - else { - plots.get(1).elm = yElm; - plots.get(1).units = UNITS_V; - } - return; - } - } - if (firstE == -1) - return; - e = firstE = -1; - } - // not reached + int e = (yElm == null) ? -1 : sim.locateElm(yElm); + int firstE = e; + while (true) { + for (e++; e < sim.elmList.size(); e++) { + CircuitElm ce = sim.getElm(e); + if ((ce instanceof OutputElm || ce instanceof ProbeElm) && ce != plots.get(0).elm) { + yElm = ce; + if (plots.size() == 1) + plots.add(new ScopePlot(yElm, UNITS_V)); + else { + plots.get(1).elm = yElm; + plots.get(1).units = UNITS_V; + } + return; + } + } + if (firstE == -1) + return; + e = firstE = -1; + } + // not reached } - + void onMouseWheel(MouseWheelEvent e) { - wheelDeltaY += e.getDeltaY(); - if (wheelDeltaY > 5) { - slowDown(); - wheelDeltaY = 0; - } - if (wheelDeltaY < -5) { - speedUp(); - wheelDeltaY = 0; - } + wheelDeltaY += e.getDeltaY(); + if (wheelDeltaY > 5) { + slowDown(); + wheelDeltaY = 0; + } + if (wheelDeltaY < -5) { + speedUp(); + wheelDeltaY = 0; + } } - + CircuitElm getElm() { if (selectedPlot >= 0 && visiblePlots.size() > selectedPlot) return visiblePlots.get(selectedPlot).elm; @@ -2133,27 +2159,28 @@ boolean viewingWire() { return true; return false; } - + CircuitElm getXElm() { return getElm(); } + CircuitElm getYElm() { if (plots.size() == 2) return plots.get(1).elm; return null; } - + boolean needToRemove() { boolean ret = true; boolean removed = false; int i; for (i = 0; i != plots.size(); i++) { - ScopePlot plot = plots.get(i); - if (sim.locateElm(plot.elm) < 0) { - plots.remove(i--); - removed = true; - } else - ret = false; + ScopePlot plot = plots.get(i); + if (sim.locateElm(plot.elm) < 0) { + plots.remove(i--); + removed = true; + } else + ret = false; } if (removed) calcVisiblePlots(); @@ -2163,29 +2190,33 @@ boolean needToRemove() { public boolean isManualScale() { return manualScale; } - + public double getManScaleFromMaxScale(int units, boolean roundUp) { - // When the user manually switches to manual scale (and we don't already have a setting) then - // call with "roundUp=true" to get a "sensible" suggestion for the scale. When importing from - // a legacy file then call with "roundUp=false" to stay as close as possible to the old presentation - double s =scale[units]; - if ( units > UNITS_A) - s = 0.5*s; + // When the user manually switches to manual scale (and we don't already have a + // setting) then + // call with "roundUp=true" to get a "sensible" suggestion for the scale. When + // importing from + // a legacy file then call with "roundUp=false" to stay as close as possible to + // the old presentation + double s = scale[units]; + if (units > UNITS_A) + s = 0.5 * s; if (roundUp) - return ScopePropertiesDialog.nextHighestScale((2*s)/(double)(manDivisions)); - else - return (2*s)/(double)(manDivisions); + return ScopePropertiesDialog.nextHighestScale((2 * s) / (double) (manDivisions)); + else + return (2 * s) / (double) (manDivisions); } - + static String exportAsDecOrHex(int v, int thresh) { // If v>=thresh then export as hex value prefixed by "x", else export as decimal - // Allows flags to be exported as dec if in an old value (for compatibility) or in hex if new value - if (v>=thresh) - return "x"+Integer.toHexString(v); + // Allows flags to be exported as dec if in an old value (for compatibility) or + // in hex if new value + if (v >= thresh) + return "x" + Integer.toHexString(v); else return Integer.toString(v); } - + static int importDecOrHex(String s) { if (s.charAt(0) == 'x') return Integer.parseInt(s.substring(1), 16); diff --git a/src/com/lushprojects/circuitjs1/client/ScopeElm.java b/src/com/lushprojects/circuitjs1/client/ScopeElm.java index 0521a270..0b1f059d 100644 --- a/src/com/lushprojects/circuitjs1/client/ScopeElm.java +++ b/src/com/lushprojects/circuitjs1/client/ScopeElm.java @@ -20,27 +20,26 @@ package com.lushprojects.circuitjs1.client; class ScopeElm extends CircuitElm { - + Scope elmScope; public ScopeElm(int xx, int yy) { super(xx, yy); - noDiagonal=false; - x2=x+128; - y2=y+64; + noDiagonal = false; + x2 = x + 128; + y2 = y + 64; elmScope = new Scope(sim); setPoints(); } - + public void setScopeElm(CircuitElm e) { elmScope.setElm(e); elmScope.resetGraph(); } - - public ScopeElm(int xa, int ya, int xb, int yb, int f, - StringTokenizer st) { + + public ScopeElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) { super(xa, ya, xb, yb, f); - noDiagonal=false; + noDiagonal = false; String sStr = st.nextToken(); StringTokenizer sst = new StringTokenizer(sStr, "_"); elmScope = new Scope(sim); @@ -48,43 +47,46 @@ public ScopeElm(int xa, int ya, int xb, int yb, int f, setPoints(); elmScope.resetGraph(); } - + public void setScopeRect() { - int i1 = sim.transformX(min(x,x2)); - int i2 = sim.transformX(max(x,x2)); - int j1 = sim.transformY(min(y,y2)); - int j2 = sim.transformY(max(y,y2)); - Rectangle r = new Rectangle(i1,j1,i2-i1, j2-j1); + int i1 = sim.transformX(min(x, x2)); + int i2 = sim.transformX(max(x, x2)); + int j1 = sim.transformY(min(y, y2)); + int j2 = sim.transformY(max(y, y2)); + Rectangle r = new Rectangle(i1, j1, i2 - i1, j2 - j1); if (!r.equals(elmScope.rect)) elmScope.setRect(r); } - + public void setPoints() { super.setPoints(); setScopeRect(); } - - public void setElmScope( Scope s) { - elmScope=s; + + public void setElmScope(Scope s) { + elmScope = s; } - - + public void stepScope() { elmScope.timeStep(); } - + public void reset() { super.reset(); elmScope.resetGraph(true); } - + public void clearElmScope() { elmScope = null; } - - boolean canViewInScope() { return false; } - - int getDumpType() { return 403; } + + boolean canViewInScope() { + return false; + } + + int getDumpType() { + return 403; + } public String dump() { String dumpStr = super.dump(); @@ -95,7 +97,7 @@ public String dump() { sStr = sStr.replaceFirst("o_", ""); // remove unused prefix for embedded Scope return dumpStr + " " + sStr; } - + void draw(Graphics g) { g.setColor(needsHighlight() ? selectColor : whiteColor); g.context.save(); @@ -108,9 +110,16 @@ void draw(Graphics g) { drawPosts(g); } - - int getPostCount() { return 0; } - int getNumHandles() { return 2; } - - void selectScope(int mx, int my) { elmScope.selectScope(mx, my); } + + int getPostCount() { + return 0; + } + + int getNumHandles() { + return 2; + } + + void selectScope(int mx, int my) { + elmScope.selectScope(mx, my); + } } diff --git a/src/com/lushprojects/circuitjs1/client/ScopePopupMenu.java b/src/com/lushprojects/circuitjs1/client/ScopePopupMenu.java index 1d7a72be..61df9c1e 100644 --- a/src/com/lushprojects/circuitjs1/client/ScopePopupMenu.java +++ b/src/com/lushprojects/circuitjs1/client/ScopePopupMenu.java @@ -24,7 +24,7 @@ import com.lushprojects.circuitjs1.client.util.Locale; public class ScopePopupMenu { - + private MenuBar m; private MenuItem removeScopeItem; private CheckboxMenuItem maxScaleItem; @@ -36,22 +36,28 @@ public class ScopePopupMenu { private MenuItem propertiesItem; private MenuItem dockItem; private MenuItem undockItem; - + ScopePopupMenu() { - m = new MenuBar(true); - m.addItem(removeScopeItem = new CheckboxAlignedMenuItem(Locale.LS("Remove Scope"),new MyCommand("scopepop", "remove"))); - m.addItem(dockItem = new CheckboxAlignedMenuItem(Locale.LS("Dock Scope"),new MyCommand("scopepop", "dock"))); - m.addItem(undockItem = new CheckboxAlignedMenuItem(Locale.LS("Undock Scope"),new MyCommand("scopepop", "undock"))); - m.addItem(maxScaleItem = new CheckboxMenuItem(Locale.LS("Max Scale"), new MyCommand("scopepop", "maxscale"))); - m.addItem(stackItem = new CheckboxAlignedMenuItem(Locale.LS("Stack"), new MyCommand("scopepop", "stack"))); - m.addItem(unstackItem = new CheckboxAlignedMenuItem(Locale.LS("Unstack"), new MyCommand("scopepop", "unstack"))); - m.addItem(combineItem = new CheckboxAlignedMenuItem(Locale.LS("Combine"), new MyCommand("scopepop", "combine"))); - m.addItem(removePlotItem = new CheckboxAlignedMenuItem(Locale.LS("Remove Plot"),new MyCommand("scopepop", "removeplot"))); - m.addItem(resetItem = new CheckboxAlignedMenuItem(Locale.LS("Reset"), new MyCommand("scopepop", "reset"))); - m.addItem(propertiesItem = new CheckboxAlignedMenuItem(Locale.LS("Properties..."), new MyCommand("scopepop", "properties"))); + m = new MenuBar(true); + m.addItem(removeScopeItem = new CheckboxAlignedMenuItem(Locale.LS("Remove Scope"), + new MyCommand("scopepop", "remove"))); + m.addItem(dockItem = new CheckboxAlignedMenuItem(Locale.LS("Dock Scope"), new MyCommand("scopepop", "dock"))); + m.addItem(undockItem = new CheckboxAlignedMenuItem(Locale.LS("Undock Scope"), + new MyCommand("scopepop", "undock"))); + m.addItem(maxScaleItem = new CheckboxMenuItem(Locale.LS("Max Scale"), new MyCommand("scopepop", "maxscale"))); + m.addItem(stackItem = new CheckboxAlignedMenuItem(Locale.LS("Stack"), new MyCommand("scopepop", "stack"))); + m.addItem( + unstackItem = new CheckboxAlignedMenuItem(Locale.LS("Unstack"), new MyCommand("scopepop", "unstack"))); + m.addItem( + combineItem = new CheckboxAlignedMenuItem(Locale.LS("Combine"), new MyCommand("scopepop", "combine"))); + m.addItem(removePlotItem = new CheckboxAlignedMenuItem(Locale.LS("Remove Plot"), + new MyCommand("scopepop", "removeplot"))); + m.addItem(resetItem = new CheckboxAlignedMenuItem(Locale.LS("Reset"), new MyCommand("scopepop", "reset"))); + m.addItem(propertiesItem = new CheckboxAlignedMenuItem(Locale.LS("Properties..."), + new MyCommand("scopepop", "properties"))); } - - void doScopePopupChecks( boolean floating, boolean canstack, boolean cancombine, boolean canunstack, Scope s) { + + void doScopePopupChecks(boolean floating, boolean canstack, boolean cancombine, boolean canunstack, Scope s) { maxScaleItem.setState(s.maxScale); stackItem.setVisible(!floating); stackItem.setEnabled(canstack); @@ -62,8 +68,7 @@ void doScopePopupChecks( boolean floating, boolean canstack, boolean cancombine, dockItem.setVisible(floating); undockItem.setVisible(!floating); } - - + public MenuBar getMenuBar() { return m; } diff --git a/src/com/lushprojects/circuitjs1/client/ScopePropertiesDialog.java b/src/com/lushprojects/circuitjs1/client/ScopePropertiesDialog.java index a06c9b54..0c7d4a99 100644 --- a/src/com/lushprojects/circuitjs1/client/ScopePropertiesDialog.java +++ b/src/com/lushprojects/circuitjs1/client/ScopePropertiesDialog.java @@ -27,12 +27,12 @@ class ScopeCheckBox extends CheckBox { String menuCmd; - + ScopeCheckBox(String text, String menu) { super(text); menuCmd = menu; } - + void setValue(boolean x) { if (getValue() == x) return; @@ -40,34 +40,32 @@ void setValue(boolean x) { } } - - public class ScopePropertiesDialog extends Dialog implements ValueChangeHandler { - -Panel fp, channelButtonsp, channelSettingsp; -HorizontalPanel hp; -HorizontalPanel vModep; -CirSim sim; -//RichTextArea textBox; -TextArea textArea; -RadioButton autoButton, maxButton, manualButton; -RadioButton acButton, dcButton; -CheckBox scaleBox, voltageBox, currentBox, powerBox, peakBox, negPeakBox, freqBox, spectrumBox, manualScaleBox; -CheckBox rmsBox, dutyBox, viBox, xyBox, resistanceBox, ibBox, icBox, ieBox, vbeBox, vbcBox, vceBox, vceIcBox, logSpectrumBox, averageBox; -CheckBox elmInfoBox; -TextBox labelTextBox, manualScaleTextBox; -Button applyButton, scaleUpButton, scaleDownButton; -Scrollbar speedBar,positionBar; -Scope scope; -Grid grid, vScaleGrid, hScaleGrid; -int nx, ny; -Label scopeSpeedLabel, manualScaleLabel,vScaleList, manualScaleId, positionLabel; -expandingLabel vScaleLabel, hScaleLabel; -Vector