/* 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.text.DecimalFormat; //import java.text.NumberFormat; import com.google.gwt.canvas.client.Canvas; import com.google.gwt.canvas.dom.client.CanvasGradient; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.canvas.dom.client.Context2d; import com.google.gwt.canvas.dom.client.Context2d.LineCap; import com.google.gwt.canvas.dom.client.TextMetrics; import com.google.gwt.core.shared.GWT; import com.google.gwt.i18n.client.NumberFormat; // circuit element class public abstract class CircuitElm implements Editable { static double voltageRange = 5; static int colorScaleCount = 32; static Color colorScale[]; static double currentMult, powerMult; static Point ps1, ps2; static CirSim sim; static Color whiteColor, selectColor, lightGrayColor; static Font unitsFont; static NumberFormat showFormat, shortFormat;//, noCommaFormat; static final double pi = 3.14159265358979323846; int x, y, x2, y2, flags, nodes[], voltSource; int dx, dy, dsign; int lastHandleGrabbed=-1; int numHandles=2; double dn, dpx1, dpy1; Point point1, point2, lead1, lead2; double volts[]; double current, curcount; Rectangle boundingBox; boolean noDiagonal; public boolean selected; private boolean iAmMouseElm=false; // 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 } Class getDumpClass() { return getClass(); } int getDefaultFlags() { return 0; } static void initClass(CirSim s) { unitsFont = new Font("SansSerif", 0, 12); sim = s; colorScale = new Color[colorScaleCount]; int i; for (i = 0; i != colorScaleCount; i++) { double v = i*2./colorScaleCount - 1; if (v < 0) { int n1 = (int) (128*-v)+127; int n2 = (int) (127*(1+v)); colorScale[i] = new Color(n1, n2, n2); } else { int n1 = (int) (128*v)+127; int n2 = (int) (127*(1-v)); colorScale[i] = new Color(n2, n1, n2); } } ps1 = new Point(); ps2 = new Point(); // showFormat = DecimalFormat.getInstance(); // showFormat.setMaximumFractionDigits(2); showFormat=NumberFormat.getFormat("####.##"); // shortFormat = DecimalFormat.getInstance(); // shortFormat.setMaximumFractionDigits(1); shortFormat=NumberFormat.getFormat("####.#"); // noCommaFormat = DecimalFormat.getInstance(); // noCommaFormat.setMaximumFractionDigits(10); // noCommaFormat.setGroupingUsed(false); } CircuitElm(int xx, int yy) { x = x2 = xx; y = y2 = yy; flags = getDefaultFlags(); allocNodes(); initBoundingBox(); } CircuitElm(int xa, int ya, int xb, int yb, int 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); } void allocNodes() { int n = getPostCount() + getInternalNodeCount(); // preserve voltages if possible if (nodes == null || nodes.length != n) { nodes = new int[n]; volts = new double[n]; } } String dump() { int t = getDumpType(); return (t < 127 ? ((char)t)+" " : t+" ") + x + " " + y + " " + x2 + " " + y2 + " " + flags; } void reset() { int i; for (i = 0; i != getPostCount()+getInternalNodeCount(); i++) volts[i] = 0; curcount = 0; } void draw(Graphics g) {} void setCurrent(int x, double c) { current = c; } double getCurrent() { return current; } void doStep() {} void delete() {} void startIteration() {} double getPostVoltage(int x) { return volts[x]; } void setNodeVoltage(int n, double c) { volts[n] = c; calculateCurrent(); } void calculateCurrent() {} 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); } 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)); } Point interpPoint(Point a, Point b, double f) { Point p = new Point(); interpPoint(a, b, p, f); return p; } void interpPoint(Point a, Point b, Point c, double f) { int xpd = b.x-a.x; int ypd = b.y-a.y; /*double q = (a.x*(1-f)+b.x*f+.48); System.out.println(q + " " + (int) q);*/ 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); } void interpPoint(Point a, Point b, Point c, 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); } /** * 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) { Point p = new Point(); 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 */ 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); } void draw2Leads(Graphics g) { // draw first lead setVoltageColor(g, volts[0]); drawThickLine(g, point1, lead1); // draw second lead setVoltageColor(g, volts[1]); drawThickLine(g, lead2, point2); } Point [] newPointArray(int n) { Point a[] = new Point[n]; while (n > 0) a[--n] = new Point(); return a; } void drawDots(Graphics g, Point pa, Point pb, double pos) { 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); g.setColor(sim.conventionCheckItem.getState()?Color.yellow:Color.cyan); int ds = 16; 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); } } 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); poly.addPoint(b.x, b.y); 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); p.addPoint(b.x, b.y); 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); p.addPoint(b.x, b.y); p.addPoint(c.x, c.y); p.addPoint(d.x, d.y); return p; } Polygon createPolygon(Point a[]) { Polygon p = new Polygon(); int i; for (i = 0; i != a.length; i++) p.addPoint(a[i].x, a[i].y); return p; } 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)) { xx = x; } else { yy = y; } } x2 = xx; y2 = yy; setPoints(); } void move(int dx, int dy) { x += dx; y += dy; x2 += dx; y2 += dy; boundingBox.translate(dx, dy); setPoints(); } // 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 i; for (i = 0; i != sim.elmList.size(); i++) { CircuitElm ce = sim.getElm(i); if (ce.x == nx && ce.y == ny && ce.x2 == nx2 && ce.y2 == ny2) return false; if (ce.x == nx2 && ce.y == ny2 && ce.x2 == nx && ce.y2 == ny) return false; } 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 (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 // 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) return; int i; for (i = 0; i != getPostCount(); i++) { Point p = getPost(i); drawPost(g, p); } } 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 (numHandles==2) { 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 (Graphics.distanceSq(x2, y2, xtest,ytest) <= deltaSq) lastHandleGrabbed=1; } return lastHandleGrabbed; } void stamp() {} int getVoltageSourceCount() { return 0; } int getInternalNodeCount() { return 0; } void setNode(int p, int n) { nodes[p] = n; } void setVoltageSource(int n, int v) { voltSource = v; } // int getVoltageSource() { return voltSource; } // Never used double getVoltageDiff() { return volts[0] - volts[1]; } boolean nonLinear() { return false; } int getPostCount() { return 2; } int getNode(int n) { return nodes[n]; } Point getPost(int n) { return (n == 0) ? point1 : (n == 1) ? point2 : null; } /* 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); } // 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); } 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); } 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; } x1 = min(boundingBox.x, x1); y1 = min(boundingBox.y, y1); x2 = max(boundingBox.x+boundingBox.width-1, x2); y2 = max(boundingBox.y+boundingBox.height-1, y2); boundingBox.setBounds(x1, y1, x2-x1, y2-y1); } void adjustBbox(Point p1, Point p2) { adjustBbox(p1.x, p1.y, p2.x, p2.y); } 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.context.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.context.restore(); } 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();; g.setColor(whiteColor); 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; } int dpx = (int) (dpx1*hs); int dpy = (int) (dpy1*hs); if (dpx == 0) 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); } } void drawCoil(Graphics g, int hs, Point p1, Point p2, double v1, double v2) { double len = distance(p1, p2); g.context.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); 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); if (len > 24) g.context.scale(1, hs/(len/6)); else g.context.scale(1, hs > 0 ? 1 : -1); int loop; for (loop = 0; loop != 3; loop++) { g.context.beginPath(); double start = len*loop/3; g.context.moveTo(start,0); g.context.arc(len*(loop+.5)/3, 0, len/6, Math.PI, Math.PI*2); g.context.lineTo(len*(loop+1)/3, 0); g.context.stroke(); } g.context.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); } 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); } 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); } 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]);*/ } 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); } Polygon getSchmittPolygon(float gsize, float ctr) { Point pts[] = newPointArray(6); 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); } static String getVoltageDText(double v) { return getUnitText(Math.abs(v), "V"); } static String getVoltageText(double v) { return getUnitText(v, "V"); } // IES - hacking static String getUnitText(double v, String u) { return myGetUnitText(v,u, false); } static String getShortUnitText(double v, String u) { return myGetUnitText(v,u, true); } static String myGetUnitText(double v, String u, boolean sf) { NumberFormat s; String sp = ""; if (sf) s=shortFormat; else { s=showFormat; sp = " "; } double va = Math.abs(v); if (va < 1e-14) // this used to return null, but then wires would display "null" with 0V return "0" + sp + u; if (va < 1e-9) return s.format(v*1e12) + sp + "p" + u; if (va < 1e-6) return s.format(v*1e9) + sp + "n" + u; if (va < 1e-3) return s.format(v*1e6) + sp + CirSim.muString + u; if (va < 1) return s.format(v*1e3) + sp + "m" + u; if (va < 1e3) return s.format(v) + sp + u; if (va < 1e6) return s.format(v*1e-3) + sp + "k" + u; if (va < 1e9) return s.format(v*1e-6) + sp + "M" + u; return s.format(v*1e-9) + sp + "G" + u; } /* static String getUnitText(double v, String u) { double va = Math.abs(v); if (va < 1e-14) return "0 " + u; if (va < 1e-9) return showFormat.format(v*1e12) + " p" + u; if (va < 1e-6) return showFormat.format(v*1e9) + " n" + u; if (va < 1e-3) return showFormat.format(v*1e6) + " " + CirSim.muString + u; if (va < 1) return showFormat.format(v*1e3) + " m" + u; if (va < 1e3) return showFormat.format(v) + " " + u; if (va < 1e6) return showFormat.format(v*1e-3) + " k" + u; if (va < 1e9) return showFormat.format(v*1e-6) + " M" + u; return showFormat.format(v*1e-9) + " G" + u; } static String getShortUnitText(double v, String u) { double va = Math.abs(v); if (va < 1e-13) return null; if (va < 1e-9) return shortFormat.format(v*1e12) + "p" + u; if (va < 1e-6) return shortFormat.format(v*1e9) + "n" + u; if (va < 1e-3) return shortFormat.format(v*1e6) + CirSim.muString + u; if (va < 1) return shortFormat.format(v*1e3) + "m" + u; if (va < 1e3) return shortFormat.format(v) + u; if (va < 1e6) return shortFormat.format(v*1e-3) + "k" + u; if (va < 1e9) return shortFormat.format(v*1e-6) + "M" + u; return shortFormat.format(v*1e-9) + "G" + u; }*/ static String getCurrentText(double i) { return getUnitText(i, "A"); } static String getCurrentDText(double i) { return getUnitText(Math.abs(i), "A"); } void updateDotCount() { curcount = updateDotCount(current, curcount); } double updateDotCount(double cur, double cc) { if (!sim.simIsRunning()) return cc; double cadd = cur*currentMult; /*if (cur != 0 && cadd <= .05 && cadd >= -.05) cadd = (cadd < 0) ? -.05 : .05;*/ cadd %= 8; /*if (cadd > 8) cadd = 8; if (cadd < -8) cadd = -8;*/ return cc + cadd; } void doDots(Graphics g) { updateDotCount(); if (sim.dragElm != this) drawDots(g, point1, point2, curcount); } void doAdjust() {} void setupAdjust() {} 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]; } Color getVoltageColor(Graphics g, double volts) { if (needsHighlight()) { return (selectColor); } if (!sim.voltsCheckItem.getState()) { if (!sim.powerCheckItem.getState()) // && !conductanceCheckItem.getState()) return(whiteColor); return (g.lastColor); } 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)); } void setPowerColor(Graphics g, boolean yellow) { /*if (conductanceCheckItem.getState()) { setConductanceColor(g, current/getVoltageDiff()); return; }*/ if (!sim.powerCheckItem.getState()) return; setPowerColor(g, getPower()); } void setPowerColor(Graphics g, double w0) { w0 *= powerMult; //System.out.println(w); double w = (w0 < 0) ? -w0 : w0; if (w > 1) w = 1; int rg = 128+(int) (w*127); int b = (int) (128*(1-w)); /*if (yellow) g.setColor(new Color(rg, rg, b)); else */ if (w0 > 0) g.setColor(new Color(rg, b, b)); else g.setColor(new Color(b, rg, b)); } void setConductanceColor(Graphics g, double w0) { w0 *= powerMult; //System.out.println(w); double w = (w0 < 0) ? -w0 : w0; if (w > 1) w = 1; int rg = (int) (w*255); g.setColor(new Color(rg, rg, rg)); } double getPower() { return getVoltageDiff()*current; } double getScopeValue(int x) { 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; } 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 // 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 // unconnected nodes, and look for loops boolean getConnection(int n1, int n2) { return true; } // is n1 connected to ground somehow? boolean hasGroundConnection(int n1) { return false; } boolean isWire() { 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 iAmMouseElm || selected || sim.plotYElm == this; } boolean isSelected() { return selected; } boolean canShowValueInScope(int v) { return false; } void setSelected(boolean x) { selected = x; } void selectRect(Rectangle r) { selected = r.intersects(boundingBox); } 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); } Rectangle getBoundingBox() { return boundingBox; } boolean needsShortcut() { return getShortcut() > 0; } int getShortcut() { return 0; } boolean isGraphicElmt() { return false; } void setMouseElm(boolean v) {iAmMouseElm=v;} void draggingDone() {} boolean isMouseElm() {return iAmMouseElm; } void updateModels() {} void stepFinished() {} // Sadly not all elements override this routine to set it correctly. // If you depend on it (eg if you have a compositeElement) then check it is implemented correctly in // all relevant element types. // // In general it would be better if the future standard was to define getCurrentIntoNode for // each element and then to define getCurrentIntoPoint to map the point to the node and then // call getCurrentIntoNode double getCurrentIntoNode(int n) { if (n==0 && getPostCount() == 2) return -current; else return current; } double getCurrentIntoPoint(int xa, int ya) { if (xa == x && ya == y && getPostCount() == 2) return -current; // if ((xa == x2 && ya == y2) || getPostCount() == 1) // return current; // sim.stop("bad current into point", this); // for debugging return current; } void flipPosts() { int oldx = x; int oldy = y; x = x2; y = y2; x2 = oldx; y2 = oldy; setPoints(); } }