Tutorial: Drawing Basic Logic Gates with GWT
--D. Thiebaut (talk) 18:21, 4 July 2014 (EDT)
This recipe illustrates how to draw logic gates on a GWT canvas. I found remarkably little information on the Web about the geometry and the generation of logic gates, including the OR gate and its 3 arcs, and decided to just create the 3 basic gates: AND, INVERTER, and OR. The NAND and NOR gates can easily be generated from the information presented here. Look at other GWT Tutorials in this Wiki for information about setting up Eclipse and generating simple GWT Web applications.
Setup
- Mac OSX 10.8.5 with Java SDK 1.7
- Eclipse Kepler
- Google WebKit gwt-6.2.1.
Sample Output
This is what we're after, below: a way to generate simple AND, OR, and INVERTER gates on a GWT canvas.
Gate Geometry
The geometry for the gates is given by an IEEE document, with this main illustration, shown below, and found in Chapter 9 of this on-line reference on ASICS: http://iroi.seu.edu.cn/books/asics/ASICs.htm. (The OR gate shape is better spotted in the other diagram, located toward the end of this page.)
The Java Project
Canvas3.java
/*
* Canvas3.java
* D. Thiebaut
* A simple canvas application that positions a few gates in a 800x600 canvas.
*/
package dft.client;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
/**
* The main class for the project. Implements an empty canvas (Context2D) on which
* a few gates are drawn, along with 3 text labels
*/
public class Canvas3 implements EntryPoint {
Canvas canvas;
Context2d context;
static final int canvasHeight = 800;
static final int canvasWidth = 600;
public void onModuleLoad() {
canvas = Canvas.createIfSupported();
if (canvas == null) {
RootPanel.get().add(new Label("Sorry, your browser doesn't support the HTML5 Canvas element"));
return;
}
// standard code to size the canvas
canvas.setStyleName("mainCanvas");
canvas.setWidth(canvasWidth + "px");
canvas.setCoordinateSpaceWidth(canvasWidth);
canvas.setHeight(canvasHeight + "px");
canvas.setCoordinateSpaceHeight(canvasHeight);
RootPanel.get().add(canvas);
context = canvas.getContext2d();
// drop a few gates on the canvas
for ( int x = 100; x < 300; x += 75 ) {
// some inverters facing right
InverterRight inv = new InverterRight( context, x, 300 );
inv.draw();
// some inverters facing down
InverterDown inv2 = new InverterDown( context, 300, x );
inv2.draw();
// some AND gates (facing right)
AndGate a = new AndGate( context, x+50, 150 );
a.draw();
}
// an OR gate
OrGate or1 = new OrGate( context, 200, 200 );
or1.draw();
// Put some labels
TextLabel L1, L2, L3;
L1 = new TextLabel( context, "75-75", 75, 75);
L1.draw();
L2 = new TextLabel( context, "195-95", 195, 95);
L2.draw();
L3 = new TextLabel( context, "75-195", 75, 195);
//L3.setFont( "bold 22px sans-serif");
L3.draw();
}
}
AndGate.java
package dft.client;
import com.google.gwt.canvas.dom.client.Context2d;
public class AndGate {
Context2d context;
double x;
double y;
double andGateHeight = 30;
double andGateLength = 40;
double xin1, yin1, xin2, yin2, xout, yout;
public AndGate( Context2d c, double xx, double yy ) {
x = xx;
y = yy;
context = c;
xin1 = x;
xin2 = x;
yin1 = y + andGateHeight/4;
yin2 = y + 3*andGateHeight/4;
xout = x + andGateLength/3 + andGateHeight/2;
yout = y + andGateHeight/2;
}
public void draw() {
context.moveTo( x, y );
context.lineTo( x, y+andGateHeight );
context.lineTo( x+andGateLength/3, y+andGateHeight );
context.moveTo( x, y );
context.lineTo( x+andGateLength/3, y );
context.stroke();
context.moveTo( x+andGateLength/3, y );
context.arc( x+andGateLength/3 , y+andGateHeight/2, andGateHeight/2, -Math.PI/2, Math.PI/2);
context.stroke();
}
public void drawIO() {
context.moveTo( xin1, yin1);
context.arc( xin1, yin1, 2, 0, Math.PI*2 );
context.stroke();
context.moveTo( xin2, yin2);
context.arc( xin2, yin2, 2, 0, Math.PI*2 );
context.stroke();
context.moveTo( xout, yout);
context.arc( xout, yout, 2, 0, Math.PI*2 );
context.stroke();
}
}
InverterDown.java
package dft.client;
import com.google.gwt.canvas.dom.client.Context2d;
public class InverterDown {
double x;
double y;
double xin, yin, xout, yout;
Context2d context = null;
int inverterHeight = 20;
int inverterLength = 20;
int inverterCircleRadius = 5;
int calculatedCenterx = 0;
int calculatedCentery = inverterHeight + inverterCircleRadius;
public InverterDown(Context2d c, double xx, double yy) {
context = c;
x = xx;
y = yy;
xin = x;
yin = y;
yout = y + inverterLength + inverterCircleRadius * 2;
xout = x;
}
public void draw() {
context.moveTo(x, y);
context.lineTo(x - inverterHeight / 2, y);
context.lineTo(x, y + inverterLength);
context.lineTo(x + inverterHeight / 2, y);
context.lineTo(x, y);
context.stroke();
context.moveTo(x + calculatedCenterx + inverterCircleRadius, y
+ calculatedCentery);
context.arc(x + calculatedCenterx, y + calculatedCentery,
inverterCircleRadius, 0, Math.PI * 2.0, true);
context.stroke();
}
public void drawIO() {
context.moveTo(xin, yin);
context.arc(xin, yin, 2, 0, Math.PI * 2);
context.stroke();
context.moveTo(xout, yout);
context.arc(xout, yout, 2, 0, Math.PI * 2);
context.stroke();
}
}
InverterRight.java
package dft.client;
import com.google.gwt.canvas.dom.client.Context2d;
public class InverterRight {
double x;
double y;
double xin, yin, xout, yout;
Context2d context = null;
int inverterHeight = 20;
int inverterLength = 20;
int inverterCircleRadius = 5;
int calculatedCenterx = inverterLength + inverterCircleRadius;
int calculatedCentery = 0;
public InverterRight(Context2d c, double xx, double yy) {
context = c;
x = xx;
y = yy;
xin = x;
yin = y;
xout = x + inverterLength + inverterCircleRadius * 2;
yout = y;
}
public void draw() {
context.moveTo(x, y);
context.lineTo(x, y - inverterHeight / 2);
context.lineTo(x + inverterLength, y);
context.lineTo(x, y + inverterHeight / 2);
context.lineTo(x, y);
context.stroke();
context.moveTo(x + calculatedCenterx + inverterCircleRadius, y
+ calculatedCentery);
context.arc(x + calculatedCenterx, y + calculatedCentery,
inverterCircleRadius, 0, Math.PI * 2.0, true);
context.stroke();
}
public void drawIO() {
context.moveTo(xin, yin);
context.arc(xin, yin, 2, 0, Math.PI * 2);
context.stroke();
context.moveTo(xout, yout);
context.arc(xout, yout, 2, 0, Math.PI * 2);
context.stroke();
}
}
OrGate.java
The geometry of the OR gate is better illustrated by labeling key points in the original diagram. These (x,y) points are computed in the java code below. All the angles considered are PI/6 for the gate itself. To locate the two inputs of the gate, we use + and -PI/12 from the x6,y6 center of the left circle.
package dft.client;
import com.google.gwt.canvas.dom.client.Context2d;
/**
* OrGate
*
* @author thiebaut
*
* Defined by geometry of IEEE pub:
* http://iroi.seu.edu.cn/books/asics/Book/CH09/CH09-1.gif
*/
public class OrGate {
// various points defining the gate
Context2d context;
double x, x1, x2, x3, x4, x5, x6;
double y, y1, y2, y3, y4, y5, y6;
double radius = 26;
double height = 26;
double flat = 10;
double alpha, beta;
// inputs and output
double xin1, yin1, xin2, yin2, xout, yout;
public OrGate(Context2d c, double xx, double yy) {
x = xx;
y = yy;
context = c;
// compute various quantities
alpha = Math.PI / 6;
beta = alpha;
y1 = y - radius / 2;
y2 = y1;
y3 = y;
y4 = y2 + height;
y5 = y4;
y6 = y;
x6 = x - flat - radius;
x1 = x6 + radius * Math.sqrt(3) / 2;
x5 = x1;
x2 = x;
x4 = x;
x3 = x + radius * Math.sqrt(3) / 2;
// I/O Pins
xin1 = x6 + radius * 0.96592582628; // cos( PI/12 )
yin1 = y - radius * 0.2588190451; // sin( PI/12 )
xin2 = xin1;
yin2 = y + radius * 0.2588190451; // sin( PI/12 )
xout = x3;
yout = y3;
}
public double getXInput1() {
return xin1;
}
public double getYInput1() {
return yin1;
}
public double getXInput2() {
return xin2;
}
public double getYInput2() {
return yin2;
}
public double getXOutput() {
return xout;
}
public double getYOutput() {
return yout;
}
public void draw() {
// draw 1-2
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
// draw 2-3
context.moveTo(x2, y2);
context.arc(x4, y4, radius, 3 * Math.PI / 2, Math.PI * 2 - Math.PI / 6);
context.stroke();
// draw 4-3
context.moveTo(x3, y3);
context.arc(x2, y2, radius, Math.PI / 6, Math.PI / 2);
context.stroke();
// Draw 4-5
context.moveTo(x4, y4);
context.lineTo(x5, y5);
context.stroke();
// Draw 1-5
context.moveTo(x1, y1);
context.arc(x6, y6, radius, -Math.PI / 6, Math.PI / 6);
context.stroke();
}
}
TextLabel.java
package dft.client;
import com.google.gwt.canvas.dom.client.Context2d;
public class TextLabel {
Context2d context;
String text;
double x, y;
String font = "bold 22px sans-serif";
public TextLabel( Context2d c, String t, double xx, double yy ) {
context = c;
text = t;
x = xx;
y = yy;
}
public void setFont( String f ) {
font = f;
}
public void draw() {
context.setFont( font );
context.fillText( text, x, y);
}
}