From 12db01963f8f280561f80c252f0a265aa4101e38 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Wed, 31 Jul 2019 18:28:27 +0300 Subject: [PATCH] multi bit math --- src/assets/4decoder.svg | 7 ++++ src/assets/4encoder.svg | 7 ++++ src/modules/activation/types/Context.ts | 14 ++++--- src/modules/colors/helpers/fromHex.ts | 30 +++++++++++++ .../logic-gates/components/LogicGatesPage.tsx | 1 + src/modules/saving/constants.ts | 6 ++- src/modules/saving/data/4BitScale.ts | 4 ++ src/modules/saving/data/categories.ts | 8 ++++ src/modules/saving/helpers/adderActivation.ts | 10 +++++ src/modules/saving/helpers/fromState.ts | 30 ++++++++++++- src/modules/saving/templates/4bitDecoder.ts | 40 ++++++++++++++++++ src/modules/saving/templates/4bitEncoder.ts | 39 +++++++++++++++++ src/modules/saving/templates/and.ts | 7 +++- src/modules/saving/templates/button.ts | 6 ++- src/modules/saving/templates/fullAdder.ts | 12 +++--- src/modules/saving/templates/halfAdder.ts | 12 +++--- src/modules/saving/templates/light.ts | 6 ++- src/modules/saving/templates/nand.ts | 7 +++- src/modules/saving/templates/nor.ts | 8 +++- src/modules/saving/templates/not.ts | 8 +++- src/modules/saving/templates/or.ts | 7 +++- .../saving/templates/parallelDelayer.ts | 4 +- src/modules/saving/templates/rgb.ts | 4 +- .../saving/templates/sequentialDelayer.ts | 4 +- src/modules/saving/templates/xnor.ts | 10 ++--- src/modules/saving/templates/xor.ts | 9 ++-- src/modules/simulation/classes/Gate.ts | 42 ++++++++++++++++++- src/modules/simulation/classes/Pin.ts | 4 +- src/modules/simulation/constants.ts | 4 +- src/modules/simulation/helpers/addGate.ts | 2 + .../simulation/helpers/getGateTimePipes.ts | 2 +- src/modules/simulation/types/GateTemplate.ts | 1 + src/modules/simulationRenderer/constants.ts | 4 +- .../helpers/calculateGateHeight.ts | 20 +++++++++ .../simulationRenderer/helpers/pinFill.ts | 24 ++++++++--- .../simulationRenderer/helpers/renderGate.ts | 10 ++--- 36 files changed, 353 insertions(+), 60 deletions(-) create mode 100644 src/assets/4decoder.svg create mode 100644 src/assets/4encoder.svg create mode 100644 src/modules/colors/helpers/fromHex.ts create mode 100644 src/modules/saving/data/4BitScale.ts create mode 100644 src/modules/saving/data/categories.ts create mode 100644 src/modules/saving/helpers/adderActivation.ts create mode 100644 src/modules/saving/templates/4bitDecoder.ts create mode 100644 src/modules/saving/templates/4bitEncoder.ts create mode 100644 src/modules/simulationRenderer/helpers/calculateGateHeight.ts diff --git a/src/assets/4decoder.svg b/src/assets/4decoder.svg new file mode 100644 index 0000000..e6ed5b4 --- /dev/null +++ b/src/assets/4decoder.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/4encoder.svg b/src/assets/4encoder.svg new file mode 100644 index 0000000..10b65f4 --- /dev/null +++ b/src/assets/4encoder.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/modules/activation/types/Context.ts b/src/modules/activation/types/Context.ts index 850651d..11df2c8 100644 --- a/src/modules/activation/types/Context.ts +++ b/src/modules/activation/types/Context.ts @@ -1,18 +1,22 @@ import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation' -import { SimulationError } from '../../errors/classes/SimulationError' -import { fromSimulationState } from '../../saving/helpers/fromState' +import { PinState } from '../../simulation/classes/Pin' export interface Context { - memory: Record getProperty: (name: string) => unknown setProperty: (name: string, value: unknown) => void - get: (index: number) => boolean - set: (index: number, state: boolean) => void + get: (index: number) => PinState + set: (index: number, state: PinState) => void + getBinary: (index: number) => number + setBinary: (index: number, value: number, bits: number) => void + invertBinary: (value: number) => number color: (color: string) => void innerText: (value: string) => void update: () => void + toLength: (value: number | PinState, length: number) => string + maxLength: number enviroment: SimulationEnv colors: Record + memory: Record } export interface InitialisationContext { diff --git a/src/modules/colors/helpers/fromHex.ts b/src/modules/colors/helpers/fromHex.ts new file mode 100644 index 0000000..9a255df --- /dev/null +++ b/src/modules/colors/helpers/fromHex.ts @@ -0,0 +1,30 @@ +/** + * Gets the 3 chunks frmo a hex color string + * + * @param color The color string + */ +export const fromHexColorString = (color: string) => { + const actual = color.slice(1) + + const chunks = [ + actual.substr(0, 2), + actual.substr(2, 2), + actual.substr(4, 2) + ] + + const numbers = chunks.map(chunk => parseInt(chunk, 16)) + + return numbers +} + +/** + * Rebuilds a color from its chunks + */ +export const fromChunks = (chunks: number[]) => { + return `#${chunks.reduce((acc, curr) => { + const stringified = curr.toString(16) + return ( + acc + (stringified.length === 1 ? `0${stringified}` : stringified) + ) + }, '')}` +} diff --git a/src/modules/logic-gates/components/LogicGatesPage.tsx b/src/modules/logic-gates/components/LogicGatesPage.tsx index 8e63db2..4c747d9 100644 --- a/src/modules/logic-gates/components/LogicGatesPage.tsx +++ b/src/modules/logic-gates/components/LogicGatesPage.tsx @@ -19,6 +19,7 @@ const LogicGatePage = () => {
{gates .map(getTemplateSafely) + .sort((a, b) => a.category - b.category) .filter(template => { return ( renderer.simulation.mode === 'project' || diff --git a/src/modules/saving/constants.ts b/src/modules/saving/constants.ts index 3758345..1c006a0 100644 --- a/src/modules/saving/constants.ts +++ b/src/modules/saving/constants.ts @@ -14,6 +14,8 @@ import xnorTemplate from './templates/xnor' import xorTemplate from './templates/xor' import halfAdderTemplate from './templates/halfAdder' import fullAdderTemplate from './templates/fullAdder' +import _4bitEncoderTemplate from './templates/4bitEncoder' +import _4bitDecoderTemplate from './templates/4bitDecoder' export const defaultSimulationName = 'default' export const baseTemplates: DeepPartial[] = [ @@ -30,7 +32,9 @@ export const baseTemplates: DeepPartial[] = [ xnorTemplate, xorTemplate, halfAdderTemplate, - fullAdderTemplate + fullAdderTemplate, + _4bitEncoderTemplate, + _4bitDecoderTemplate // commentTemplate ] diff --git a/src/modules/saving/data/4BitScale.ts b/src/modules/saving/data/4BitScale.ts new file mode 100644 index 0000000..bded514 --- /dev/null +++ b/src/modules/saving/data/4BitScale.ts @@ -0,0 +1,4 @@ +/** + * The actual scale for the 4-bit encoder / decoder + */ +export const _4BitScale = [150, 150] diff --git a/src/modules/saving/data/categories.ts b/src/modules/saving/data/categories.ts new file mode 100644 index 0000000..4d39014 --- /dev/null +++ b/src/modules/saving/data/categories.ts @@ -0,0 +1,8 @@ +export const categories = { + basic: 0, + io: 3, + math: 1, + time: 2, + advancedIo: 4, + compressing: 5 +} diff --git a/src/modules/saving/helpers/adderActivation.ts b/src/modules/saving/helpers/adderActivation.ts new file mode 100644 index 0000000..171fd62 --- /dev/null +++ b/src/modules/saving/helpers/adderActivation.ts @@ -0,0 +1,10 @@ +export const adderActivation = (full: boolean) => ` + const a = context.getBinary(0) + const b = context.getBinary(1) + ${full ? `const c = context.getBinary(2)` : ''} + + const sum = a + b + ${full ? `c` : '0'} + + context.setBinary(0, sum) + context.setBinary(1, sum >> context.maxLength) +` diff --git a/src/modules/saving/helpers/fromState.ts b/src/modules/saving/helpers/fromState.ts index 77d5532..454c0c9 100644 --- a/src/modules/saving/helpers/fromState.ts +++ b/src/modules/saving/helpers/fromState.ts @@ -9,6 +9,10 @@ import { Camera } from '../../simulationRenderer/classes/Camera' import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation' import { Wire } from '../../simulation/classes/Wire' import { templateStore } from '../stores/templateStore' +import { calculateGateHeight } from '../../simulationRenderer/helpers/calculateGateHeight' +import { getRendererSafely } from '../../logic-gates/helpers/getRendererSafely' +import { rendererSubject } from '../../core/subjects/rendererSubject' +import { filter, take } from 'rxjs/operators' /** * Contains methods for transforming saved state into the respective class instances @@ -38,9 +42,33 @@ export const fromSimulationState = ( gateState.id, gateState.props ) + gate.transform = fromTransformState(gateState.transform) - simulation.push(gate) + const fixWrongHeight = () => { + gate.transform.height = calculateGateHeight( + getRendererSafely(), + gate + ) + } + + try { + fixWrongHeight() + } catch { + // retry if an error occured + rendererSubject + .pipe( + filter(x => !!x), + take(1) + ) + .subscribe(() => { + if (gate) { + fixWrongHeight() + } + }) + } finally { + simulation.push(gate) + } } for (const wireState of state.wires) { diff --git a/src/modules/saving/templates/4bitDecoder.ts b/src/modules/saving/templates/4bitDecoder.ts new file mode 100644 index 0000000..a49b61b --- /dev/null +++ b/src/modules/saving/templates/4bitDecoder.ts @@ -0,0 +1,40 @@ +import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' +import { _4BitScale } from '../data/4BitScale' + +/** + * The template of the _4bitDecoder gate + */ +const _4bitDecoderTemplate: PartialTemplate = { + metadata: { + name: `4 bit decoder` + }, + category: categories.compressing, + code: { + activation: ` + const input = context.get(0) + + const set = (index) => { + context.set(3 - index, input[index] || '0') + } + + for (const index of [0,1,2,3]){ + set(index) + } + ` + }, + material: { + type: 'image', + fill: require('../../../assets/4decoder') + }, + shape: { + scale: _4BitScale + }, + pins: { + outputs: { + count: 4 + } + } +} + +export default _4bitDecoderTemplate diff --git a/src/modules/saving/templates/4bitEncoder.ts b/src/modules/saving/templates/4bitEncoder.ts new file mode 100644 index 0000000..27efac4 --- /dev/null +++ b/src/modules/saving/templates/4bitEncoder.ts @@ -0,0 +1,39 @@ +import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' +import { _4BitScale } from '../data/4BitScale' + +/** + * The template of the _4bitEncoder gate + */ +const _4bitEncoderTemplate: PartialTemplate = { + metadata: { + name: `4 bit encoder` + }, + category: categories.compressing, + code: { + activation: ` + const get = (num) => { + const value = context.get(num) + return value[value.length - 1] + } + + const total = get(3) + get(2) + get(1) + get(0) + + context.set(0, total) + ` + }, + material: { + type: 'image', + fill: require('../../../assets/4encoder') + }, + shape: { + scale: _4BitScale + }, + pins: { + inputs: { + count: 4 + } + } +} + +export default _4bitEncoderTemplate diff --git a/src/modules/saving/templates/and.ts b/src/modules/saving/templates/and.ts index ba8636d..bae1ebd 100644 --- a/src/modules/saving/templates/and.ts +++ b/src/modules/saving/templates/and.ts @@ -12,7 +12,12 @@ const andTemplate: PartialTemplate = { fill: require('../../../assets/and') }, code: { - activation: `context.set(0, context.get(0) && context.get(1))` + activation: ` + const a = context.getBinary(0) + const b = context.getBinary(1) + const c = a & b + + context.setBinary(0, c)` }, pins: { inputs: { diff --git a/src/modules/saving/templates/button.ts b/src/modules/saving/templates/button.ts index a8e1e8d..8b6292c 100644 --- a/src/modules/saving/templates/button.ts +++ b/src/modules/saving/templates/button.ts @@ -1,4 +1,5 @@ import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' /** * The template of the button gate @@ -27,7 +28,7 @@ const buttonTemplate: PartialTemplate = { activation: ` const state = context.getProperty('active') - context.set(0, state) + context.set(0, Number(state).toString(2)) context.color(!state ? context.colors.main : context.colors.pressed) ` }, @@ -50,7 +51,8 @@ const buttonTemplate: PartialTemplate = { needsUpdate: true } ] - } + }, + category: categories.io } export default buttonTemplate diff --git a/src/modules/saving/templates/fullAdder.ts b/src/modules/saving/templates/fullAdder.ts index 2c1099e..d642d17 100644 --- a/src/modules/saving/templates/fullAdder.ts +++ b/src/modules/saving/templates/fullAdder.ts @@ -1,4 +1,6 @@ import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' +import { adderActivation } from '../helpers/adderActivation' /** * The template of the fullAdder gate @@ -12,12 +14,7 @@ const fullAdderTemplate: PartialTemplate = { fill: require('../../../assets/full-adder') }, code: { - activation: ` - const result = context.get(0) + context.get(1) + context.get(2) - - context.set(0, result & 1) - context.set(1, result >> 1) - ` + activation: adderActivation(true) }, pins: { inputs: { @@ -26,7 +23,8 @@ const fullAdderTemplate: PartialTemplate = { outputs: { count: 2 } - } + }, + category: categories.math } export default fullAdderTemplate diff --git a/src/modules/saving/templates/halfAdder.ts b/src/modules/saving/templates/halfAdder.ts index 6a3ccd8..f8dbd9d 100644 --- a/src/modules/saving/templates/halfAdder.ts +++ b/src/modules/saving/templates/halfAdder.ts @@ -1,4 +1,6 @@ import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' +import { adderActivation } from '../helpers/adderActivation' /** * The template of the halfAdder gate @@ -12,12 +14,7 @@ const halfAdderTemplate: PartialTemplate = { fill: require('../../../assets/half-adder') }, code: { - activation: ` - const result = context.get(0) + context.get(1) - - context.set(0, result & 1) - context.set(1, result >> 1) - ` + activation: adderActivation(false) }, pins: { inputs: { @@ -26,7 +23,8 @@ const halfAdderTemplate: PartialTemplate = { outputs: { count: 2 } - } + }, + category: categories.math } export default halfAdderTemplate diff --git a/src/modules/saving/templates/light.ts b/src/modules/saving/templates/light.ts index c01a357..96a1fd1 100644 --- a/src/modules/saving/templates/light.ts +++ b/src/modules/saving/templates/light.ts @@ -1,4 +1,5 @@ import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' /** * The template of the light gate @@ -23,7 +24,7 @@ const lightTemplate: PartialTemplate = { activation: ` const { main, active } = context.colors - context.color(context.get(0) ? active : main) + context.color(parseInt(context.get(0),2) ? active : main) ` }, integration: { @@ -34,7 +35,8 @@ const lightTemplate: PartialTemplate = { outputs: { count: 0 } - } + }, + category: categories.io } export default lightTemplate diff --git a/src/modules/saving/templates/nand.ts b/src/modules/saving/templates/nand.ts index 08cdf36..1704afe 100644 --- a/src/modules/saving/templates/nand.ts +++ b/src/modules/saving/templates/nand.ts @@ -12,7 +12,12 @@ const nandTemplate: PartialTemplate = { fill: require('../../../assets/nand') }, code: { - activation: `context.set(0, !context.get(0) || !context.get(1))` + activation: ` + const a = context.getBinary(0) + const b = context.getBinary(1) + const c = context.invertBinary(a & b) + + context.setBinary(0, c)` }, pins: { inputs: { diff --git a/src/modules/saving/templates/nor.ts b/src/modules/saving/templates/nor.ts index 3a57108..58eb554 100644 --- a/src/modules/saving/templates/nor.ts +++ b/src/modules/saving/templates/nor.ts @@ -12,7 +12,13 @@ const norTemplate: PartialTemplate = { fill: require('../../../assets/nor') }, code: { - activation: `context.set(0, !(context.get(0) || context.get(1)))` + activation: ` + const a = context.getBinary(0) + const b = context.getBinary(1) + const c = context.invertBinary(a | b) + + context.setBinary(0, c) + ` }, pins: { inputs: { diff --git a/src/modules/saving/templates/not.ts b/src/modules/saving/templates/not.ts index 485ddce..e5fe80e 100644 --- a/src/modules/saving/templates/not.ts +++ b/src/modules/saving/templates/not.ts @@ -12,7 +12,13 @@ const notTemplate: PartialTemplate = { fill: require('../../../assets/not') }, code: { - activation: `context.set(0, !context.get(0))` + activation: ` + context.setBinary(0, + context.invertBinary( + context.getBinary(0) + ) + ) + ` }, info: ['https://en.wikipedia.org/wiki/Inverter_(logic_gate)'] } diff --git a/src/modules/saving/templates/or.ts b/src/modules/saving/templates/or.ts index dc9c80a..c03be6b 100644 --- a/src/modules/saving/templates/or.ts +++ b/src/modules/saving/templates/or.ts @@ -12,7 +12,12 @@ const orTemplate: PartialTemplate = { fill: require('../../../assets/or') }, code: { - activation: `context.set(0, context.get(0) || context.get(1))` + activation: ` + const a = context.getBinary(0) + const b = context.getBinary(1) + + context.setBinary(0, a | b) + ` }, pins: { inputs: { diff --git a/src/modules/saving/templates/parallelDelayer.ts b/src/modules/saving/templates/parallelDelayer.ts index 6e50c83..cf4c87c 100644 --- a/src/modules/saving/templates/parallelDelayer.ts +++ b/src/modules/saving/templates/parallelDelayer.ts @@ -1,5 +1,6 @@ import { PartialTemplate } from '../types/PartialTemplate' import { delayProperties } from '../data/delayProperties' +import { categories } from '../data/categories' /** * The template of the parallelDelayer gate @@ -24,7 +25,8 @@ const parallelDelayerTemplate: PartialTemplate = { }) ` }, - properties: delayProperties + properties: delayProperties, + category: categories.time } export default parallelDelayerTemplate diff --git a/src/modules/saving/templates/rgb.ts b/src/modules/saving/templates/rgb.ts index 8fe0c05..2b06e3d 100644 --- a/src/modules/saving/templates/rgb.ts +++ b/src/modules/saving/templates/rgb.ts @@ -1,4 +1,5 @@ import { PartialTemplate } from '../types/PartialTemplate' +import { categories } from '../data/categories' /** * The template of the rgbLight gate @@ -43,7 +44,8 @@ const rgbLightTemplate: PartialTemplate = { inputs: { count: 3 } - } + }, + category: categories.advancedIo } export default rgbLightTemplate diff --git a/src/modules/saving/templates/sequentialDelayer.ts b/src/modules/saving/templates/sequentialDelayer.ts index d6519e1..7626cd2 100644 --- a/src/modules/saving/templates/sequentialDelayer.ts +++ b/src/modules/saving/templates/sequentialDelayer.ts @@ -1,5 +1,6 @@ import { PartialTemplate } from '../types/PartialTemplate' import { delayProperties } from '../data/delayProperties' +import { categories } from '../data/categories' /** * The template of the sequentialDelayer gate @@ -25,7 +26,8 @@ const sequentialDelayerTemplate: PartialTemplate = { `, async: true }, - properties: delayProperties + properties: delayProperties, + category: categories.time } export default sequentialDelayerTemplate diff --git a/src/modules/saving/templates/xnor.ts b/src/modules/saving/templates/xnor.ts index 978bc5a..5978def 100644 --- a/src/modules/saving/templates/xnor.ts +++ b/src/modules/saving/templates/xnor.ts @@ -13,11 +13,11 @@ const xnorTemplate: PartialTemplate = { }, code: { activation: ` - const a = context.get(0) - const b = context.get(1) - const c = (a && b) || !(a || b) - - context.set(0, c)` + const a = context.getBinary(0) + const b = context.getBinary(1) + const c = context.invertBinary(a ^ b) + + context.setBinary(0, c)` }, info: ['https://en.wikipedia.org/wiki/XNOR_gate'], pins: { diff --git a/src/modules/saving/templates/xor.ts b/src/modules/saving/templates/xor.ts index 5d96ecb..b2a4060 100644 --- a/src/modules/saving/templates/xor.ts +++ b/src/modules/saving/templates/xor.ts @@ -13,11 +13,10 @@ const xorTemplate: PartialTemplate = { }, code: { activation: ` - const a = context.get(0) - const b = context.get(1) - const c = (a || b) && (!a || !b) - - context.set(0, c)` + const a = context.getBinary(0) + const b = context.getBinary(1) + + context.setBinary(0, a ^ b)` }, info: ['https://en.wikipedia.org/wiki/XOR_gate'], pins: { diff --git a/src/modules/simulation/classes/Gate.ts b/src/modules/simulation/classes/Gate.ts index 3c9455c..4fc4067 100644 --- a/src/modules/simulation/classes/Gate.ts +++ b/src/modules/simulation/classes/Gate.ts @@ -360,13 +360,49 @@ export class Gate { * Generates the activation context */ public getContext(): Context { + const maxLength = Math.max( + ...this._pins.inputs.map(pin => pin.state.value.length) + ) + + const toLength = ( + original: string | number, + length: number = maxLength + ) => { + const value = original.toString(2) + + if (value.length === length) { + return value + } else if (value.length > length) { + const difference = value.length - length + + return value.substr(difference) + } else { + return `${'0'.repeat(length - value.length)}${value}` + } + } + return { get: (index: number) => { return this._pins.inputs[index].state.value }, - set: (index: number, state: boolean = false) => { + set: (index: number, state) => { return this._pins.outputs[index].state.next(state) }, + getBinary: (index: number) => { + return parseInt(this._pins.inputs[index].state.value, 2) + }, + setBinary: ( + index: number, + value: number, + bits: number = maxLength + ) => { + return this._pins.outputs[index].state.next( + toLength(value.toString(2), bits) + ) + }, + invertBinary: (value: number) => { + return value ^ ((1 << maxLength) - 1) + }, color: (color: string) => { if (this.template.material.type === 'color') { this.template.material.fill = color @@ -384,6 +420,8 @@ export class Gate { update: () => { this.update() }, + toLength, + maxLength, enviroment: this.env, memory: this.memory, colors: { @@ -430,6 +468,6 @@ export class Gate { private static generatePins(options: PinCount, type: number, gate: Gate) { return [...Array(options.count)] .fill(true) - .map(() => new Pin(type, gate)) + .map((v, index) => new Pin(type, gate)) } } diff --git a/src/modules/simulation/classes/Pin.ts b/src/modules/simulation/classes/Pin.ts index 2dd934b..9a0eb92 100644 --- a/src/modules/simulation/classes/Pin.ts +++ b/src/modules/simulation/classes/Pin.ts @@ -2,6 +2,8 @@ import { SubscriptionData } from '../types/SubscriptionData' import { BehaviorSubject } from 'rxjs' import { Gate } from './Gate' +export type PinState = string + /* Types: First bit = input @@ -9,7 +11,7 @@ Second bit = output */ export class Pin { - public state = new BehaviorSubject(false) + public state = new BehaviorSubject('0') public pairs = new Set() private subscriptions: SubscriptionData[] = [] diff --git a/src/modules/simulation/constants.ts b/src/modules/simulation/constants.ts index fd73458..83ce040 100644 --- a/src/modules/simulation/constants.ts +++ b/src/modules/simulation/constants.ts @@ -1,4 +1,5 @@ import { GateTemplate } from './types/GateTemplate' +import { categories } from '../saving/data/categories' export const DefaultGateTemplate: GateTemplate = { metadata: { @@ -57,5 +58,6 @@ export const DefaultGateTemplate: GateTemplate = { innerText: { enabled: false, color: 'white' - } + }, + category: categories.basic } diff --git a/src/modules/simulation/helpers/addGate.ts b/src/modules/simulation/helpers/addGate.ts index 610fbff..2e0fb81 100644 --- a/src/modules/simulation/helpers/addGate.ts +++ b/src/modules/simulation/helpers/addGate.ts @@ -10,6 +10,7 @@ import { toast } from 'react-toastify' import { createToastArguments } from '../../toasts/helpers/createToastArguments' import { CurrentLanguage } from '../../internalisation/stores/currentLanguage' import { GateInitter } from '../../simulationRenderer/types/GateInitter' +import { calculateGateHeight } from '../../simulationRenderer/helpers/calculateGateHeight' /** * Adds a gate to a renderer @@ -43,6 +44,7 @@ export const addGate = ( const offset = multiply([scalarOffset, scalarOffset], renderer.spawnCount) gate.transform.position = add(origin, offset) + gate.transform.height = calculateGateHeight(renderer, gate) renderer.simulation.push(gate) renderer.spawnCount++ diff --git a/src/modules/simulation/helpers/getGateTimePipes.ts b/src/modules/simulation/helpers/getGateTimePipes.ts index 6c8e7a1..13a4c34 100644 --- a/src/modules/simulation/helpers/getGateTimePipes.ts +++ b/src/modules/simulation/helpers/getGateTimePipes.ts @@ -2,7 +2,7 @@ import { GateTemplate } from '../types/GateTemplate' import { debounceTime, throttleTime } from 'rxjs/operators' import { MonoTypeOperatorFunction, pipe } from 'rxjs' -export type TimePipe = MonoTypeOperatorFunction +export type TimePipe = MonoTypeOperatorFunction export const getGateTimePipes = (template: GateTemplate) => { const pipes: TimePipe[] = [] diff --git a/src/modules/simulation/types/GateTemplate.ts b/src/modules/simulation/types/GateTemplate.ts index dfe8fa6..07e8ff3 100644 --- a/src/modules/simulation/types/GateTemplate.ts +++ b/src/modules/simulation/types/GateTemplate.ts @@ -79,4 +79,5 @@ export interface GateTemplate { color: string enabled: boolean } + category: number // for better sorting } diff --git a/src/modules/simulationRenderer/constants.ts b/src/modules/simulationRenderer/constants.ts index d283aed..de60df3 100644 --- a/src/modules/simulationRenderer/constants.ts +++ b/src/modules/simulationRenderer/constants.ts @@ -13,8 +13,8 @@ export const defaultSimulationRendererOptions: SimulationRendererOptions = { pinStrokeColor: '#888888', pinStrokeWidth: 3, pinFill: { - open: 'rgb(255,216,20)', - closed: 'rgb(90,90,90)' + open: '#ffff22', + closed: '#555555' }, gateStroke: { active: 'yellow', diff --git a/src/modules/simulationRenderer/helpers/calculateGateHeight.ts b/src/modules/simulationRenderer/helpers/calculateGateHeight.ts new file mode 100644 index 0000000..c000992 --- /dev/null +++ b/src/modules/simulationRenderer/helpers/calculateGateHeight.ts @@ -0,0 +1,20 @@ +import { Gate } from '../../simulation/classes/Gate' +import { SimulationRenderer } from '../classes/SimulationRenderer' + +/** + * Calculates the correct height for a gate + * + * @param renderer The renderer to get the pin-radius of + * @param gate The gate to get the height of + */ +export const calculateGateHeight = ( + renderer: SimulationRenderer, + gate: Gate +) => { + return Math.max( + gate.transform.scale[1], + Math.max(gate._pins.outputs.length, gate._pins.inputs.length) * + 4 * + renderer.options.gates.pinRadius + ) +} diff --git a/src/modules/simulationRenderer/helpers/pinFill.ts b/src/modules/simulationRenderer/helpers/pinFill.ts index 52d5677..17619a8 100644 --- a/src/modules/simulationRenderer/helpers/pinFill.ts +++ b/src/modules/simulationRenderer/helpers/pinFill.ts @@ -1,15 +1,29 @@ import { Pin } from '../../simulation/classes/Pin' import { SimulationRenderer } from '../classes/SimulationRenderer' +import { fromHexColorString, fromChunks } from '../../colors/helpers/fromHex' export const pinFill = (renderer: SimulationRenderer, pin: Pin) => { let color = 'rgba(0,0,0,0)' if (pin.pairs.size) { - if (pin.state.value) { - color = renderer.options.gates.pinFill.open - } else { - color = renderer.options.gates.pinFill.closed - } + const { open, closed } = renderer.options.gates.pinFill + const digits = Array.from(pin.state.value).map(Number) + + const colors = digits.map(digit => (digit ? open : closed)) + const chunked = colors.map(fromHexColorString) + + const summed = [0, 1, 2] + .map(key => + chunked + .flat() + .filter((v, index) => index % 3 === key) + .reduce((acc, curr) => acc + curr, 0) + ) + .map(value => Math.floor(value / digits.length)) + + color = fromChunks(summed) + + // console.log(color) } return color diff --git a/src/modules/simulationRenderer/helpers/renderGate.ts b/src/modules/simulationRenderer/helpers/renderGate.ts index 5d44069..811b541 100644 --- a/src/modules/simulationRenderer/helpers/renderGate.ts +++ b/src/modules/simulationRenderer/helpers/renderGate.ts @@ -32,12 +32,12 @@ export const renderGate = ( ctx.save() - const r = useTransform(ctx, gate.transform) + const relativeTransform = useTransform(ctx, gate.transform) const renderingParameters = [ - r.x, - r.y, - r.width, - r.height, + relativeTransform.x, + relativeTransform.y, + relativeTransform.width, + relativeTransform.height, gate.template.shape.rounded ? gate.template.shape.radius : 0 ]