UNPKG

cirsim

Version:

Cirsim Circuit Simulator

377 lines (314 loc) 9.39 kB
import {Simulation} from './Simulation'; import {Circuit} from './Circuit'; import {Sanitize} from './Utility/Sanitize'; /** * A collection of circuit objects * @param model The model we are a member of * @param simulation The simulation object that simulates operation of the circuits * @constructor */ export const Circuits = function(model, simulation) { this.model = model; this.circuits = []; this.grid = 8; this.snap = true; this.id = model !== null ? model.id : undefined; // If none is supplied, create a simulation object this.simulation = simulation ? simulation : new Simulation(); // Previous copy in the copy stack this.prev = null; }; /** * Add a circuit to this collection of circuits * @param circuit */ Circuits.prototype.add = function(circuit) { this.circuits.push(circuit); circuit.circuits = this; return circuit; }; Circuits.prototype.insert = function(circuit) { this.circuits.unshift(circuit); circuit.circuits = this; return circuit; } /** * Get the collection of circuits. * @returns Array of Circuit objects (copy) */ Circuits.prototype.getCircuits = function() { return this.circuits.slice(); }; /** * Get a circuit by name * @param name Name of the circuit * @returns Circuit object or null */ Circuits.prototype.getCircuit = function(name) { for(let i=0; i<this.circuits.length; i++) { const circuit = this.circuits[i]; if(circuit.name === name) { return circuit; } } return null; }; Circuits.prototype.advance = function(delta) { let ret = false; for(let i=0; i<this.circuits.length; i++) { const circuit = this.circuits[i]; if(circuit.advance(delta)) { ret = true; } } return ret; } /** * Determine if a circuit can be deleted. * @param ndx Index into the circuits. */ Circuits.prototype.canDelete = function(ndx) { if(ndx === 0) { // The main circuit (first) cannot be deleted return false; } // Do any circuits to the left refer to this one? const circuit = this.circuits[ndx]; for(let i=0; i<ndx; i++) { const references = this.circuits[i].references(circuit); if(references.length > 0) { return false; } } return true; } /** * Determine if a circuit can be moved left as a tab. * @param ndx Index into the circuits. * @returns {boolean} True if can be moved left */ Circuits.prototype.canMoveLeft = function(ndx) { // First two tabs cannot be moved left at all if(ndx < 2) { return false; } // Does the circuit to the left refer to this one? const circuit = this.circuits[ndx]; const references = this.circuits[ndx-1].references(circuit); return references.length === 0; } /** * Determine if a circuit can be moved right as a tab * @param ndx Index into the circuits. * @returns {boolean} True if can be move right */ Circuits.prototype.canMoveRight = function(ndx) { // First tab cannot be moved at all. Last tab can't // move to the right. if(ndx === 0 || ndx === this.circuits.length-1) { return false; } // What does this circuit refer to? const right = this.circuits[ndx+1].name; const references = this.circuits[ndx].references(); for(let reference of references) { if(reference.circuitName === right) { return false; } } return true; } Circuits.prototype.moveLeft = function(ndx) { if(this.canMoveLeft(ndx)) { this.model.backup(); const t = this.circuits[ndx-1]; this.circuits[ndx-1] = this.circuits[ndx]; this.circuits[ndx] = t; return true; } return false; } Circuits.prototype.moveRight = function(ndx) { if(this.canMoveRight(ndx)) { this.model.backup(); const t = this.circuits[ndx+1]; this.circuits[ndx+1] = this.circuits[ndx]; this.circuits[ndx] = t; return true; } return false; } Circuits.prototype.rename = function(ndx, name) { this.model.backup(); const circuit = this.circuits[ndx]; // Rename any references to this circuit for(let i=0; i<ndx; i++) { const references = this.circuits[i].references(circuit); for(let reference of references) { reference.circuitName = name; } } circuit.setName(name); } Circuits.prototype.newTab = function() { // for(let i=0; i<this.circuits.length; i++) { // this.circuits[i].newTab(); // } for(let i=this.circuits.length-1; i>=0; i--) { this.circuits[i].newTab(); } } Circuits.prototype.recompute = function() { //for(let i=0; i<this.circuits.length; i++) { for(let i=this.circuits.length-1; i>=0; i--) { this.circuits[i].recompute(); } } /** * Create a backup clone of this circuit * @returns {Circuits} */ Circuits.prototype.clone = function() { const copy = new Circuits(this.model, this.simulation); copy.grid = this.grid; copy.snap = this.snap; // Add to the copy stack copy.prev = this.prev; this.prev = copy; // Copy the circuit objects for(let i=0; i<this.circuits.length; i++) { const circuit = this.circuits[i]; copy.add(circuit.clone()); } return copy; }; /** * Update circuits after a circuit change. * This is used by CircuitRef components to ensure * references are always correct. * @param circuit Update up until this circuit */ Circuits.prototype.update = function(circuit) { for(let c of this.circuits) { if(c === circuit) { break; } c.update(); } } Circuits.prototype.toJSON = function() { return JSON.stringify(this.save()); }; /** * Load the circuits from a JSON-encoded object * @param json */ Circuits.prototype.fmJSON = function(json) { const obj = JSON.parse(json); this.load(obj); }; /** * Save this object into an object suitable for conversion to * a JSON object for storage. * @returns Object */ Circuits.prototype.save = function() { const cirs = []; for(let i=0; i<this.circuits.length; i++) { const circuit = this.circuits[i]; cirs.push(circuit.save()); } let obj = {"grid": this.grid, "circuits": cirs, "id": this.id}; if(this.snap) { obj.snap = true; } return obj; }; /** * Load this object from an object converted from a JSON * object used for storage. * @param obj */ Circuits.prototype.load = function(obj) { this.grid = +obj["grid"]; this.snap = Sanitize.boolean(obj["snap"]); this.prev = null; this.circuits = []; if(obj["id"] !== undefined) { this.id = Sanitize.sanitize(obj["id"]); } // // Load circuits in reverse order // for(let i=obj.circuits.length-1; i>=0; i--) { var circuitObj = obj.circuits[i]; var circuit = new Circuit(circuitObj.name); this.insert(circuit); circuit.load(circuitObj); } // In reverse order, ensure all circuits have // had compute called on all components for(let i=this.circuits.length-1; i>=0; i--) { this.circuits[i].pending(); } }; Circuits.prototype.addCircuit = function(name) { var circuit = new Circuit(name); this.add(circuit); } /** * Delete a circuit by the index to the circuit * @param index Index into the circuits array */ Circuits.prototype.deleteCircuitByIndex = function(index) { this.circuits.splice(index, 1); } /** * Get a component by it's naming * @param naming Naming to search for * @returns {*} */ Circuits.prototype.getComponentByNaming = function(naming) { for(var i=0; i<this.circuits.length; i++) { var circuit = this.circuits[i]; var pin = circuit.getComponentByNaming(naming); if(pin !== null) { return pin; } } return null; } /** * Get all components by type * @param type Naming to search for * @returns Array with collection of components of that type */ Circuits.prototype.getComponentsByType = function(type) { let components = []; for(let i=0; i<this.circuits.length; i++) { const circuit = this.circuits[i]; const c = circuit.getComponentsByType(type); components = components.concat(c); } return components; } /** * Replace a circuit that currently exists with a new version. */ Circuits.prototype.replaceCircuit = function(circuit) { circuit.circuits = this; for(let i=0; i<this.circuits.length; i++) { if(this.circuits[i].name === circuit.name) { this.circuits[i] = circuit; // Ensure all components in the new circuit are pending, so they // all get updated. circuit.components.forEach(function(component) { component.pending(); }); // Force this to appear to be a new tab this.model.newTab(); break; } } }