com.lushprojects.circuitjs1.client.VoltageElm.java Source code

Java tutorial

Introduction

Here is the source code for com.lushprojects.circuitjs1.client.VoltageElm.java

Source

/*    
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 com.google.gwt.user.client.Window;

//import java.awt.*;
//import java.util.StringTokenizer;

class VoltageElm extends CircuitElm {
    static final int FLAG_COS = 2;
    static final int FLAG_PULSE_DUTY = 4;
    int waveform;
    static final int WF_DC = 0;
    static final int WF_AC = 1;
    static final int WF_SQUARE = 2;
    static final int WF_TRIANGLE = 3;
    static final int WF_SAWTOOTH = 4;
    static final int WF_PULSE = 5;
    static final int WF_VAR = 6;
    double frequency, maxVoltage, freqTimeZero, bias, phaseShift, dutyCycle;

    static final double defaultPulseDuty = 1 / (2 * Math.PI);

    VoltageElm(int xx, int yy, int wf) {
        super(xx, yy);
        waveform = wf;
        maxVoltage = 5;
        frequency = 40;
        dutyCycle = .5;
        reset();
    }

    public VoltageElm(int xa, int ya, int xb, int yb, int f, StringTokenizer st) {
        super(xa, ya, xb, yb, f);
        maxVoltage = 5;
        frequency = 40;
        waveform = WF_DC;
        dutyCycle = .5;
        try {
            waveform = new Integer(st.nextToken()).intValue();
            frequency = new Double(st.nextToken()).doubleValue();
            maxVoltage = new Double(st.nextToken()).doubleValue();
            bias = new Double(st.nextToken()).doubleValue();
            phaseShift = new Double(st.nextToken()).doubleValue();
            dutyCycle = new Double(st.nextToken()).doubleValue();
        } catch (Exception e) {
        }
        if ((flags & FLAG_COS) != 0) {
            flags &= ~FLAG_COS;
            phaseShift = pi / 2;
        }

        // old circuit files have the wrong duty cycle for pulse waveforms (wasn't configurable in the past)
        if ((flags & FLAG_PULSE_DUTY) == 0 && waveform == WF_PULSE) {
            dutyCycle = defaultPulseDuty;
        }

        reset();
    }

    int getDumpType() {
        return 'v';
    }

    String dump() {
        // set flag so we know if duty cycle is correct for pulse waveforms
        if (waveform == WF_PULSE)
            flags |= FLAG_PULSE_DUTY;
        else
            flags &= ~FLAG_PULSE_DUTY;

        return super.dump() + " " + waveform + " " + frequency + " " + maxVoltage + " " + bias + " " + phaseShift
                + " " + dutyCycle;
        // VarRailElm adds text at the end
    }

    void reset() {
        freqTimeZero = 0;
        curcount = 0;
    }

    double triangleFunc(double x) {
        if (x < pi)
            return x * (2 / pi) - 1;
        return 1 - (x - pi) * (2 / pi);
    }

    void stamp() {
        if (waveform == WF_DC)
            sim.stampVoltageSource(nodes[0], nodes[1], voltSource, getVoltage());
        else
            sim.stampVoltageSource(nodes[0], nodes[1], voltSource);
    }

    void doStep() {
        if (waveform != WF_DC)
            sim.updateVoltageSource(nodes[0], nodes[1], voltSource, getVoltage());
    }

    double getVoltage() {
        double w = 2 * pi * (sim.t - freqTimeZero) * frequency + phaseShift;
        switch (waveform) {
        case WF_DC:
            return maxVoltage + bias;
        case WF_AC:
            return Math.sin(w) * maxVoltage + bias;
        case WF_SQUARE:
            return bias + ((w % (2 * pi) > (2 * pi * dutyCycle)) ? -maxVoltage : maxVoltage);
        case WF_TRIANGLE:
            return bias + triangleFunc(w % (2 * pi)) * maxVoltage;
        case WF_SAWTOOTH:
            return bias + (w % (2 * pi)) * (maxVoltage / pi) - maxVoltage;
        case WF_PULSE:
            return ((w % (2 * pi)) < (2 * pi * dutyCycle)) ? maxVoltage + bias : bias;
        default:
            return 0;
        }
    }

    final int circleSize = 17;

    void setPoints() {
        super.setPoints();
        calcLeads((waveform == WF_DC || waveform == WF_VAR) ? 8 : circleSize * 2);
    }

    void draw(Graphics g) {
        setBbox(x, y, x2, y2);
        draw2Leads(g);
        if (waveform == WF_DC) {
            setPowerColor(g, false);
            setVoltageColor(g, volts[0]);
            interpPoint2(lead1, lead2, ps1, ps2, 0, 10);
            drawThickLine(g, ps1, ps2);
            setVoltageColor(g, volts[1]);
            int hs = 16;
            setBbox(point1, point2, hs);
            interpPoint2(lead1, lead2, ps1, ps2, 1, hs);
            drawThickLine(g, ps1, ps2);
        } else {
            setBbox(point1, point2, circleSize);
            interpPoint(lead1, lead2, ps1, .5);
            drawWaveform(g, ps1);
            if (bias != 0) {
                g.setColor(Color.white);
                g.setFont(unitsFont);
                Point plusPoint = interpPoint(point1, point2, (dn / 2 + circleSize + 4) / dn, 10 * dsign);
                plusPoint.y += 4;
                int w = (int) g.context.measureText("+").getWidth();
                ;
                g.drawString("+", plusPoint.x - w / 2, plusPoint.y);
            }
        }
        updateDotCount();
        if (sim.dragElm != this) {
            if (waveform == WF_DC)
                drawDots(g, point1, point2, curcount);
            else {
                drawDots(g, point1, lead1, curcount);
                drawDots(g, point2, lead2, -curcount);
            }
        }
        drawPosts(g);
    }

    void drawWaveform(Graphics g, Point center) {
        g.setColor(needsHighlight() ? selectColor : Color.gray);
        setPowerColor(g, false);
        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);
        int xc2;
        switch (waveform) {
        case WF_DC: {
            break;
        }
        case WF_SQUARE:
            xc2 = (int) (wl * 2 * dutyCycle - wl + xc);
            xc2 = max(xc - wl + 3, min(xc + wl - 3, xc2));
            drawThickLine(g, xc - wl, yc - wl, xc - wl, yc);
            drawThickLine(g, xc - wl, yc - wl, xc2, yc - wl);
            drawThickLine(g, xc2, yc - wl, xc2, yc + wl);
            drawThickLine(g, xc + wl, yc + wl, xc2, yc + wl);
            drawThickLine(g, xc + wl, yc, xc + wl, yc + wl);
            break;
        case WF_PULSE:
            yc += wl / 2;
            drawThickLine(g, xc - wl, yc - wl, xc - wl, yc);
            drawThickLine(g, xc - wl, yc - wl, xc - wl / 2, yc - wl);
            drawThickLine(g, xc - wl / 2, yc - wl, xc - wl / 2, yc);
            drawThickLine(g, xc - wl / 2, yc, xc + wl, yc);
            break;
        case WF_SAWTOOTH:
            drawThickLine(g, xc, yc - wl, xc - wl, yc);
            drawThickLine(g, xc, yc - wl, xc, yc + wl);
            drawThickLine(g, xc, yc + wl, xc + wl, yc);
            break;
        case WF_TRIANGLE: {
            int xl = 5;
            drawThickLine(g, xc - xl * 2, yc, xc - xl, yc - wl);
            drawThickLine(g, xc - xl, yc - wl, xc, yc);
            drawThickLine(g, xc, yc, xc + xl, yc + wl);
            drawThickLine(g, xc + xl, yc + wl, xc + xl * 2, yc);
            break;
        }
        case WF_AC: {
            int i;
            int xl = 10;
            g.context.beginPath();
            g.context.setLineWidth(3.0);

            for (i = -xl; i <= xl; i++) {
                int yy = yc + (int) (.95 * Math.sin(i * pi / xl) * wl);
                if (i == -xl)
                    g.context.moveTo(xc + i, yy);
                else
                    g.context.lineTo(xc + i, yy);
            }
            g.context.stroke();
            g.context.setLineWidth(1.0);
            break;
        }
        }
        if (sim.showValuesCheckItem.getState()) {
            String s = getShortUnitText(frequency, "Hz");
            if (dx == 0 || dy == 0)
                drawValues(g, s, circleSize);
        }
    }

    int getVoltageSourceCount() {
        return 1;
    }

    double getPower() {
        return -getVoltageDiff() * current;
    }

    double getVoltageDiff() {
        return volts[1] - volts[0];
    }

    void getInfo(String arr[]) {
        switch (waveform) {
        case WF_DC:
        case WF_VAR:
            arr[0] = "voltage source";
            break;
        case WF_AC:
            arr[0] = "A/C source";
            break;
        case WF_SQUARE:
            arr[0] = "square wave gen";
            break;
        case WF_PULSE:
            arr[0] = "pulse gen";
            break;
        case WF_SAWTOOTH:
            arr[0] = "sawtooth gen";
            break;
        case WF_TRIANGLE:
            arr[0] = "triangle gen";
            break;
        }
        arr[1] = "I = " + getCurrentText(getCurrent());
        arr[2] = ((this instanceof RailElm) ? "V = " : "Vd = ") + getVoltageText(getVoltageDiff());
        if (waveform != WF_DC && waveform != WF_VAR) {
            arr[3] = "f = " + getUnitText(frequency, "Hz");
            arr[4] = "Vmax = " + getVoltageText(maxVoltage);
            int i = 5;
            if (waveform == WF_AC && bias == 0)
                arr[i++] = "V(rms) = " + getVoltageText(maxVoltage / 1.41421356);
            if (bias != 0)
                arr[i++] = "Voff = " + getVoltageText(bias);
            else if (frequency > 500)
                arr[i++] = "wavelength = " + getUnitText(2.9979e8 / frequency, "m");
            arr[i++] = "P = " + getUnitText(getPower(), "W");
        }
        if (waveform == WF_DC && current != 0 && sim.showResistanceInVoltageSources) {
            arr[3] = "(R = " + getUnitText(maxVoltage / current, sim.ohmString) + ")";
        }
    }

    public EditInfo getEditInfo(int n) {
        if (n == 0)
            return new EditInfo(waveform == WF_DC ? "Voltage" : "Max Voltage", maxVoltage, -20, 20);
        if (n == 1) {
            EditInfo ei = new EditInfo("Waveform", waveform, -1, -1);
            ei.choice = new Choice();
            ei.choice.add("D/C");
            ei.choice.add("A/C");
            ei.choice.add("Square Wave");
            ei.choice.add("Triangle");
            ei.choice.add("Sawtooth");
            ei.choice.add("Pulse");
            ei.choice.select(waveform);
            return ei;
        }
        if (waveform == WF_DC)
            return null;
        if (n == 2)
            return new EditInfo("Frequency (Hz)", frequency, 4, 500);
        if (n == 3)
            return new EditInfo("DC Offset (V)", bias, -20, 20);
        if (n == 4)
            return new EditInfo("Phase Offset (degrees)", phaseShift * 180 / pi, -180, 180).setDimensionless();
        if (n == 5 && (waveform == WF_PULSE || waveform == WF_SQUARE))
            return new EditInfo("Duty Cycle", dutyCycle * 100, 0, 100).setDimensionless();
        return null;
    }

    public void setEditValue(int n, EditInfo ei) {
        if (n == 0)
            maxVoltage = ei.value;
        if (n == 3)
            bias = ei.value;
        if (n == 2) {
            // adjust time zero to maintain continuity ind the waveform
            // even though the frequency has changed.
            double oldfreq = frequency;
            frequency = ei.value;
            double maxfreq = 1 / (8 * sim.timeStep);
            if (frequency > maxfreq) {
                if (Window.confirm("Adjust timestep to allow for higher frequencies?"))
                    sim.timeStep = 1 / (32 * frequency);
                else
                    frequency = maxfreq;
            }
            double adj = frequency - oldfreq;
            freqTimeZero = sim.t - oldfreq * (sim.t - freqTimeZero) / frequency;
        }
        if (n == 1) {
            int ow = waveform;
            waveform = ei.choice.getSelectedIndex();
            if (waveform == WF_DC && ow != WF_DC) {
                ei.newDialog = true;
                bias = 0;
            } else if (waveform != ow)
                ei.newDialog = true;

            // change duty cycle if we're changing to or from pulse
            if (waveform == WF_PULSE && ow != WF_PULSE)
                dutyCycle = defaultPulseDuty;
            else if (ow == WF_PULSE && waveform != WF_PULSE)
                dutyCycle = .5;

            setPoints();
        }
        if (n == 4)
            phaseShift = ei.value * pi / 180;
        if (n == 5)
            dutyCycle = ei.value * .01;
    }
}