/*
Copyright (C) Paul Falstad and Iain Sharp
This file is part of CircuitJS1.
CircuitJS1 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
CircuitJS1 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CircuitJS1. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lushprojects.circuitjs1.client;
//import java.awt.*;
//import java.util.StringTokenizer;
abstract class GateElm extends CircuitElm {
final int FLAG_SMALL = 1;
final int FLAG_SCHMITT = 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);
}
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;
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, 0, hs*i0);
volts[i] = (lastOutput ^ isInverting()) ? 5 : 0;
}
hs2 = gwidth*(inputCount/2+1);
setBbox(point1, point2, hs2);
if (hasSchmittInputs())
schmittPoly = getSchmittPolygon(gsize, .47f);
}
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);
drawThickPolygon(g, gatePoly);
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);
curcount = updateDotCount(current, curcount);
drawDots(g, lead2, point2, curcount);
drawPosts(g);
}
Polygon gatePoly, schmittPoly;
Point pcircle, linePoints[];
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) {
if (!hasSchmittInputs())
return volts[x] > highVoltage*.5;
boolean res = volts[x] > highVoltage*(inputStates[x] ? .35 : .55);
inputStates[x] = res;
return res;
}
abstract boolean calcFunction();
void doStep() {
int i;
boolean f = calcFunction();
if (isInverting())
f = !f;
lastOutput = f;
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 Voltage (V)", highVoltage, 1, 10);
if (n == 2) {
EditInfo ei = new EditInfo("", 0, -1, -1);
ei.checkbox = new Checkbox("Schmitt Inputs", hasSchmittInputs());
return ei;
}
return null;
}
public void setEditValue(int n, EditInfo ei) {
if (n == 0) {
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();
}
}
// 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);
}
@Override double getCurrentIntoPoint(int xa, int ya) {
if (xa == x2 && ya == y2)
return current;
return 0;
}
}