cirsim
Version:
Cirsim Circuit Simulator
211 lines (170 loc) • 5.62 kB
JavaScript
import {Component} from '../Component';
import {ComponentPropertiesDlg} from '../Dlg/ComponentPropertiesDlg';
/**
* Component: Bus OR gate
* @constructor
*/
export const BusOr = function() {
Component.call(this);
this.height = 50;
this.width = 80;
this.size = 4;
this.addOut(this.width/2, 0, 16).bus = true;
this.ensureIO();
};
BusOr.prototype = Object.create(Component.prototype);
BusOr.prototype.constructor = BusOr;
BusOr.type = "BusOr"; ///< Name to use in files
BusOr.label = "Bus OR"; ///< Label for the palette
BusOr.desc = "Bus OR gate"; ///< Description for the palette
BusOr.img = "busor.png"; ///< Image to use for the palette
BusOr.description = `<h2>Bus OR Gate</h2><p>The output of an OR gate is <em>true</em>
if either or both inputs are true. Otherwise, it is false. This version works for
buses. The size determines the number of inputs.</p>`;
BusOr.order = 308;
/**
* Compute the gate result
* @param state
*/
BusOr.prototype.compute = function(state) {
var result = [];
state.forEach(function(s) {
if(Array.isArray(s)) {
for(var i=0; i<s.length; i++) {
var v = s[i];
if(result.length > i) {
if(v === true) {
result[i] = true;
}
} else {
result.push(v);
}
}
}
});
this.outs[0].set(result);
};
/**
* Clone this component object.
* @returns {BusOr}
*/
BusOr.prototype.clone = function() {
var copy = new BusOr();
copy.size = this.size;
copy.ensureIO();
copy.copyFrom(this);
return copy;
};
/**
* Load this object from an object converted from JSON
* @param obj Object from JSON
*/
BusOr.prototype.load = function(obj) {
this.size = obj["size"];
this.ensureIO();
Component.prototype.load.call(this, obj);
};
/**
* Create a save object suitable for conversion to JSON for export.
* @returns {*}
*/
BusOr.prototype.save = function() {
var obj = Component.prototype.save.call(this);
obj.size = this.size;
return obj;
};
/**
* Ensure the actual number of inputs matches the
* defined bus size.
*/
BusOr.prototype.ensureIO = function() {
var spacing = 16;
this.height = this.size * spacing + 8;
if(this.height < 50) {
this.height = 50;
}
var startY = this.size / 2 * spacing - 8;
for(var i=0; i<this.size; i++) {
//
// This math computes the location of the pins
// relative to the arc on the left side of the OR gate
//
var offset = this.size * 30;
var a = Math.atan2(this.height/2, offset);
var r = offset / Math.cos(a);
var pinY = startY - i * spacing;
var pinX = Math.sqrt(r*r - pinY*pinY) - offset;
if(i < this.ins.length) {
this.ins[i].x = -this.width / 2 + pinX;
this.ins[i].y = pinY;
this.ins[i].len = 16 + pinX;
this.ins[i].bus = true;
} else {
// Add any new pins
this.addIn(-this.width / 2 + pinX,
startY - i * spacing,
16 + pinX).bus = true;
}
}
for(; i<this.size; i++) {
}
// Delete pins that have ceased to exist
if(i < this.ins.length) {
for( ; i<this.ins.length; i++) {
this.ins[i].clear();
}
this.ins.splice(this.size);
}
}
/**
* Draw component object.
* @param context Display context
* @param view View object
*/
BusOr.prototype.draw = function(context, view) {
this.selectStyle(context, view);
var h = this.height;
var w = this.width;
var leftX = this.x - w/2 - 0.5;
var rightX = this.x + w/2 + 0.5;
var topY = this.y - h/2 - 0.5;
var botY = this.y + h/2 + 0.5;
context.beginPath();
// Left side
var offsetX = this.size * 30;
var a = Math.atan2(h/2, offsetX);
var r = offsetX / Math.cos(a);
context.arc(leftX - offsetX, this.y, r, -a, a);
// Top
var offsetY = ((w/2)*(w/2) - (h/2)*(h/2)) / h;
r = h/2 + offsetY;
a = Math.atan2(offsetY, w/2);
context.moveTo(leftX, topY);
context.lineTo(this.x - this.width/4, topY);
context.bezierCurveTo(this.x + this.width/4, topY,
this.x + 3 * this.width/8, this.y - this.height/4, this.x + this.width/2, this.y);
context.moveTo(leftX, botY);
context.lineTo(this.x - this.width/4, botY);
context.bezierCurveTo(this.x + this.width/4, botY,
this.x + 3 * this.width/8, this.y + this.height/4, this.x + this.width/2, this.y);
context.stroke();
this.drawName(context, -2, 5);
this.drawIO(context, view);
};
BusOr.prototype.properties = function(main) {
var dlg = new ComponentPropertiesDlg(this, main);
var id = dlg.uniqueId();
var html = `<div class="control1 center"><label for="${id}">Size: </label>
<input class="number" type="text" name="${id}" id="${id}" value="${this.size}"></div>`;
dlg.extra(html, () => {
let size = parseInt(document.getElementById(id).value);
if(isNaN(size) || size < 2 || size > 16) {
return "Size must be an integer from 2 to 16";
}
return null;
}, () => {
this.size = parseInt(document.getElementById(id).value);
this.ensureIO();
});
dlg.open();
};